【移動適配】一個像素的border怎麼實現

clipboard.png
一個像素裏複雜紛擾的世界html

文 | 啃先生 Mar.3rd.2016 首發於微信公衆號(啃先生) web

上一篇發了《【移動適配】移動Web怎麼作屏幕適配》,如今繼續。算法

壹 | Fisrt

在CSS的世界裏Px是原子操做,咱們沒法定義邊框的寬度是0.5px,最小都是1px。因此有如下結論:segmentfault

clipboard.png

然而,對於精益求精的產品而言,這種認識只是片面的!例如:我作了一個頁面,上面只有兩條邊框,在高清屏(如iPhone5s)上,通過特殊處理的邊框比1像素的邊框還要細。瀏覽器

所以,在高清屏上,border-width:1px;並非最小邊框。瀏覽器能夠顯示的最小粒度比CSS中的1px還要小。微信

clipboard.png

貳 | Second

那麼CSS中的1px是什麼?瀏覽器是怎麼渲染它的?ide

網頁在一個叫viewport的東西里渲染,能夠理解爲畫布,畫布被分紅 N x M 個小方格,1個CSS像素,就是其中的一個小方格。字體

viewport又是什麼?ui

網頁在viewport上渲染,能夠想像在PS上畫東西時,上面也有個畫布,這個畫布分割了 N x M 個方格,N是它的寬度,M是它的高度。寬高均可以任意設置,因此說viewport是虛擬的。假設設置寬度是400,那麼瀏覽器顯示區域的橫向將被分爲400份,CSS的1px佔的寬度就是顯示區域的 1/400。若是是980,那就是1/980。idea

viewport值不同時,對頁面元素寬度的影響

看一個的頁面,不動任何其餘代碼,只修改viewport的寬度,頁面發生了什麼變化

代碼以下:

clipboard.png

如下是運行結果

clipboard.png
viewport=500的情況

clipboard.png
viewport=900的情況

咱們只分析用戶頭像的圖片,已知頭像寬度是50px。

  • 當viewport寬度爲500時,屏幕橫向被分爲500份,每份1px,因此頭像寬度是屏幕的1/10。(500/50=10)

  • 當viewport寬度爲900時,屏幕橫向被分爲900份,每份1px,因此頭像寬度是屏幕的1/8。 (900/50=18)

因此,在CSS中,1px是指viewport中的一個小方格,而viewport寬度是能夠任意設置的。

叄 | Third

那麼,怎麼合理設置viewport的寬度?
viewport的寬度能夠是數字和字符串"device-width"。device-width指設備寬度。

  • 當取值爲數字時,指不管是什麼手機屏幕,viewport都被分爲那麼多份

  • 當取值爲device-width時,指的是手機屏幕的viewport寬度被設置爲跟手機寬度同樣。那這個寬度怎麼算的呢?

device-width的算法

先理清幾個很是關鍵的術語概念:

  • 物理像素:買手機的時候會有一個 nm 的分辨率,那是屏幕的nm個呈像的點,一個點(小方格)爲一個物理像素。它是屏幕能顯示的最小粒度

  • CSS像素:就是CSS裏的Px,上面已經講了是viewport中的一個小方格。

  • 像素密度:即dpi或ppi,屏幕每英寸所佔的物理像素點。

而CSS像素與物理像素之間是有一個轉換關係的。便是:
clipboard.png

其中,轉換系數計算過程以下:

clipboard.png

clipboard.png
安卓的密度區域和轉化係數的對應表

