吃透移動端 H5 響應式佈局

前言

最近寫第三個移動端 H5 的項目了,準備記錄下本身在 H5 項目中的一些實踐探索。移動端 H5 與 PC 端開發最大的區別之一,大概就是響應式佈局問題。css

那麼下面咱們來聊聊移動端響應式佈局,瞭解他的前因後果,對現有的最佳解決方案探索。html

問題

全文將圍繞下面幾個問題進行論述和展開:前端

  • 寫移動端 H5 相關頁面,相比 PC 端有哪些值得注意的點?
  • 關於H5 響應式佈局有哪些解決方案?
  • 什麼是 rem?如何在項目中完美使用它?
  • vh/vw 是最佳解決方案嗎?它有什麼優點和缺陷
  • 大型開源庫裏面經常使用解決方案是什麼?
  • 怎樣快速搭建一套移動端佈局解決方案?

由來

概念

什麼是 H5 技術?

H5 這個命名自己是一個很不討巧的命名,咋一眼看上去認爲 HTML5,或者第 5 級標題的標籤,對一些形成一些不小的誤解。vue

好比:個人一個某後端同事,談論到 H5 很簡單,HTML 以前我也學過一些,之後要是你請假,我來幫你寫。git

我是一臉矇蔽,H5 === HTML?github

再看看,搜索引擎中H5是什麼?(引用來自谷歌詞條第一頁)web

如此看來,將 H5 視做 HTML 的大有人在,而 H5 這個概念只在中國特有,因此對外國人來講他們也認爲是 HTML, 因此,對於外國人和非這個領域的人來講,他們存在同樣的誤解。vue-cli

目前的 H5 算是一個比較大的概念了,我認爲的 H5 技術是一系列移動端 web 前端技術的集合 大體用一個韋恩圖表示以下後端

咱們這裏只談 web 前端中 H5 技術,H5 技術自己是用於移動端的 web 網頁。因爲App自己有個 「 webview 」 的容器,在容器裏能夠運行 web 前端相關代碼,由此 H5 和原生 App 結合又衍生出來了 Hybrid App 技術瀏覽器

Hybrid App 技術大體原理

這是我給公司同事普及 H5 知識繪製的圖像。

移動端 web 和 PC web 的區別

PC 端咱們是怎麼佈局的呢? 通常採用兩種方案,一種是 min-width 限制最小的寬度,瀏覽器寬度小於 min-width 就直接滾動。另一種呢,就是留白。設置頁面一個基礎寬度,超出的部分留白。

可是這兩種解決方案在移動端可行嗎?

移動端手機的寬度,大多不一致,並且沒辦法進行窗口的縮放。讓移動端產生滾動,體驗更加糟糕,更別說和原生 app 性能相比較,基本頁面展現體驗就不好了。

那麼留白呢? 更不可行了,手機設備自己寬度就小,再留白就基本看不了什麼了。

因此爲了讓這種 web 可以像原生 app 同樣的體驗,就出現了 H5 技術。進一步衍生了 Hybird, 雖然比不上 app 性能,可是在熱更新 上佔有絕對優點,有着原生沒法替代的地方。

下面咱們來就來實踐下 H5 最基本的技術之一移動端響應式佈局

實踐

解決方案一:rem + pxToRem

概念

css 中用於計量的單位有兩種,一種是絕對單位,另外一種是相對單位

絕對單位

對於絕對單位,通常來講經常使用的也就 px, 其餘的可能打印須要用到

相對單位

對於相對單位來講, emrem 屬於一對, vwvh 屬於一對。

前一對相對於字體大小,區別在於 rem 相對於根字體,對於咱們控制總體的大小相對容易些,因此咱們可使用它來控制整個頁面的縮放。

後一對,相對於視窗的大小,這個將在下一個節中發揮主要做用。

原理

  1. 監聽屏幕視窗的寬度,經過必定比例換算賦值給htmlfont-size。此時,根字體大小就會隨屏幕寬度而變化。
  2. px 轉換成 rem, 常規方案有兩種,一種是利用sass/less中的自定義函數 pxToRem,寫px時,利用pxToRem函數轉換成 rem。另一種是直接寫px,編譯過程利用插件所有轉成rem。這樣 dom 中元素的大小,就會隨屏幕寬度變化而變化了。

實現

  1. 動態更新根字體大小
const MAX_FONT_SIZE = 420

// 定義最大的屏幕寬度
document.addEventListener('DOMContentLoaded', () => {
  const html = document.querySelector('html')
  let fontSize = window.innerWidth / 10
  fontSize = fontSize > MAX_FONT_SIZE ? MAX_FONT_SIZE : fontSize
  html.style.fontSize = fontSize + 'px'
})
複製代碼
  1. pxrem

pxToRem 方案一

$rootFontSize: 375 / 10;
// 定義 px 轉化爲 rem 的函數
@function px2rem ($px) {
    @return $px / $rootFontSize + rem;
}

.demo {
    width: px2rem(100);
    height: px2rem(100);
}
複製代碼

