H5 - rem自適應方案

Silkage發表於2021-04-27

  H5 - rem自適應方案

  對於H5應用來說,為了更通用地滿足各機型螢幕的自適應佈局要求,我們目前採用rem佈局方案。

  rem

  rem是相對於根元素(html)字型大小的單位,它只是一種相對單位。不同於另一個相對單位em,em是相對於父元素的字型大小,而rem則相對於根元素(html),與父元素的字型大小無關。

  等比例適配所有螢幕

  不論傳統的px絕對畫素佈局,還是流式佈局、固定寬度和響應式做法,都有其缺陷,並不能完全做到自適應所有螢幕。

  但是,rem方案可以比較容易地做到等比例適配所有螢幕,保證各螢幕的顯示效果與原始設計稿一致。

  我們看看rem是如何工作的。

  舉個例子:

  html{

  font-size: 20px;

  }

  .btn {

  width: 6rem;

  height: 3rem;

  line-height: 3rem;

  font-size: 1.2rem;

  display: inline-block;

  background: #06c;

  color: #fff;

  border-radius: .5rem;

  text-decoration: none;

  text-align: center;

  }

  如果我們把html的font-size改改,再看看效果。

  html{

  font-size: 40px;

  }

  可以看到,按鈕的 width 、 height 、 font-size 和 border-radius 都被放大了一倍,我們只需要改變 html 的 font-size ,就能改變按鈕在頁面上的顯示大小,而不必再去重設按鈕的樣式規則。

  按鈕的大小 = 按鈕的rem * html.font-size

  於是,利用這個特性,我們可以這樣實現等比例適配所有螢幕。

  基準螢幕寬度

  以設計稿寬度作為最理想的基準螢幕寬度,假設設計稿寬度是 750px ,那麼基準螢幕寬度就是 750px ,寬度大於 750px 的螢幕,等同於等比例放大了頁面,小於 750px 的螢幕,等同於等比例縮小了頁面。

  把設計稿750px十等分一下,每等分= 75px ,我們可以把這個 75px 當做 1個rem單位 ,那麼 750px 寬度就等於是 10rem 。

  設定html的 font-size: 75px ,即 1rem ,也就是 rem的基準px=75px 。

  設計稿上的元素尺寸換算公式: 原始px值 / rem基準px ;例如 240px * 120px 的元素,其實就是 3.2rem * 1.6rem 。

  適配任意螢幕

  我們可以透過js來取得當前機型螢幕的寬度值,然後10等分得出當前螢幕1個rem應該代表的絕對畫素值,再將這個 rem基準px 動態設定到 html.font-size ,核心程式碼如下:

  var docEl = document.documentElement;

  var width = docEl.getBoundingClientRect().width;

  var rem = width / 10;

  docEl.style.fontSize = rem + 'px';

  我們還可以透過less預處理工具,編寫一個絕對px轉rem的函式,自動轉換px值,省卻我們手動計算rem的麻煩,核心程式碼如下:

  @design-width: 750px; // 設計稿寬度

  @rem: @design-width / 10; // 10等分得到的rem基準px

  .px2rem(@attr; @px) when (ispixel(@px)) {

  @{attr}: unit(@px / @rem, rem);

  }

  // 處理非px值

  .px2rem(@attr; @px) when (default()) {

  @{attr}: @px;

  }

  .px2rem(@attr; @px1; @px2) when (ispixel(@px1)) and (ispixel(@px2)) {

  @{attr}: unit(@px1 / @rem, rem) unit(@px2 / @rem, rem);

  }

  .px2rem(@attr; @px1; @px2) when (ispixel(@px1)) and not (ispixel(@px2)) {

  @{attr}: unit(@px1 / @rem, rem) @px2;

  }

  .px2rem(@attr; @px1; @px2) when not (ispixel(@px1)) and (ispixel(@px2)) {

  @{attr}: @px1 unit(@px2 / @rem, rem);

  }

  //

  處理非px值

  .px2rem(@attr; @px1; @px2) when (default()) {

  @{attr}: @px1 @px2;

  }

  然後用法如:

  .px2rem(width; 240px);

  .px2rem(padding; 10px; 20px);

  對於Retina高畫質螢幕的處理

  對於2倍和3倍的高畫質螢幕,分別做2倍和3倍處理。

  處理方法是:重設viewport,將viewport縮小指定倍數。

  核心程式碼如:

  var dpr = 1;

  var scale = 1;

  // 僅ios考慮2/3倍方案,其他裝置下,仍舊使用1倍的方案

  if (/i(Phone|Pod|Pad)/.test(navigator.userAgent)) {

  var ratio = win.devicePixelRatio;

  dpr = ratio >= 3 ? 3 : (ratio >= 2 ? 2 : 1);

  } else {

  dpr = 1;

  }

  scale = 1 / dpr;

  docEl.setAttribute('data-dpr', dpr);

  metaEl.setAttribute('content', 'initial-scale=' + scale + ', width=device-width, maximum-scale=' + scale + ', user-scalable=no');

  字號不用rem

  字號大小不推薦用rem作為單位,因此,字號仍舊使用px作為單位,並配合 data-dpr 自定義屬性來在普通屏和2/3倍高畫質屏設定不同的 font-size 。

  高畫質屏的 font-size =設計稿的font-size,普通屏是設計稿font-size的一半。

  處理方式是:設定 body 的 font-size ,此後頁面上所有元素的字號大小都是相對於body的 font-size ,而不是html的 font-size 。

  核心程式碼如:

  var fontBase = 16; // 普通屏基準字號:16px,高畫質屏基準字號:16px * 2、16px * 3

  if (doc.readyState === 'complete') {

  document.body.style.fontSize = fontBase * dpr + 'px';

  } else {

  document.addEventListener('DOMContentLoaded', function(e) {

  document.body.style.fontSize = fontBase * dpr + 'px';

  }, false);

  }

  // 預設普通屏,設計稿字號的一半

  h3 {

  font-size: 18px;

  }

  // 高畫質屏:設計稿的字號

  [data-dpr="2"] h3 {

  font-size: 36px;

  }

  [data-dpr="3"] h3 {

  font-size: 54px;

  }

  文字字號應該用rem嗎? 顯然,我們在iPhone3G和iPhone4的Retina屏下面,希望看到的文字字號是相同的。也就是說,我們不希望文字在Retina螢幕下變小,另外,我們希望在大屏手機上看到更多文字,以及,現在絕大多數的字型檔案都自帶一些點陣尺寸,通常是16px和24px,所以我們不希望出現13px和15px這樣的奇葩尺寸。 如此一來, rem並不適合用到段落文字上。所以在整個案中,考慮文字還是使用px作為單位。只不過使用[data-dpr]屬性來區分不同dpr下的文字字號大小。

  關於css圖片

  css圖片只需要按設計稿輸出的高畫質圖即可,編寫樣式的時候, width 和 height 分別取圖片真實寬和高的一半,再折算成rem單位,然後設定 background-size: contain 。

  .icon {

  width: .px2rem(image-width / 2);

  height: .px2rem(image-height / 2);

  background-image: url(image);

  background-size: contain;

  }

  關於img標籤圖片

  如果img標籤載入的圖片可以知道其寬高的話,那麼也可以按照上一節的方法來設定圖片的高畫質顯示。

  如果不能預知圖片大小,則需要透過js動態計算,將計算得出的寬高按上一節的方法動態設到 style 上。

  動態計算rem的函式是: FS.px2rem(px) 。

  完整程式碼

  <html>

  <head>

  <meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1, user-scalable=no" />

  <script type="text/javascript">

  var FS = {};

  (function(win, FS) {

  var doc = win.document;

  var docEl = doc.documentElement;

  var metaEl = doc.querySelector('meta[name="viewport"]');

  var dpr = 1;

  var scale = 1;

  var fontBase = 16;

  // 僅ios考慮2/3倍方案,其他裝置下,仍舊使用1倍的方案

  if (/i(Phone|Pod|Pad)/.test(navigator.userAgent)) {

  var ratio = win.devicePixelRatio;

  dpr = ratio >= 3 ? 3 : (ratio >= 2 ? 2 : 1);

  } else {

  dpr = 1;

  }

  scale = 1 / dpr;

  docEl.setAttribute('data-dpr', dpr);

  metaEl.setAttribute('content', 'initial-scale=' + scale + ', width=device-width, maximum-scale=' + scale + ', user-scalable=no');

  function refreshRem() {

  var width = docEl.getBoundingClientRect().width;

  var rem = width / 10;

  docEl.style.fontSize = rem + 'px';

  FS.rem = rem;

  }

  var tid = null;

  win.addEventListener('resize', function() {

  clearTimeout(tid);

  tid = setTimeout(refreshRem, 300);

  }, false);

  if (doc.readyState === 'complete') {

  doc.body.style.fontSize = fontBase * dpr + 'px';

  } else {

  doc.addEventListener('DOMContentLoaded', function(e) {

  doc.body.style.fontSize = fontBase * dpr + 'px';

  }, false);

  }

  refreshRem();

  FS.dpr = dpr;

  FS.rem2px = function(d) {

  var val = parseFloat(d) * FS.rem;

  if (typeof d === 'string' && d.match(/rem$/)) {

  val += 'px';

  }

  return val;

  }

  FS.px2rem = function(d) {

  var val = parseFloat(d) / FS.rem;

  if (typeof d === 'string' && d.match(/px$/)) {

  val += 'rem';

  }

  return val;

  }

  })(window, FS);

  </script>

  </head>

  <body></body>

  </html>


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69999013/viewspace-2770028/,如需轉載,請註明出處,否則將追究法律責任。

相關文章