在過去的幾年時間裏,移動端web野蠻生長,智能機的Android陣營和IOS陣營平起平坐,隨之產生了多個系統版本(系統版本多樣);五花八門的屏幕尺寸、屏幕展現技術(如大名鼎鼎的Retina技術屏)層出不窮(屏幕尺寸、技術多樣),仍是CSS的W3C標準在各式各樣的移動端瀏覽器上落實得也是七零八落(瀏覽器兼容多樣)。css
細看下來移動端Web開發工做面臨着不少的多樣性,可想而知在這樣的不肯定性下去開發一個完善的項目會有多大的阻力,所以,移動端Web亟需一個完善成熟的適配方案來磨平這些多樣性之間的差別和不足,提供一個相對穩定、可控的開發環境。html
本文只介紹CSS樣式佈局的適配方案,至於HTML5和JavaScript的適配方案,其實如今已經有了一些成熟的解決方案,如Babel,各類polyfill等,而且搭配Webpack使用更香。node
Flexible方案主要是藉助JavaScript控制viewport
的能力,使用rem
模擬vw
的特性從而達到適配目的的一套解決方案。webpack
Flexible方案的實現涉及並使用到了不少PC端開發不多接觸到的概念,其實不管是怎麼樣的適配方案都是創建在梳理和管理這些概念之上的,所以,這些概念對咱們理解和探究移動端適配的深層原理尤其重要(具體概念講述請見《深刻淺出移動端適配》)。ios
rem
是相對於html
元素的font-size
來作計算的計算屬性值。
經過設置documentElement
的fontSize
屬性值就能夠統一整個頁面的佈局標準。css3
// set 1rem = viewWidth / 10
function setRemUnit () {
var rem = docEl.clientWidth / 10
// docEl爲document.documentElement,即html元素
docEl.style.fontSize = rem + 'px'
}
setRemUnit();
複製代碼
如上代碼所示,Flexible將整個頁面的寬度切成了10份,而後將計算出來的頁面寬度的1/10
設置爲html
節點的fontSize
,也就意味着,以後咱們在當前頁面的html
節點的子節點上應用rem
爲單位時都是按照頁面比例來計算的。web
設置viewport
的width
爲device-width
,改變瀏覽器viewport
(佈局視口和視覺視口)的默認寬度爲理想視口寬度,從而使得用戶能夠在理想視口內看到完整的佈局視口的內容。正則表達式
等比設置viewport
的initial-scale
、maximum-scale
、minimum-scale
的值,從而實現1物理像素=1css像素
,以適配高倍屏的顯示效果(就是在這個地方規避了你們熟知的「1px問題」)segmentfault
var metaEL= doc.querySelector('meta[name="viewport"]');
var dpr = window.devicePixelRatio;
var scale = 1 / dpr
metaEl.setAttribute('content', 'width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
複製代碼
Flexible使用了rem
做爲統一頁面佈局標準的佈局單位,且把頁面寬度等分爲了10份,那麼咱們在書寫css代碼時就須要去計算當前的px
單位在當前設計稿上對應的rem
值應該是多少。
以iPhone6爲例:佈局視口爲375px
,則1rem = 37.5px
,這時設計稿上給定一個元素的寬爲75px
(設備獨立像素),咱們只須要將它設置爲75 / 37.5 = 2rem
便可。數組
固然,以上的工做方式顯然是低效且不可接受的,咱們能夠藉助PostCSS的pxtorem
插件來幫咱們完成這個計算過程:
plugins: {
...,
'postcss-pxtorem': {
// 750設計標準
rootValue: 75,
// 轉換成的rem後,保留小數點後幾位
unitPrecision: 5,
/**
* 將會被轉換的css屬性列表,
* 設置爲*表示所有,['*','*position*','!letter-spacing','!font*']
* *position* 表示全部包含 position 的屬性
* !letter-spacing 表示非 letter-spacing 屬性
* !font* 表示非font-size font-weight ... 等的屬性
* */
propList: ['*', '!letter-spacing'],
// 不會被轉換的class選擇器名,支持正則
selectorBlackList: ['.rem-'],
replace: true,
// 容許在媒體查詢中轉換`px`
mediaQuery: false,
// 小於1px的將不會被轉換
minPixelValue: 1
}
}
複製代碼
以上代碼是基於Vue Cli3.x的Webpack項目,只須要配置在當前項目根目錄的postcss.config.js
中便可,除了Webpack配置以外,還可使用其餘的配置方式,詳細介紹能夠點擊這裏進行了解。
postcss-pxtorem
能夠幫咱們把咱們須要轉的px值計算轉換爲對應的rem
值,如:
.name-item {
font-size: 40px;
line-height: 56px;
margin-left: 144px;
border-top: 1PX solid #eeeeee;
color: #333333;
}
複製代碼
轉換後是這個樣子:
.name-item {
font-size: .53333rem;
line-height: .74667rem;
font-weight: 700;
margin-left: 1.92rem;
border-top: 1px solid #eee;
color: #333;
}
複製代碼
即iframe
中展現的內容依然使用的是css
像素,在高倍屏下會出問題,如咱們在使用iframe
引用一個騰訊視頻的視頻播放資源時,該視頻播放器的播放按鈕在不一樣dpr
的設備上展現差別很大:
從圖中咱們能夠看出播放按鈕在dpr = 2
的設備上展現的大小要比在dpr = 3
的設備上要大不少,若是你去仔細測量的話,會發現恰好是其1.5
倍,若是你讀過了深刻淺出移動端適配,那麼很容易就理解爲何了,咱們這裏不作深究。
若是你去研究過lib-flexible
的源碼,那你必定知道lib-flexible
對安卓手機的特殊處理,即:一概按dpr = 1
處理。
if (isIPhone) {
// iOS下,對於2和3的屏,用2倍的方案,其他的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其餘設備下,仍舊使用1倍的方案
dpr = 1;
}
複製代碼
那麼,Flexible爲何不對安卓的高倍屏作適配處理呢?我想Flexible這樣作應該是有苦衷的:長久以來,安卓手機的dpr
五花八門,從1
到4
甚至到5
,更甚者1.75
、2.6
、3.5
這樣的dpr
值也層出不窮。因此Flexible在權衡之下直接簡單粗暴的把安卓手一概按dpr = 1
處理,也算是快刀斬亂麻了。
固然,咱們也能夠手動去修改lib-flexible
的源碼去彌補上這個缺憾,但咱們也只可能針對那些dpr
爲整數的安卓設備作適配,對於那些比較奇葩的dpr
直接忽略便可。然而,天知道安卓手機的dpr
最大整數值是多少呢?天知道(三星S8的dpr
就是4
)
響應式佈局,其實質性作法就是結合css3
的媒體查詢@media
對一些不一樣尺寸閾值作特定的佈局設計,如對768px
如下屏幕的使用緊湊型佈局,對769px
到992px
的屏幕作圖文混排型佈局,對大於992px
的屏幕作富元素、多元素佈局等。
.main-content {
max-width: 70em
}
@media screen and (min-width: 0) {
.main-content {
margin:0 6.4935064935%
}
}
@media screen and (min-width: 45em) {
.main-content {
margin:0 5.1282051282%
}
}
@media screen and (min-width: 70em) {
.main-content {
margin:0 5.1282051282%
}
}
複製代碼
其中,@media
語法中涉及到的尺寸查詢語句,查詢的尺寸依據是當前設備的物理像素,和Flexible的佈局理論(即針對不一樣dpr
設備等比縮放視口的scale
值,從而同時改變佈局視口和視覺視口大小)相悖,所以響應式佈局在「等比縮放視口大小」的情境下是沒法正常工做的。
根據Flexible的實現理論,咱們都知道它是經過設置的html
元素的font-size
大小,從而確保頁面內全部元素在使用rem
爲單位進行樣式設置時都是相對於html
元素的font-size
值。
然而,在微信環境(或其餘可設置字體大小的Web瀏覽器中,如Safari)下,設置微信的字體大小(調大)後再打開使用Flexible技術適配的Web頁面,你會發現頁面佈局錯亂了,全部使用rem
設置大小的元素都變大了,此時html
的font-size
仍是原來的大小,可是元素就是變大了,這是爲何呢?
事實上,雖然Flexible幫咱們使用<meta/>
標籤設置了width=device-width
和user-scalable=no
以及對應的scale
縮放值以保證咱們的元素大小在高倍屏下(dpr >= 2
)正常展現,可是在調整Web瀏覽器的字體大小後,咱們的"視口"也響應的等比縮小了,即視覺視口(window.innerWidth
),豁然開朗,並非咱們的元素變大了,而是咱們的視覺視口變小了!
基於咱們已經掌握的視口相關知識,其根本緣由是咱們在調整Web瀏覽器的字體大小時,也響應的調整了視口的scale
值,所以才致使了視覺視口的變小。
知道了Bug產生的緣由,那咱們有辦法解決嗎?答案是在Flexible方案下毫無辦法,而在接下來要講到的Viewport方案中則能夠完美解決。Flexible承載的歷史使命已經完成了,讓咱們放下Flexible,擁抱新的變化。
Viewport方案中主要使用的是css3
中CSS Values and Units Module Level 3(候選推薦)新增的<length>
單位vw
、vh
、vmax
和vmin
。定義中,它們都是相對單位,其相對的參考系都是"視覺視口":
unit | relative to(參考單位) |
---|---|
'vw' | 1% of viewport's width(視覺視口寬度的1%) |
'vh' | 1% of viewport's height(視覺視口高度的1%) |
'vmax' | 1% of viewport's larger dimension(vw和vh中的較大值) |
'vmin' | 1% of viewport's smaller dimension(vw和vh中的較大值) |
vmin
和vmax
是根據Viewport中長度偏大的那個維度值計算出來的,若是window.innerHeight > window.innerWidth
則vmin
取值爲window.innerWidth / 100
,vmax
取值爲window.innerHeight / 100
。
可能會有同窗擔憂Viewport方案的瀏覽器兼容性問題,咱們可使用caniuse來查看下viewport單位在各主流瀏覽器版本上的兼容狀況:
從圖中能夠看出,目前大部分的主流瀏覽器基本上已經支持了viewport單位,其中有一些淡綠色的瀏覽器版本表示爲部分支持,其主要內容爲沒法兼容vmax
和vmin
的用法;而「Know issues」一欄中所列的一些已知問題大多也是針對用戶縮放viewport
大小或者IOS 7 Safari
所特有的一些buggy behavior,而對於這些咱們是能夠控制的。
事實上,咱們的適配方案,與其稱爲「viewport適配方案」不如叫「vw適配方案」,由於在咱們的適配方案中,咱們只須要使用到vw
這一個相對單位便可,而且其兼容性是最好的,其餘單位基本上使用不到。
對於那些只存在IOS 7 Safari
及老版本纔會出現的一些問題,大可沒必要多慮,畢竟如今已經9102年了,而IOS 7
是「2013年9月18日正式推出,2013年9月19日凌晨1點開放免費下載更新」的,年代久遠,加之iPhone
的不更新系統就給你來個限速變卡的騷操做,這種遠古系統再出現的機率幾乎爲0。
vw
做爲佈局單位,從底層根本上解決了不一樣尺寸屏幕的適配問題,由於每一個屏幕的百分比是固定的、可預測、可控制的。
從咱們的實際開發工做出發,咱們如今都是統一使用的iPhone6
的視覺設計稿(即寬度爲750px
),那麼100vw=750px
,即1vw = 7.5px
。那麼若是設計稿上某一元素的寬度爲value
像素,那麼其對應的vw值則能夠經過vw = value / 7.5
來計算獲得。
須要注意的是,雖然vw
無痛解決了咱們以前遇到的不少問題,可是它並非萬能的,經過查找資料、博客和測試實踐,如下場景咱們能夠放心使用vw來適配咱們的頁面:
• 容器適配,可使用vw
• 文本適配,可使用vw
• 大於1px
的邊框、圓角、陰影均可以使用vw
• 內邊距和外邊距均可以使用vw
在咱們已知的大部分主流瀏覽器中,都是自然支持vw
單位的,但不排除有某些瀏覽器的某些版本存在不兼容的狀況,若是業務須要,咱們能夠經過以下兩種方式作降級處理:
• CSS Houdini:經過CSS Houdini針對vw作處理,調用CSS Typed DOM Level1提供的CSSUnitValue API;
• CSS Polifill:經過相應的Polyfill作響應的處理,目前針對vw單位的Polyfill主要有:vminpoly、Viewport Units Buggyfill、vunits.js和Modernizr。大漠老師比較推薦的是Viewport Units Buggyfill
postcss-px-to-viewport
插件的做用和postcss-pxtorem
的做用相似,主要用來把px
單位轉換爲vw
、vh
、vmin
或者vmax
這樣的視窗單位(推薦轉換爲vw
,其餘單位多多少少都有一些兼容性問題),也是viewport適配方案的核心插件之一。
結合webpack
項目進行配置時,只須要將其配置在項目根目錄下的postcss.config.js
中便可,其基本配置項以下:
plugins: {
'postcss-px-to-viewport': {
unitToConvert: 'px', // 須要轉換的單位
viewportWidth: 750, // 視口寬度,等同於設計稿寬度
unitPrecision: 5, // 精確到小數點後幾位
/**
* 將會被轉換的css屬性列表,
* 設置爲 * 表示所有,如:['*']
* 在屬性的前面或後面設置*,如:['*position*'],*position* 表示全部包含 position 的屬性,如 background-position-y
* 設置爲 !xx 表示不匹配xx的那些屬性,如:['!letter-spacing'] 表示除了letter-spacing 屬性以外的其餘屬性
* 還能夠同時使用 ! 和 * ,如['!font*'] 表示除了font-size、 font-weight ...這些以外屬性以外的其餘屬性名頭部是‘font’的屬性
* */
propList: ['*'],
viewportUnit: 'vw', // 須要轉換成爲的單位
fontViewportUnit: 'vw',// 須要轉換稱爲的字體單位
/**
* 須要忽略的選擇器,即這些選擇器對應的屬性值不作單位轉換
* 設置爲字符串,轉換器在作轉換時會忽略那些選擇器中包含該字符串的選擇器,如:['body']會匹配到 .body-class,也就意味着.body-class對應的樣式設置不會被轉換
* 設置爲正則表達式,在作轉換前會先校驗選擇器是否匹配該正則,若是匹配,則不進行轉換,如[/^body$/]會匹配到 body 可是不會匹配到 .body
*/
selectorBlackList: [],
minPixelValue: 1, // 最小的像素單位值
mediaQuery: false, // 是否轉換媒體查詢中設置的屬性值
replace: true, // 替換包含vw的規則,而不是添加回退
/**
* 忽略一些文件,如'node_modules'
* 設置爲正則表達式,將會忽略匹配該正則的全部文件
* 若是設置爲數組,那麼該數組內的元素都必須是正則表達式
*/
exclude: [],
landscape: false, // 是否自動加入 @media (orientation: landscape),其中的屬性值是經過橫屏寬度來轉換的
landscapeUnit: 'vw', // 橫屏單位
landscapeWidth: 1334 // 橫屏寬度
}
複製代碼
目前出視覺設計稿,咱們都是使用750px
寬度的,那麼100vw = 750px
,即1vw = 7.5px
。那麼咱們能夠根據設計圖上的px
值直接轉換成對應的vw
值。在實際擼碼過程,不須要進行任何的計算,直接在代碼中寫px
便可,postcss-px-to-viewport
會自動幫咱們把px計算轉換爲對應的vw
值,好比:
.name-item {
font-size: 40px;
line-height: 56px;
margin-left: 144px;
border-top: 1PX solid #eeeeee;
color: #333333;
}
複製代碼
轉換後:
.name-item {
font-size: 5.33333vw;
line-height: 7.46667vw;
margin-left: 19.2vw;
border-top: 1px solid #eee;
color: #333;
}
複製代碼
固然,postcss-px-to-viewport
的功能不止於此,它還能夠在selectorBlackList
選項中設置一些關鍵詞或正則,來避免對這些指定的選擇器作轉換,如selectorBlackList:['.ignore', '.hairlines']
:
<div class="box ignore"></div>
寫CSS的時候:
.ignore {
margin: 10px;
background-color: red;
}
.box {
width: 180px;
height: 300px;
}
.hairlines {
border-bottom: 0.5px solid red;
}
複製代碼
轉化以後:
.box {
width: 24vw;
height: 40vw;
}
.ignore {
margin: 10px; /*.box元素中帶有.ignore類名,在這個類名寫的`px`不會被轉換*/
background-color: red;
}
.hairlines {
border-bottom: 0.5px solid red;
}
複製代碼
這個js庫是爲了兼容那些不兼容vw
、vh
、vmax
、vmin
這些viewport單位的瀏覽器所使用的,在該方案開始咱們已經明確過,現現在大部分機型的大部分瀏覽器都已經兼容了viewport
單位,大漠老師在17年左右對Top30的熱門機型進行了測試,其中只有以下幾款機型沒有徹底支持viewport單位:
可是若是你的業務不容許,須要你的項目跑在不少更古老的機型或者瀏覽器版本上,那麼就不得不考慮到一些hack手段,那麼這個js庫就是你的首選方案了。
viewport-units-buggyfill
主要有兩個JavaScript文件:viewport-units-buggyfill.js
和viewport-units-buggyfill.hacks.js
。你只須要在你的HTML文件中引入這兩個文件。好比在Vue項目中的index.html
引入它們:
<script src="//g.alicdn.com/fdilab/lib3rd/viewport-units-buggyfill/0.6.2/??viewport-units-buggyfill.hacks.min.js,viewport-units-buggyfill.min.js"></script>
複製代碼
在html文件中引入polyfill
的位置以後,須要手動調用下 viewport-units-buggyfill
:
<script>
window.onload = function () {
window.viewportUnitsBuggyfill.init({
hacks: window.viewportUnitsBuggyfillHacks
});
}
</script>
複製代碼
具體的使用。在你的CSS
中,只要使用到了viewport的單位地方,須要在樣式中添加content
:
.my-viewport-units-using-thingie {
width: 50vmin;
height: 50vmax;
top: calc(50vh - 100px);
left: calc(50vw - 100px);
/* hack to engage viewport-units-buggyfill */
content: 'viewport-units-buggyfill; width: 50vmin; height: 50vmax; top: calc(50vh - 100px); left: calc(50vw - 100px);';
}
複製代碼
這可能會令你感到噁心,並且咱們不可能每次寫vw
都去人肉的計算。特別是在咱們的這個場景中,咱們使用了postcss-px-to-viewport這個插件來轉換vw
,更沒法讓咱們人肉的去添加content
內容。
這個時候就須要前面提到的postcss-viewport-units插件。這個插件將讓你無需關注content
的內容,插件會自動幫你處理。好比插件處理後的代碼:
.test {
padding: 3.2vw;
margin: 3.2vw auto;
background-color: #eee;
text-align: center;
font-size: 3.73333vw;
color: #333;
content: "viewport-units-buggyfill; padding: 3.2vw; margin: 3.2vw auto; font-size: 3.73333vw";
}
複製代碼
配置這個插件也很簡單,只須要和配置postcss-px-to-viewport
同樣,配置在項目根目錄的postcss.config.js
中便可:
plugins: {
'postcss-viewport-units': {}
}
複製代碼
在咱們使用了Viewport Units Buggyfill後,正如你看到的,它會在佔用content
屬性,所以會或多或少的形成一些反作用。如img
元素和僞元素的使用::before
或::after
。
對於img,在部分瀏覽器中,content
的寫入會形成圖片沒法正常展現,這時候須要全局添加樣式覆蓋:
img {
content: normal !important;
}
複製代碼
對於::before
等僞元素,就算是在裏面使用了vw單位,Viewport Units Buggyfill對其並不會起做用,如:
// 編譯前
.after {
content: 'after content';
display: block;
width: 100px;
height: 20px;
background: green;
}
// 編譯後
.after[data-v-469af010] {
content: "after content";
display: block;
width: 13.333vw;
height: 2.667vw;
background: green;
}
複製代碼
採用vw
來作適配在處理一些細節之處還是存在必定的缺陷的。好比當容器使用
vw,
margin採用
px時,很容易形成總體寬度超過
100vw,從而影響佈局效果。固然咱們也是能夠避免的,例如使用
padding代替
margin,結合
calc()`函數使用等等...
另一點,px
轉換成vw
不必定能徹底整除,所以有必定的像素差。
通讀整套適配方案,你會發現viewport適配方案單單是使用了vw
去適配不一樣尺寸屏幕的大小問題,而並無解決高倍屏展現的問題,如老生常談的1px
問題、圖片展現模糊等問題。
其實網上關於1px
這些關於解決高倍屏展現問題的方案有不少,如大漠老師的再談Retina下1px
的解決方案,周陸軍的Retina真實還原1px
邊框的解決方案,方法總比問題多。
結合上面一些方案,我這裏也整理了幾套被各位大佬所推薦的解決方案並測試了下效果:
• 結合postcss-write-svg和border-image
或background-image
解決1px
問題
border-image
方案雖然很好用,可是在一些低端機型和ios
設備上有兼容問題。主要表現爲在一些低端安卓機型,如魅藍note1中展現4個邊框時,下側和右側邊框缺失;在iPhone5s
、iPhone6s
、iPhone6s Plus
上直接不顯示(不知道是否是我姿式不對)。
border-image
還有一個問題就是沒法作圓角。
background-image
方案,在以上機型上都能比較好的展示,可是在背景圖方案中須要提供2像素的圖片,如:
fineLine(color = #e8e8e8, position = bottom)
if position == top || position == bottom
background-repeat: repeat-x
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAAXNSR…hZcwAADsMAAA7DAcdvqGQAAAAQSURBVBhXY5g5c+Z/BhAAABRcAsvqBShzAAAAAElFTkSuQmCC)
if position == top
background-position: 0 0
else
background-position: 0 100%
else
background-repeat: repeat-y
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAAXNSR…hZcwAADsMAAA7DAcdvqGQAAAAQSURBVBhXY5g5c+Z/BhAAABRcAsvqBShzAAAAAElFTkSuQmCC)
if position == left
background-position: 0 0
else
background-position: 100% 0
複製代碼
固然,咱們也能夠藉助postcss-write-svg
的能力,本身編寫一個能夠繪出上圖中兩種類型的base64
圖片出來:
// 畫出來的圖片如圖一(上下)
@svg squareLR {
width: 1px;
height: 2px;
@rect {
fill: var(--color, black);
width: 100%;
height: 50%;
}
}
// 畫出來的圖片如圖二(左右)
@svg squareTB {
width: 2px;
height: 1px;
@rect {
fill: var(--color, black);
width: 50%;
height: 100%;
}
}
// 順便還能夠優化下咱們的mixin寫法
fineLine(color = #e8e8e8, position = bottom)
if position == top || position == bottom
background-repeat: repeat-x
background-image: svg(squareLR param(--color color))
if position == top
background-position: 0 0
else
background-position: 0 100%
else
background-repeat: repeat-y
background-image: svg(squareTB param(--color color))
if position == left
background-position: 0 0
else
background-position: 100% 0
複製代碼
除此以外,咱們還有漸變背景圖片方案。在漸變背景圖片方案中,咱們只須要維護一份mixin
代碼就能夠實現咱們想要的效果:
bgLine($color = #efefef, $direction = all)
background-repeat: no-repeat
if $direction == all
border: none
padding: 1px
background-image:
-webkit-linear-gradient(top, transparent 50%, $color 50%),
-webkit-linear-gradient(right, transparent 50%, $color 50%),
-webkit-linear-gradient(bottom, transparent 50%, $color 50%),
-webkit-linear-gradient(left, transparent 50%, $color 50%)
background-image:
linear-gradient(to top, transparent 50%, $color 50%),
linear-gradient(to right, transparent 50%, $color 50%),
linear-gradient(to bottom, transparent 50%, $color 50%),
linear-gradient(to left,transparent 50%, $color 50%)
background-size:
100% 1px,
1px 100%,
100% 1px,
1px 100%
background-position:
top center,
right center,
bottom center,
left center
else
background-position: $direction center
background-image: -webkit-linear-gradient($direction, transparent 50%, $color 50%);
background-image: linear-gradient(to $direction, transparent 50%, $color 50%);
if $direction == left || $direction == right
background-size: 1px 100%
if $direction == top || $direction == bottom
background-size: 100% 1px
.test
width 400px
padding 24px
margin 24px
bgLine(red, all)
複製代碼
可是漸變色背景圖方案依然有她的不足,如沒法設置邊框圓角、須要維護比較繁瑣的漸變色控制代碼(雖然一萬年可能就動一次)等問題,不過依然是值得一試的適配方案。
• 0.5px
方案
0.5px
方案在IOS8
以後有很好的支持,我所能蒐羅到的iPhone
設備都很清晰的顯示了咱們想要到的細線(可是對於iPhone 6s Plus
、iPhone X
、iPhone Xs
等3倍屏的IOS設備其實並非真實的1
物理像素,而是1.5
物理像素,不過影響不大)。
可是在安卓設備上缺喜憂參半,通過個人測試,在Android5.1
以後的版本,各設備基本上已經兼容了0.5px
的正常顯示,可是不排除有一些低於Android5.1
版本的設備不能正常展現,那麼就覺得這要用js代碼去作必定的hack,並要涉及到Flexible適配方案去作兼容,這簡直就是技術的倒退,不能忍的。
因此,在各類場景的綜合權衡下,並不推薦在viewport適配方案的項目中使用該策略去作1px問題的兼容。
• 僞元素 + transform scale方案
僞元素 + transform scale的方法相比以上幾種方案是比較簡潔、可控好理解的方式,而且這種方式也支持設置圓角。在騰訊、京東的大部分移動端產品中大都採用的這種適配方案(阿里的移動端產品,如手機版淘寶、手機版天貓等並未對1px作適配處理,amazing!it's understandable~ 比較任性吧)。
其方案的思路也很好理解,你們一看便知:
border-1px($color = #ccc, $radius = 2PX, $direction = all)
position: relative
&::after
content: ""
pointer-events: none
display: block
position: absolute
border-radius: $radius
box-sizing border-box
width 100%
height 100%
left: 0
top: 0
transform-origin: 0 0
if $direction == all
border: 1PX solid $color
else
border-{$direction}: 1PX solid $color
@media only screen and (-webkit-min-device-pixel-ratio:2)
width: 200%
height: 200%
border-radius: $radius * 2
transform: scale(.5)
@media only screen and (-webkit-min-device-pixel-ratio:3)
width: 300%
height: 300%
border-radius: $radius * 3
transform: scale(.333)
複製代碼
在高倍屏下產生圖片模糊的問題以及其對應的解決方案,在深刻淺出移動端適配已經向你們解釋和介紹過了,此處略過。
完結,撒花。
如今牆內所能查到的移動端適配方案比較零散,並且有一些信息也是不合時宜的、甚至已通過時失真。深刻淺出移動端適配和本篇文章的目的就是對那些網上能蒐羅到的移動端適配方案作一個總結和實踐驗證,也算是一個學習的過程。這兩篇文章中的一些觀點和想法或者代碼實現可能多多少少會有一些不足之處,歡迎你們批評指正。
• www.w3cplus.com/mobile/vw-l…• www.w3cplus.com/css/fix-1px…• www.w3cplus.com/css/vw-for-…• www.w3cplus.com/mobile/lib-…• blog.51cto.com/zhoulujun/2…• juejin.im/post/5cddf2…• www.cnblogs.com/sunLemon/p/…• segmentfault.com/q/101000001…• blog.noob6.com/2018/06/03/…