pxToRem方案二

vue-cli3 中配置 裝 postcss-pxtorem 插件就能夠了,其餘平臺大體差很少

const autoprefixer = require('autoprefixer')
const pxtorem = require('postcss-pxtorem')
module.exports = { 
  // ...
  css: {
    sourceMap: true,
    loaderOptions: {
      postcss: {
        plugins: [
          autoprefixer(),
          pxtorem({
            rootValue: 37.5,
            propList: ['*']
          })
        ]
      }
    }
  }
}
複製代碼

點擊快速配置 H5 項目工程

繼續探索postcss-pxtorem插件源碼,查看它實現的原理

function createPxReplace (rootValue, unitPrecision, minPixelValue) {
    return function (m, $1) {
        if (!$1) return m;
        var pixels = parseFloat($1);
        if (pixels < minPixelValue) return m;
        var fixedVal = toFixed((pixels / rootValue), unitPrecision);
        return (fixedVal === 0) ? '0' : fixedVal + 'rem';
    };
}
複製代碼

px變換成 rem 主要是這個函數,固然裏面有不少可配置的參數, 核心原理和咱們方案一差很少,方便在於,不須要每次寫px都要加上一個函數,代碼也清晰不少

是否是全部元素 px 都要轉換成 rem呢?,那可不必定哦,border 中的 px 不該該轉 rem,涉及到另一個 1px 的問題,上一篇文章詳細論述過,避免 pxrem,將 border 中的 px 大寫成 PX/Px/pX

1px 適配問題請移至 吃透移動端 1px

解決方案二:vh + vw

原理

vw 相對於視窗寬度的單位,隨寬度變化而變化。由此看來,方案一實際上是方案二的一種 Hack, 經過使用監聽實現了方案二的效果

實現

與 rem 相似作法,直接使用 postcss-px-to-viewport 插件進行配置, 配置方式也是和 postcss-pxtorem 大同小異

咱們看看插件的原理是否是也是同樣的

function createPxReplace(opts, viewportUnit, viewportSize) {
  return function (m, $1) {
    if (!$1) return m;
    var pixels = parseFloat($1);
    if (pixels <= opts.minPixelValue) return m;
    var parsedVal = toFixed((pixels / viewportSize * 100), opts.unitPrecision);
    return parsedVal === 0 ? '0' : parsedVal + viewportUnit;
  };
}
複製代碼

果真呢,連方法名、變量名、代碼邏輯,都一摸同樣哈哈哈,誰抄誰,我就不指出來啦 - -

其餘解決方案

方案 缺陷
1 百分比 高度沒法百分比
2 媒體查詢 + metaviewport 不一樣設備寬度不一樣,縮放比沒法徹底肯定
3 flex 仍是沒法解決寬度超出問題

上面方案均存在致命缺陷,不推薦使用它完成移動端佈局計算。

flex 與 rem 結合使用更佳

兼容性

上述兩種方案,兼容性主要在於 rem,vh,vw 關鍵詞上

rem在移動端表現高達 100%,使人驚歎!

vh vw 表現慘不忍睹

不得不說 rem 仍然是移動端 h5 佈局的最佳方案

開源庫解決方案

vant 組件庫

vant 組件庫中,默認採用 px 作計量單位,若是須要使用 rem,直接使用插件完美適配。

對於 vw 方案,vant 也是能夠經過插件將 px 轉成 vw,對於 vw 可能會存在一些坑點。

ant-design-mobile 組件庫

ant-design-mobile 組件庫仍然使用 px 單位

@hd: 1px; // 基本單位

// 字體尺寸
// ---
@font-size-icontext: 10 * @hd;
@font-size-caption-sm: 12 * @hd;
@font-size-base: 14 * @hd;
@font-size-subhead: 15 * @hd;
@font-size-caption: 16 * @hd;
@font-size-heading: 17 * @hd;

// 圓角
// ---
@radius-xs: 2 * @hd;
@radius-sm: 3 * @hd;
@radius-md: 5 * @hd;
@radius-lg: 7 * @hd;
@radius-circle: 50%;

// 邊框尺寸
// ---
@border-width-sm: 1PX;
@border-width-md: 1PX;
@border-width-lg: 2 * @hd;
複製代碼

vant 組件同樣,仍是由開發者來決定到底用哪種方案 這種把選擇權交給開發者,算是一種開源庫的最靈活的作法了

總結

經過該文,你大概瞭解 H5 問題的前因後果了吧,也明白瞭如何解決移動端響應式佈局問題,若是這篇文章能解決你的疑問或者工做中問題,不妨點個贊收藏下。

因爲技術水平有限,文章中若有錯誤地方,請在評論區指出,感謝!

上一篇文章,解決了 1px 問題,這篇文章解決了響應式佈局問題, 接下我應該會繼續研究下,關於 H5 一些踩坑總結,以後應該會去研究下 vue 最新的源碼再進行分享,想持續瞭解更多,不妨點個關注唄。

相關文章
相關標籤/搜索