移動端布局之postcss-px-to-viewport(兼容vant)【更新於2021/09/27】


移動端布局之postcss-px-to-viewport(兼容vant)【更新於2021/09/27】

 

主角是誰

在今天這篇文章中,我並不會在這里講一些移動端視口的概念,包括物理像素和邏輯像素,理想視口,dpr等等等等,我只介紹這樣一種非常不錯的移動端適配方案:post-css-to-viewport,如果我說這種方案能解決98%以上的移動端布局痛點,我想整個掘金,應該沒有人會反駁。

痛點在哪里

在之前有一種流行已久的移動端適配方案,那就是rem,我想下面這兩句代碼,有不少老移動端都不會陌生:

    const deviceWidth = document.documentElement.clientWidth || document.body.clientWidth;     document.querySelector('html').style.fontSize = deviceWidth / 7.5 + 'px'; 

沒錯,在那個移動端UI稿尺寸為750*1334滿天飛的時代,這兩句代碼確實給開發者帶來了很大的方便,這樣設置根font-size后,px和rem的轉換比例成了100, 為比如UI稿一個長寬分別為120px*40px,那么開發者對應的寫成1.2rem*0.4rem就可以了

這種換算已經是頗為方便,但是並非所有的項目都能這樣去設置一個方便換算的比例系數,當比例系數為100時,小數點往前面挪兩位就行了,然而有的項目設置的換算系數千奇百怪,有50的,有16的,很多已經嚴重超出口算力所能及的范疇了。所以后來誕生的px-to-rem或者px2rem就是為了解決這個問題

人們希望有這樣一種方案…

  • 首先,無論換算方不方便,我都不想換算(就是這么懶🤭),我也不想去操心什么轉換系數
  • 其次,有些屬性或者類選擇器我不想進行轉換
  • css代碼要足夠簡潔,我只希望看到一種單位,那就是px

兩種方案都很好,但我偏愛后者

第一種方案是lib-flexible+postcss-pxtorem,在相當長一段時間里,這兩個插件搭配都是解決移動端布局的神器,lib-flexible是阿里手淘系開源的一個庫,用於設置font-size,同時處理一些窗口縮放的問題。其中一位主要貢獻者正是阿里的大神winter。

直到2020年的今天,我仍然可以說,lib-flexible+postcss-pxtorem是解決移動端布局的主流,但是我們可以好好想一想,它是否有什么不足?

從我個人來說,我認為它主要有以下兩個不足:

  1. 兩個插件需要配套使用,而且rootValue設置的值不好理解
  2. rem是相對於html元素字體單位的一個相對單位,從本質上來說,它屬於一個字體單位,用字體單位來布局,並不是太合適

翻閱其github地址,可以看到這樣一段有意思的話:

第二種方案是viewport,postcss-px-to-viewport就是這樣一款優秀的插件,它解決了以上提到的痛點,也滿足以上提到的理想要求。它將px轉換成視口單位vw,眾所周知,vw本質上還是一種百分比單位,100vw即等於100%,即window.innerWidth

在vue項目中引入試試(更新於2021年9月27日)

  1. 創建一個vue項目並安裝該插件
 vue create mobile-px-demo

 cd mobile-px-demo && yarn add postcss-px-to-viewport -D

以下是我的創建配置,本機node版本為v14.16.1

image.pngimage.png
  1. 在項目根目錄下添加.postcssrc.js文件
  2. 添加如下配置:
