内容简介:本来团队是搞PC端开发的,前段时间架构调整,内端人力不足,所以团队把移动端的工作也一起接过来了。不过由于我们团队以前没开发过移动端的东西,技术积累较少,因此花费了不少时间在基础技术积累上面。这次介绍一下我们的移动端适配方案的改进过程。
本来团队是搞PC端开发的,前段时间架构调整,内端人力不足,所以团队把移动端的工作也一起接过来了。
不过由于我们团队以前没开发过移动端的东西,技术积累较少,因此花费了不少时间在基础技术积累上面。
这次介绍一下我们的移动端适配方案的改进过程。
hotcss库
最开始进行移动端开发时,由于工期比较紧张,为了快速构建整个项目,我最后选择使用了 hotcss 这个库。 这个库的优点其实挺多的:
- 使用方便
- 支持不同的设计稿尺寸
- 支持在js代码中换算适配后的像素
- 有效解决1px问题
最开始选用这个库的原因其实也是因为使用方便,当初经过测试之后发现可以比较好的还原设计稿的尺寸后,我们就选择使用这个方案了。
不过由于担心cdn访问延迟和dns解析能问题导致 hotcss.js
资源加载失败,再加上本身源码也不长,我们直接将源码压缩后内联进模板里面。
不过使用一段时间之后,发现hotcss方案确实也有不少的坑。
1px问题
官方号称完美解决1px的问题,但是经过我们QA同学的真机测试,发现在安卓4dpi=1的情况下, 1px
的 border
经过 px2rem
的转换后,还是会有问题,所以我们为了兼容1dpi的手机,不得不专门写了一个 border
的兼容方案(其他css样式同理):
@mixin border-bottom($width: 1) { border-bottom: px2rem($width) solid map-get($defaultColor, borderColor); [data-dpr='1'] & { border-bottom-width: $width + 'px'; } } 复制代码
设计稿尺寸问题
其实这个问题并不是hotcss库本身的问题,应该让UI同学出设计稿的时候,给前端同学一套统一的尺寸。
但是我们最开始的UI同学由于个人习惯问题,有的给我们的是iOS尺寸的设计稿,这种的尺寸是375px的,有的是安卓尺寸的设计稿360px的。而 hotcss
这个库需要提前声明 $designWidth
这个变量,之后使用 px2rem()
方法的时候才会进行替换,由于css没有作用域的概念,当碰到单页应用的时候两种尺寸的设计稿就会出现问题。
不过好在我们目前的移动端页面大部分都不是单页应用,少数几个单页应用也是同一尺寸的设计稿。但是这个问题总归是一个隐患。
因此我们后续和UI团队沟通,以后出统一的设计稿尺寸。
书写繁琐
说实话虽然使用起来很方便,只需要引入一个官方的sdk就完成了移动端适配方案。但是当写起业务css代码的时候,还是感觉hotcss使用起来很繁琐。
当UI稿中的尺寸是这样的时候:
font-size: 16px; font-height: 20px; height: 50px; width: 200px; 复制代码
我们就不能直接copy过来了,需要对其进行单位转换:
// 这一块代码可以放到common.scss中 @function px2rem($px) { @return $px * 320 / $designWidth/20 + rem; } $designWidth: 360; font-size: px2rem(16); font-height: px2rem(20); height: px2rem(50); width: px2rem(200); 复制代码
总之当业务稳定之后,我们慢慢才发现用这个方案还是非常麻烦的,就经常被同事吐槽。
基于以上种种原因,我们团队在升级打包工具webpack->razzle的过程中,改进了适配方案,采用了 hotcss
+ postcss-pxtorem
结合的方案。
hotcss配合postcss-pxtorem
postcss-pxtorem
这个 工具 库的使用介绍网上也到处都有,这个库的优点在于有很强的转换规则,可以适配各种场景。我们在这里使用这个插件是为了自动进行px->rem的转化,其他过程还是由 hotcss
来进行。
postcss-px2rem的一些参数
require('postcss-pxtorem')({ rootValue: 75, unitPrecision: 5, propList: ['*'], selectorBlackList: [], replace: true, mediaQuery: false, minPixelValue: 12 }) 复制代码
-
rootValue
是根标签的font-size
大小 -
unitPrecision
是转换成rem后的小数位数 -
propList
是需要转换的属性列表 -
selectorBlackList
则是一个对css选择器进行过滤的数组,比如你设置为['fs'],那例如fs-xl类名,里面有关px的样式将不被转换,这里也支持正则写法。 -
minPixelValue
可以设置小于多少尺寸将不会进行转换。
刚好 minPixelValue
这个属性设置为 1px
的时候,就解决了之前 hotcss
的1px的问题。
postcss.cofnig.js
const PostCssFlexBugFixes = require('postcss-flexbugs-fixes'); const autoprefixer = require('autoprefixer'); const px2rem = require('postcss-pxtorem'); const path = require('path'); const designWidth = 360; // 统一的视觉稿尺寸 const rootValue = (designWidth * 20) / 320; // root FontSize module.exports = ctx => { const remInclude = [ /\.rem\.less$/, /\.rem\.scss$/, ]; // 白名单,命中白名单则进行px2rem转换,包括.rem.less、.rem.scss结尾的文件 const useRem = remInclude.some(x => x.test(path.join(ctx.file.dirname, ctx.file.basename)) ); return { plugins: [ PostCssFlexBugFixes, //修复某些浏览器的flex bug autoprefixer({ // autprefixer browsers: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9'], flexbox: 'no-2009' }), useRem && px2rem({ rootValue, propList: ['*'], minPixelValue: 1 }) ].filter(Boolean) }; }; 复制代码
postcss-pxtorem
完成对 rem
的转换,加上之前 hotcss
对 font-size
值的计算以及对 viewport
的初始化,我们最终完成了移动端的适配方案。
其中设置白名单列表是为了兼容以前老版本使用 hotcss
时候的写法,在升级razzle完毕之后我们后续的样式全部统一使用 .rem.scss
作为文件名后缀了,这样在样式文件中正常写px单位即可, postcss
会自动为我们进行转换。
hotcss缩放scale的坑
最近使用一些第三方插件(如 echarts
和视频播放器等)的时候,发现 hotcss
根据dpi给页面设置的 meta[viewport]
和插件之间会有坑。
<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5, user-scalable=no">
由于第三方插件一般读取过一次页面的scale之后,后续scale的修改不会影响这些样式。
而 hotcss
会重新根据dpi重新设置scale,这种情况下当css加载得比js慢的时候,就会导致页面样式会闪烁,并且第三方插件的样式都是根据最开始的scale进行布局的,因此在页面放大之后会显得很小。
不过这种情况一般在本地开发的时候才会出现,线上模式静态资源一般放入cdn,访问速度很快,在css加载速度快于js的时候就不会出现这个问题了。
不过为了在本地开发的时候方便观测样式,我们需要在客户端执行js的时候重新将 font-size
设置回1.0。
document.documentElement.style.fontSize = `${(window.innerWidth * 20) / 320 / window.devicePixelRatio}px`; let viewportEl = document.querySelector('meta[name="viewport"]'); const content = `width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no`; if (viewportEl) { viewportEl.setAttribute('content', content); } else { viewportEl = document.createElement('meta'); viewportEl.setAttribute('name', 'viewport'); viewportEl.setAttribute('content', content); document.head.appendChild(viewportEl); } 复制代码
这样整个页面上的第三方插件在本地调试的时候也是正常大小了~
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- rem 适配布局
- 模仿微信适配 iPad 的布局方式
- flutter 屏幕尺寸适配 字体大小适配
- 前端适配:移动端/web端适配方案
- iOS 关于全面屏适配的方案及UI在不同尺寸下适配方案
- iOS 关于全面屏适配的方案及UI在不同尺寸下适配方案
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Viral Loop
Adam L. Penenberg / Tantor Media / 2009-10-27 / USD 34.99
From Google to Facebook, a respected journalist delves into how a "viral loop" can make an online business a success.一起来看看 《Viral Loop》 这本书的介绍吧!