【CSS】872- 淺析rem佈局方案

一些像素概念

  • 物理像素:即實際的每一個物理像素,也就是移動設備上每一個物理顯示單元(點)
  • 設備邏輯像素( css中的 px):可以理解爲一個虛擬的相對的顯示塊,與物理像素有着一定的比例關係,也就是下面的設備像素比
  • 設備像素比( dpr):= 物理像素 / 設備獨立像素( px)

如果dpr1的話,那麼1px = 1物理像素xy軸加起來就是1

如果dpr2的話,那麼1px = 2物理像素,xy軸加起來就是4

以此類推

在js中可以通過window.devicePixelRatio獲取當前設備的dpr

這裏說明一下,無論dpr多大,1px的大小通常來說是一致的,這也就意味着,隨着dpr的增大,物理像素點會越來越小,這樣才能容納更多的物理像素,才能更高清,更retina

說完基本概念,來說一下幾個問題:

retina屏圖片模糊

首先普及一下位圖像素:一個位圖像素是圖片的最小數據單元,每一個單元都包含具體的顯示信息(色彩,透明度,位置等等)

那爲什麼在dpr高的retina屏上反而會模糊呢?看圖~

1dpr的屏幕上,位圖像素和物理像素一一對應沒什麼問題,但是在retina屏上,由於一個px4個甚至更多的物理像素組成,並且單個位圖像素不能進一步分割,所以會出現就近取色的情況,如果取色不均,那麼就會導致圖片模糊。

對於這種情況,只能採用@2x@3x這樣的倍圖來適配高清展示,這樣側向說明了爲什麼照着iphone6做的ui稿不是375,而是750的問題。

雖然這樣在dpr1的屏幕上會導致1個物理像素上有4個位圖像素,但是這種情況的取色算法更優,影響不大,不做討論。

1px的粗細問題

由於1px的實際大小是一樣的,只是裏面的物理像素數量不同,所以如果直接寫1px是沒問題的,不會出現粗細不同的情況,但是這樣一來retina的優勢也rem的作用也就沒了,其實還是dpr的問題,dpr1,那麼1px就是一個物理像素,但是在retina中。1px實際可能有49個物理像素,ui想要的其實是1個物理像素,而不是1px,不過由於不是素所有的手機都能適配0.x,所以曲線救國,採用scale縮放或者設置meta都可以

viewport

三個概念

  • layout viewport
  • visual viewport
  • ideal viewport

layout viewport

最開始,pc上的頁面是無法再移動端正常顯示的,因爲屏幕太小,會擠作一團,所以就有了viewport的概念,又稱佈局視口(虛擬視口),這個視口大小接近於pc,大部分都是980px

visual viewport

有了佈局視口,還缺一個承載它的真是視口,也就是移動設備的可視區域-視覺視口(物理視口),這個尺寸隨着設備的不同也有不同。這樣在視覺視口中創建了一個佈局視口,類似overscroll:scroll;這樣,可以通過滾動拖拽、縮放擴大進行較好的訪問體驗

ideal viewport

像上面的體驗在早些年可能比較多,但是近幾年幾乎很少了,還是歸咎於用戶體驗,所以,我們還需要一個視口-理想視口(同樣是虛擬視口),不過這個理想視口的大小是等於佈局視口的,這樣用戶就能得到更好的瀏覽體驗。

一個特性

viewport有六種可以設置的常用屬性:

  • width:定義 layout viewport的寬度,如果不設置,大部分情況下默認是 980
  • height:非常用
  • initial-scale:可以以某個比例將頁面縮放\放大,你也可以用它來設置 ideal viewport
  <meta name='viewport' content='initial-scale=1' />
  • maximum-scale:限制最大放大比例
  • minimum-scale:限制最小縮小比例
  • user-scalable:是否允許用戶放大\縮小頁面,默認爲 yes

rem適配方案

先說原理,通過meta修正1px對應的物理像素數量,在根據統一的設計稿來生成html上的動態font-size,根據dpr構造字體等誤差較大的樣式的mixin

// 第一版:
function initRem({
  const meta = document.querySelector('meta[name="viewport"]');;
  const html = document.documentElement;
  const cliW = html.clientWidth;
  const dpr = window.devicePixelRatio || 1;
  meta.setAttribute('name''viewport');
  meta.setAttribute(
      'content',
      `width=${cliW * dpr}, initial-scale=${1 /
          dpr} ,maximum-scale=${1 /
 dpr}
, minimum-scale=${1 /
          dpr},user-scalable=no`
  );
  html.setAttribute('data-dpr', dpr);
  /
/ 這樣計算的好處是,你可以直接用ui的px/100得到的就是rem大小,方便快捷,無需mixin
  html.style.fontSize = 10 / 75 * cliW * dpr + 'px';
}
initRem();
window.onresize = window.onorientationchange = initRem();

對於引入的第三方ui組件,需要使用px2rem轉換工具去做整體轉換,比如postcss-pxtorem:https://github.com/cuth/postcss-pxtorem

1. JavaScript 重溫系列(22篇全)
2. ECMAScript 重溫系列(10篇全)
3. JavaScript設計模式 重溫系列(9篇全)
4.  正則 / 框架 / 算法等 重溫系列(16篇全)
5.  Webpack4 入門(上) ||  Webpack4 入門(下)
6.  MobX 入門(上)  ||   MobX 入門(下)
7. 100 +篇原創系列彙總

回覆“加羣”與大佬們一起交流學習~

點擊“閱讀原文”查看 100+ 篇原創文章

本文分享自微信公衆號 - 前端自習課(FE-study)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章