clipboard.png
iPhone的密度區域和轉化係數的對應表
(聲明:以上三個圖片來源於 http://tgideas.qq.com/webplat/info/news_version3/804/7104/7106/m5723/201509/376281.shtml)

例如:某檯安卓手機,分辨率是 1920*1080,屏幕對象線是5英寸。那麼在這臺手機上1個CSS像素,佔了多少個物理像素?

第一步:勾股定理算出對角線的分辨率,即 √(1920²+1080²)≈2203px

第二步:算出dpi。對角線的分辨率/對角線英寸 = 2203/5≈440dpi

第三步:得出轉換系數。根據上面的圖片,安卓手機440dpi,屬於XXHDPI,轉換系數是3

所以這臺手機中,1個CSS像素 = 3*物理像素。即1個CSS像素佔了3個物理像素。

這個轉換系數,也等同於dpr,設備像素比。

由於很明顯device-width的寬度值單位是CSS像素。因此當viewport設置爲device-width時,此時它是手機橫向分辨率 / 轉換系數。即:

clipboard.png

例如上述的例子中,該檯安卓手機的device-width是1080/3 = 360,即viewport的寬度是 360 CSS像素。
而viewport設置爲固定的數字有可能會破壞這種轉換關係,都是建議設置viewport寬度爲device-width,這樣1個CSS像素就盡最大可能恰好佔dpr個物理像素點。

肆 | Fourth

爲何會出現比border-width:1px更細的邊框?

屏幕可以顯示的最小粒度是1個物理像素,而當viewport寬度設置爲device-width時,1個CSS像素佔用的物理像素是由轉換系數決定的。因此,像iPhone6這樣的高清屏上,轉換系數爲3,border-width:1px,這個邊框佔了3個物理像素。若是能讓某個border的寬度爲1個物理像素,那麼它就比1個CSS像素要細,而本文最開始邊框那個更細是由於通過特殊處理後使其只佔用1個物理像素。

讓1個CSS像素佔用一個物理像素的辦法。

  • 方法一:viewport的scale

在viewport的屬性裏,除了設置寬高的width和height外,還有縮放比例scale。
當scale爲1時,頁面大小正常,但scale爲0.5時,頁面被縮小了1倍,原本1個CSS像素寬度佔2個物理像素寬度,縮小後的border-width:1px就只佔1個物理像素。代碼以下:

clipboard.png

其中,initial-scale爲1/dpr。

優勢:

  1. 不用爲border寫不少樣式代碼,跟原來同樣border:1px solid #D5D5D6便可

  2. 能夠輕鬆設置圓角 border-radius。

缺點:
整個頁面縮小了,反作用就是字體,圖片,其餘元素的尺寸邊距等等都同比例縮小了。這種狀況,設置viewport爲dpr*document.documentElment.clientWidth,再結合我上一篇文章《【移動適配】移動Web怎麼作屏幕適配(一)》,便可解決。

  • 方法二:transform scale

方法一是縮放整個頁面,在CSS3標準裏,能夠縮放某個元素。例如某個div.border-top,爲它設置以下樣式,使該DIV的頂部有一個邊框

.border-top{position: relative;border-top: none !important;}
.border-top:after {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 1px;
    background-color: #D5D5D6;
    -webkit-transform-origin: 0 0;
    -ms-transform-origin: 0 0;
    transform-origin: 0 0;
    -webkit-transform: scaleY(0.5);
    -ms-transform: scaleY(0.5);
    transform: scaleY(0.5);
}

在該DIV後面添加一個高度爲1px的內容,而且縮小dpr倍,這裏就是縮小成原來的1/2。
優勢是整個頁面不用縮放,缺點是border代碼較多,沒法實現border-radius圓角

寫完瀕臨虛脫。。

clipboard.png

  1. 深刻理解viewport和px(http://tgideas.qq.com/webplat/info/news_version3/804/7104/7106/m5723/201509/376281.shtml

  2. A tale of two viewports(http://www.quirksmode.org/mobile/viewports.html

bVs82n
適配的問題還沒講完,但又臭又長的純技術文太硬了,下期可能會喝點湯,講講故事。

開始碼字才知道碼字不易,堅持碼字更不易。轉載請聲明來源

clipboard.png

相關文章
相關標籤/搜索