對於前端開發者來講,要處理這個問題,必須先補充一個知識點,就是設備的 物理像素[設備像素] & 邏輯像素[CSS像素]
javascript
爲何移動端CSS裏面寫了1px,實際上看起來比1px粗;瞭解設備物理像素和邏輯像素的同窗應該很容易理解,其實這兩個px
的含義實際上是不同的,UI設計師要求的1px是指設備的物理像素1px,而CSS裏記錄的像素是邏輯像素,它們之間存在一個比例關係,能夠用javascript中的window.devicePixelRatio
來獲取,也能夠用媒體查詢的-webkit-min-device-pixel-ratio
來獲取。固然,比例多少與設備相關。
在手機上border沒法達到咱們想要的效果。這是由於devicePixelRatio特性致使,iPhone的devicePixelRatio==2,而border-width: 1px描述的是設備獨立像素,因此,border被放大到物理像素2px顯示,在iPhone上就顯得較粗。css
移動端開發常須要在html的header裏添加以下一句:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
這句話定義了本頁面的viewport的寬度爲設備寬度,初始縮放值和最大縮放值都爲1,並禁止了用戶縮放。html
你的疑問可能來了,總是看到viewport,除了知道中文名叫視口,究竟是啥意思?其實,它就是設備屏幕上能用來顯示咱們網頁內容的那一塊區域,具體點就是瀏覽器或app中的webview用來顯示網頁的那部分區域,但viewport又不侷限於瀏覽器可視區域的大小,可能大也可能小。體如今用戶是否縮放了屏幕。前端
心細的同窗應該都有感受,meta標籤中常設置user-scalable=no
也就是禁止用戶縮放,那用戶縮放到底會形成什麼影響呢? 其實也就是顯示上的變化。縮放一倍,CSS像素(邏輯像素)所表明的物理像素也就縮放了一倍,即設備物理像素和設備獨立像素的比例增大(減少)了一倍。java
或許你已經明白1px變粗的緣由是啥了, viewport的設置和屏幕物理分辨率是按比例而不是相同的. 移動端window對象有個devicePixelRatio屬性, 它表示設備物理像素和css像素的比例, 在retina屏的iphone手機上, 這個值爲2或3, css裏寫的1px長度映射到物理像素上就有2px或3px那麼長。
css3
IOS8下已經支持帶小數的px值, media query
對應devicePixelRatio
有個查詢值-webkit-min-device-pixel-ratio
, css能夠寫成這樣web
.border { border: 1px solid #999 } @media screen and (-webkit-min-device-pixel-ratio: 2) { .border { border: 0.5px solid #999 } } @media screen and (-webkit-min-device-pixel-ratio: 3) { .border { border: 0.333333px solid #999 } }
【缺點】對設備有要求,小數像素目前兼容性較差。瀏覽器
該方案是對上述方案的優化,總體思路就是利用viewport + rem + js
動態的修改頁面的縮放比例,實現小於1像素的顯示。在頁面初始化時,在頭部引入原始默認狀態以下:app
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <meta name="viewport" id="WebViewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
接下來的任務就是js的動態修改縮放比 以及 實現rem根元素字體大小的設置。iphone
var viewport = document.querySelector("meta[name=viewport]") if (window.devicePixelRatio == 1) { viewport.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no') } if (window.devicePixelRatio == 2) { viewport.setAttribute('content', 'width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no') } if (window.devicePixelRatio == 3) { viewport.setAttribute('content', 'width=device-width, initial-scale=0.333333333, maximum-scale=0.333333333, minimum-scale=0.333333333, user-scalable=no') } var docEl = document.documentElement; var fontsize = 10 * (docEl.clientWidth / 320) + 'px'; docEl.style.fontSize = fontsize;
【缺點】覺得縮放涉及全局的rem單位,比較適合新項目,對於老項目可能要涉及到比較多的改動。
.border-image-1px { border-width: 1px 0px; -webkit-border-image: url("border.png") 2 0 stretch; border-image: url("border.png") 2 0 stretch; }
【解釋】border-width
指定邊框的寬度,能夠設定四個值,分別爲上右下左border-width: top right bottom left
。border-image
該例意爲:距離圖片上方2px(屬性值上沒有單位)裁剪邊框圖片做爲上邊框,下方2px裁剪做爲下邊框。距離左右0像素裁剪圖片即沒有邊框,以拉伸方式展現
結合起來就是:在邊框圖片中,裁剪圖片上下方的2個像素寬度做爲上下邊框,並展現在寬度爲1個像素的邊框空間裏。左右沒有邊框。 注意這裏的1個像素是特殊的,專指物理像素,而平時設定的長寬1px則表示邏輯像素(該觀點爲我的理解)。
你可能並無理解,裁剪邊框是什麼鬼?爲啥還要裁剪?
border-image
確實是個很難理解的屬性,是去w3c看了以後更加蒙圈了。w3c內容提煉的太精緻了,但解釋根本就不夠。所以奉上張鑫旭老師 border-image詳解 一文,特別要理解九宮格裁剪法。
固然,這種方式引入了圖片,咱們還能將圖片裝換成base64形式表現
.border-image-1px { border-width: 1px 0px; -webkit-border-image: url("data:image/png;base64,xxx") 2 0 stretch; border-image: url('如上'); }
【缺點】須要製做圖片,圓角可能出現模糊
除了使用圖片外,固然也能使用純css來實現,百度糯米糰就是採用的這種方案。
.border { background-image:linear-gradient(180deg, red, red 50%, transparent 50%), linear-gradient(270deg, red, red 50%, transparent 50%), linear-gradient(0deg, red, red 50%, transparent 50%), linear-gradient(90deg, red, red 50%, transparent 50%); background-size: 100% 1px,1px 100% ,100% 1px, 1px 100%; background-repeat: no-repeat; background-position: top, right top, bottom, left top; padding: 10px; }
【思路】將本來1個物理像素的邊框大小利用線性漸變分割成幾個部分(百分比控制),實現小於1像素效果
【解釋】linear-gradient
指定線性漸變,接受大於等於3個參數,第一個爲漸變旋轉角度,第二個開始爲漸變的顏色和到哪一個位置(百分比)所有變爲該顏色,該例子中,第一句就是,漸變方向旋轉180度,即從上往下(默認爲0度從下往上),從紅色開始漸變,到50%的位置仍是紅色,再漸變爲繼承父元素顏色。
【缺點】由於每一個邊框都是線性漸變顏色實現,所以沒法實現圓角
利用陰影也能夠實現,優勢是沒有圓角問題,缺點是顏色很差控制
div { -webkit-box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.5); }
【理解】來回顧一下box-shadow
屬性的用法。
box-shadow: h-shadow v-shadow [blur] [spread] [color] [inset];
參數分別表示: 水平陰影位置,垂直陰影位置,模糊距離, 陰影尺寸,陰影顏色,將外部陰影改成內部陰影,後四個可選。該例中爲什麼將陰影尺寸設置爲負數?設置成-1px
是爲了讓陰影尺寸稍小於div元素尺寸,這樣左右兩邊的陰影就不會暴露出來,實現只有底部一邊有陰影的效果。從而實現分割線效果(單邊邊框)。
在以上的用法種,無非逃不開一種思想,就是將1px縮小爲0.5px來展現,然而。0.5px並非全部的設備或瀏覽器都支持,就考慮用媒體查詢或viewport將其縮放比例。其實1像素問題的產生基本發生在設置邊框或分割線的時候,場景並不覆蓋全局樣式,所以,直接縮放須要設置的元素,纔是咱們真正須要的。tranform
就能實現這個需求。
height: 1px
,根據媒體查詢結合transform
縮放爲相應尺寸。div { height:1px; background:#000; -webkit-transform: scaleY(0.5); -webkit-transform-origin:0 0; overflow: hidden; }
2.用::after
和::befor
,設置border-bottom:1px solid #000
,而後在縮放-webkit-transform: scaleY(0.5);
能夠實現兩根邊線的需求
div::after{ content:'';width:100%; border-bottom:1px solid #000; transform: scaleY(0.5); }
3.用::after
設置border:1px solid #000; width:200%; height:200%,
而後再縮放scaleY(0.5);
優勢能夠實現圓角,京東就是這麼實現的,缺點是按鈕添加active
比較麻煩。
.div::after { content: ''; width: 200%; height: 200%; position: absolute; top: 0; left: 0; border: 1px solid #bfbfbf; border-radius: 4px; -webkit-transform: scale(0.5,0.5); transform: scale(0.5,0.5); -webkit-transform-origin: top left; }
/* 2倍屏 */ @media only screen and (-webkit-min-device-pixel-ratio: 2.0) { .border-bottom::after { -webkit-transform: scaleY(0.5); transform: scaleY(0.5); } } /* 3倍屏 */ @media only screen and (-webkit-min-device-pixel-ratio: 3.0) { .border-bottom::after { -webkit-transform: scaleY(0.33); transform: scaleY(0.33); } }