比较好用的移动端适配的两种方案及flexible和px2rem-loader在webpack下的配置
***********转载请注明来源***********
移动端适配,目前自己常用的两种 方案,参考以下两篇好文
方案一:使用lib-flexible包
https://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.html
使用flexible包方式,安装 lib-flexible 包和 px2rem-loader包
npm install --save-dev lib-flexible px2rem-loader
在需要的js文件中头部引入,如果是vue项目就引入到main.js中:
import 'lib-flexible'
webpack配置loader,注意顺序很重要,顺序不对会出错
{ test: /\.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', {loader: 'px2rem-loader', options: { remUni: 75, remPrecision: 8, }}, {loader: 'postcss-loader', options: {plugins: [require("autoprefixer")("last 100 versions")]}} ] }, { test: /\.less$/, use: [ MiniCssExtractPlugin.loader, 'css-loader?importLoaders=1', {loader: 'px2rem-loader', options: { remUni: 75, remPrecision: 8, }}, {loader: 'postcss-loader', options: {plugins: [require("autoprefixer")("last 100 versions")]}}, 'less-loader', ] },
这里有个问题,在安卓下flexible.js源码是全部按dpr=1来适配的,那自然是不行的,我们修改一下源码,改为按devicePixelRatio显示
if (isIPhone) { // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案 if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { dpr = 3; } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; } } else { // 其他设备下,仍旧使用1倍的方案 dpr = devicePixelRatio; //这里将原来=1改为devicePixelRatio }
然后写针对不同dpr下字体大小的视频,这里用less实现:
.font-dpr(@font-size) { font-size: @font-size; [data-dpr="1"] & { font-size: @font-size; } [data-dpr="2"] & { font-size: @font-size * 2; } // for mx3 [data-dpr="2.5"] & { font-size: @font-size * 2; } //for 小米note,for 小米mix [data-dpr="2.75"] & { font-size: @font-size * 2.2; } [data-dpr="3"] & { font-size: @font-size * 2.2; } // for 三星note4 ,三星s6 [data-dpr="4"] & { font-size: @font-size * 2; } }
使用的时候直接.font-dpr(20) 这样婶儿就可以了。
方案二:使用less或者sass等CSS 预处理语言写适配方案
https://juejin.im/post/5caaa230e51d452b672f9703#heading-7
基准按照设计图尺寸,但是缺点是不通用,不同页面可能设计图基准尺寸不同,导致在页面自己的less文件中重置基准值也不生效,这里想到了一个兼容的办法,就是在本页面的less中将传入宽度或字体的数字进行换算。
这里贴出我的mixin.less
// rem 单位换算:定为 75px 只是方便运算,750px-75px、640-64px、1080px-108px,如此类推 @baseSize: 37.5; // 默认根元素大小基准值375,即设计图尺寸为宽375px,不同页面设计图尺寸不同,在页面css头部重新初始化并重新定义html根元素的font-size @baseDesign: 375; .font-size(@px) { font-size: (@px/@baseSize/2)*1rem; } .margin(@px) { margin: (@px/@baseSize/2)*1rem; } .margin-all(@a,@b,@c,@d) { margin: (@a/@baseSize/2)*1rem (@b/@baseSize/2)*1rem (@c/@baseSize/2)*1rem (@d/@baseSize/2)*1rem; } .padding(@px) { padding: (@px/@baseSize/2)*1rem; } .padding-all(@a,@b,@c,@d) { padding: (@a/@baseSize/2)*1rem (@b/@baseSize/2)*1rem (@c/@baseSize/2)*1rem (@d/@baseSize/2)*1rem; } .width(@px) { width: (@px/@baseSize/2)*1rem; } .height(@px) { height: (@px/@baseSize/2)*1rem; } .min-width(@px) { min-width: (@px/@baseSize/2)*1rem; } .max-width(@px) { max-width: (@px/@baseSize/2)*1rem; } .line-height(@px) { line-height: (@px/@baseSize/2)*1rem; } .margin-right(@px) { margin-right: (@px/@baseSize/2)*1rem; } .padding-right(@px) { padding-right: (@px/@baseSize/2)*1rem; } .margin-left(@px) { margin-left: (@px/@baseSize/2)*1rem; } .padding-left(@px) { padding-left: (@px/@baseSize/2)*1rem; } .margin-top(@px) { //margin: @px /(@baseDesign/2) * 100vw; margin-top: (@px/@baseSize/2)*1rem; } .padding-top(@px) { padding-top: (@px/@baseSize/2)*1rem; } .margin-bottom(@px) { margin-bottom: (@px/@baseSize/2)*1rem; } .padding-bottom(@px) { padding-bottom: (@px/@baseSize/2)*1rem; } .border(@px,@color) { position: relative; &::before{ content: ""; position: absolute; left: 0; top: 0; width: 200%; border:1px solid @color; color: @color; height: 200%; -webkit-transform-origin: left top; transform-origin: left top; -webkit-transform: scale(0.5); transform: scale(0.5); pointer-events: none; /* 防止点击触发 */ box-sizing: border-box; @media screen and (min-device-pixel-ratio:3),(-webkit-min-device-pixel-ratio:3){ width: 300%; height: 300%; -webkit-transform: scale(0.33); transform: scale(0.33); } } } .border-radius(@px) { border-radius: (@px/@baseSize/2)*1rem; } .border-width(@a,@b,@c,@d) { border-width: (@a/@baseSize/2)*1rem (@b/@baseSize/2)*1rem (@c/@baseSize/2)*1rem (@d/@baseSize/2)*1rem; } .top(@px){ top: (@px/@baseSize/2)*1rem; } .left(@px){ left: (@px/@baseSize/2)*1rem; } .right(@px){ right: (@px/@baseSize/2)*1rem; } .bottom(@px){ bottom: (@px/@baseSize/2)*1rem; } @imgPath: "../../assets/images/"; // 根元素大小使用 vw 单位 html { font-size: (@baseSize/(@baseDesign / 2)) * 100vw; @media screen and (orientation: landscape) { font-size: (@baseSize/(@baseDesign / 2)) * 100vh; } // 同时,通过Media Queries 限制根元素最大最小值 @media screen and (max-width: 320px) { font-size: 64px; } //横屏下ipad等平板font-size最大限制 /* @media screen and (min-width: 813px) { font-size: 108px; }*/ }
如果使用该mixin的页面设计图宽度为其他尺寸,比如320,则进行换算:
@base: 320; @convert: 375/@base; .info{ .width(56*@convert); .height(30*@convert); }
这样进行转换之后可以保证页面中显示的尺寸是完全跟图片中的尺寸一致。
如果设计图页面是一个banner类型,这样相当于是页面横屏,且高度很低,建议重置mixin中的html根元素字体设置,由vh改为vw,形如:
html{ width:100vw; height:100vh; @media screen and (orientation: landscape) { font-size: (@baseSize/(@baseDesign / 2)) * 100vw; } }