module.exports = {   plugins: {     autoprefixer: {}, // 用來給不同的瀏覽器自動添加相應前綴,如-webkit-,-moz-等等     "postcss-px-to-viewport": {       unitToConvert: "px", // 要轉化的單位       viewportWidth: 750, // UI設計稿的寬度       unitPrecision: 6, // 轉換后的精度,即小數點位數       propList: ["*"], // 指定轉換的css屬性的單位,*代表全部css屬性的單位都進行轉換       viewportUnit: "vw", // 指定需要轉換成的視窗單位,默認vw       fontViewportUnit: "vw", // 指定字體需要轉換成的視窗單位,默認vw       selectorBlackList: ["wrap"], // 指定不轉換為視窗單位的類名,       minPixelValue: 1, // 默認值1,小於或等於1px則不進行轉換       mediaQuery: true, // 是否在媒體查詢的css代碼中也進行轉換,默認false       replace: true, // 是否轉換后直接更換屬性值       exclude: [/node_modules/], // 設置忽略文件,用正則做目錄名匹配       landscape: false // 是否處理橫屏情況     }   } }; 
  1. 重新運行項目,使配置文件生效
  2. 我們寫一段測試代碼來驗證一下:
<template>
  <div class="test-viewport">測試轉換</div> </template> <style lang="less" scoped> .test-viewport {   width: 750px;   height: 100px;   font-size: 40px;   text-align: center;   line-height: 100px;   background: #13b5b1; } </style> 
  1. 打開控制台,可以看到已經進行了轉換
image.pngimage.png

需要注意的配置

  • propList: 當有些屬性的單位我們不希望轉換的時候,可以添加在數組后面,並在前面加上!號,如propList: ["*","!letter-spacing"],這表示:所有css屬性的屬性的單位都進行轉化,除了letter-spacing
  • selectorBlackList:轉換的黑名單,在黑名單里面的我們可以寫入字符串,只要類名包含有這個字符串,就不會被匹配。比如selectorBlackList: ['wrap'],它表示形如wrap,my-wrap,wrapper這樣的類名的單位,都不會被轉換

關於兼容第三方UI庫

當然,當我們引入一些第三方庫的時候,比如vant,上面配置的exclude去掉,表示全部內容進行vw轉換,會遇到這樣的問題:

像這個TabBar,變得非常的小,被壓扁了。

其實vant官網也是給出了關於viewport的適配方案,在github找一個名為vant-demo的項目,可以看到其配置如下,github鏈接

很尷尬,vant團隊的是根據375px的設計稿去做的,理想視口寬度為375px。

那么,我們是否也要叫UI重新出一版375px的設計稿?

或者,我們在書寫的過程心算一下,所有標注的尺寸都除以2?

讓我們回到webpack本身,重新看一下這份.postcssrc.js文件,它除了暴露一個對象,也可以暴露一個函數,無論暴露什么,在webpack運行時,都會被我們配置的海量文件讀取並執行。

暴露函數有一個好處,可以拿到webpack運行的當前執行文件的信息。

那么我們可以有這樣一個思路:如果讀取的是vant相關的文件,viewportWidth就設為375,如果是其他的文件,我們就按照我們UI的寬度來設置viewportWidth,即750。

改寫.postcssrc.js文件配置如下:

const path = require('path'); module.exports = ({ webpack }) => {   const designWidth = webpack.resourcePath.includes(path.join('node_modules', 'vant')) ? 375 : 750;   return {     plugins: {       autoprefixer: {},       "postcss-px-to-viewport": {         unitToConvert: "px",         viewportWidth: designWidth,         unitPrecision: 6,         propList: ["*"],         viewportUnit: "vw",         fontViewportUnit: "vw",         selectorBlackList: [],         minPixelValue: 1,         mediaQuery: true,         exclude: [],         landscape: false       }     }   } } 
注意:這里使用path.join('node_modules', 'vant')是因為適應不同的操作系統, 在mac下結果為node_modules/vant,而在windows下結果為node_modules\vant 

另外,收到有同學反饋關於Cannot read property 'dirname' of undefined的問題,我本地由於是macOS系統,多次嘗試無法復現該問題,猜測有可能是平台問題或打包工具問題,換成了取用編譯的webpack對象中的resourcePath。

重新運行后發現,不僅vant相關組件的單位被轉換成了vw,而且其比例也是完全正確的。

github地址如下,可以下載到本地運行:

https://github.com/zhangnan24/mobile-px-demo

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM