天天看點

我修複的印象最深的一個bug - 關于移動端1px問題

關于移動端1px問題

前端這個活,真的是被産品虐到腦海中每天都有上千隻小動物飄過,然而不讓你省心的還有UI,總是跑過來告訴你,“你這和我設計圖不一樣呀?我這是1px,你這裝置上顯示的是2px”,然而,你能怎麼辦,改吧,筆者給你整理幾種解決辦法,讓你揚眉吐氣。

1px的線在高清屏下本應不需要做特殊處理。兩倍屏下會自動用兩排實體像素去展示‘1px’的細線,普通屏用一排實體像素去展示‘1px’的細線,他們應該看起來是相同的。但是,就像數學中的概念:線是沒有寬度的,點是沒有大小的。像素同樣是沒有大小的。

兩倍屏的實體像素密度是普通屏的兩倍,并不是每一個實體像素是普通屏的1/4大小,而是實體像素的間距是普通屏間距的1/2。

用兩倍屏下用兩排像素去展示,自然會比普通屏中用一排像素去展示看起來更粗。

先說原因

寫過移動端的小夥伴都知道,在頁面的開頭,我們都會加一個viewport,然而viewport的設定和螢幕實體分辨率是按比例而不是相同的. 移動端window對象有個devicePixelRatio屬性, 它表示裝置實體像素和css像素的比例, 在retina屏的iphone手機上, 這個值為2或3, css裡寫的1px長度映射到實體像素上就有2px或3px那麼長,是以1px看上去就變寬了。

解決辦法有很多,下面說幾個

flexible.js

引入flexible.js 加上rem布局,那可是對于移動端開發友善了不少,根據不同的裝置是可以達到前端開發對頁面的要求的,是以引入這個js,在處理1px問題的時候,隻需要正常書寫1px就可以了,而且你 不需要再添加等等,因為這個js都幫你動态的添加好了,是不是很友善。

可以按照不同螢幕的dpr作出轉換,比如在2倍屏下将1px的細線寫成border:0.5px。但這種方法隻在ios上支援,安卓上會顯示成被當成0px處理。

更通用的方案中,有svg和僞類元素兩種。

SVG方案

這種方案本質上border并沒有變細,但是boder被一分為二,靠内側的是透明的。

通過postcss-write-svg這個postcss插件将css中svg函數生成的圖像處理成base64。這樣就可以在css檔案直接調用svg函數。

僞類元素做法

border-width: 1px将邊框的寬度設為1px。

width:200%然後将僞類元素的寬高都設定成父元素的2倍。(但是邊框還是1px)

transform:scale(0.5)将僞類元素的x,y軸方向都縮放到0.5倍。

通過兩次尺寸的設定,使這個僞類子元素保持内容的大小還是和父元素一樣,但是border:0.5px的效果。

pointer-events: none當有元素的層級重疊時,滑鼠點選是無法穿透的。即絕對定位的僞類元素的層級更高,它底下的元素(即文字:retina border)無法被事件觸發。置為none時,絕對定位的元素不觸發事件,底下的那層才能被選中。

其他css樣式作用

僞類元素預設的display:inline。而position:absolute會使元素display:block。隻有塊級元素的尺寸(寬/高)設定才是有效的。

其中僞類選擇器中content是必填項,不然無法生效

transform-origin的縮放的中心點,預設是元素中心,

transform-origin的縮放的中心點,預設是元素中心,和絕對定位的top,right一樣,相對的是padding+content部分整個空間的位置

絕對定位的元素其top和right值是相對于padding+content的,預設值是從content開始,是以要規定都是0,否則當父元素有padding時,border就移位了

當使用百分比時,其父元素的高度必須顯式指定,(20px/20view)不能是由子元素撐開的,但是寬度是可以的。

繼續閱讀