本文主要聊了下 PxToViewport 插件、rem、vw、transform、viewpoint、computedFontSize,来解决手动计算、字体小于 12px、安卓放大字体后页面效果可能会异常、移动端适配等前端样式问题。
存在的问题
我们在前端进行样式布局的时候,经常会遇到以下几个问题:
- 视觉稿和最终的页面单位不一致,可能需要手动计算
- px 到 rem 或 vw 的手动转化
- 字体小于 12px 会直接转化为 12px
- 安卓放大字体后页面效果可能会异常
- vw 存在 pc 端兼容样式问题
- 移动端样式兼容
解决手动计算
有多种方案,比如给 IDE 装个自动转化的插件,这样就可以让 IDE 来计算了,我用的比较多的是 webpack 插件的方案:
PxToViewport 插件
该插件可以把项目里的 px 单位全部按照自己的配置转化为 rem 或者 vw。
该插件也可以过滤某些类、某些属性,或者小尺寸单位。
一般 mediaQuery 设为 true 的原因是,有一些样式写在了判断 iPhone X 的 media 逻辑里。
如果需要 font-size 保持 px 不变可以修改该配置:propList: [‘*’, ‘!font-size’]。
转为 rem
原理
rem 方案的原理就是给根元素设置一个 font-size,其他元素的大小都相对于根元素。
也就是说,我只要通过改变根元素的 font-size,就可以控制所有元素的单位。
优点
这样做的好处是,可以兼容 PC 端的场景,在超出 600px 宽度时给根元素设置一个固定 font-size,就可以视作最大宽度 600px 处理。
根元素 font-size 确定
一般是将根元素的宽度,设为 1/10 页面宽度,即在 375px 的标准下为 37.5 px。
设置为 1/10 页面宽度而不是 1/100 的原因,是为了避免根元素的 font-size 小于 12px。
如果设为 1/100,在 375px 标准下大小就是 3.75px,在某些场景下小于 12px 会按照 12px 计算,可能会出问题。
具体实现
本文的方案是,根元素在手机端的 font-size 设为 10vw,在 PC 端的 font-size 设为 60px。
这样既能兼容手机端不同尺寸的样式,又能保证在 PC 端稳定的展示。
PxToViewport 设置的时候,画布的尺寸为 3750。
最后布局的时候按照 375px 的视觉稿尺寸即可。
转为 vw
vw 好处是直观,而且不需要再给根元素设置 font-size 了,误差也比 rem 要小。
缺点就是没法兼容 PC 端样式,但十分适合离线包之类只在手机端使用的方案。
解决字体小于 12px
产生问题的原因
部分浏览器为了提升用户体验,将小于 12px 的字体都作 12px 来展示。
这样有时候在手机端这类小屏幕的场景下,可能不得不用小字号来展示,字体就会小于 12px。
这个问题一般有两种解决方案:
1. transform
将字体设为 12px 同时通过 transform 来缩放调整字体的字号,这个能实现效果,而且兼容性良好。
但是问题是,这块字体实际占据的空间还是按照 12px 来算的,一方面是要用 transform-origin 来调整位置,另一方面字体溢出的处理也有点过于宽敞。
2. viewpoint
viewpoint 方案的首要问题是只能在手机端使用,pc 不行,但是大体上 pc 展示也还比较良好。
实现原理是 view 设置成根据实际 dpr 进行缩放,这样比如 0.5,就是放大两倍,12px 就可以来展示 6px 以上尺寸的字体了。
这个同时还能解决 1px border 的问题。
该方案比较愁人的问题,就是调试的时候也要按照放大的比例设置尺寸。
PC 端的 viewpoint 属性不能生效,所以 PC 端仍然会出现 12px 的字体问题。如果要开发需要适用于 PC 端且需要解决小于 12px 字体问题的页面(比如挂件),需要自行设置使用 transform 属性对页面进行缩放解决
解决安卓放大字体后页面效果可能会异常
这个可以通过手动计算 computedFontSize 来设置解决。
移动端样式兼容
适配不同端
- 屏幕宽度小于 600px,则认为是移动端, root 元素 font-size: 10vw, viewport 根据 dpr 进行缩放(移动端)
- 屏幕宽度大于 600px, root 元素 font-size: 60px, viewport 缩放等级为 1 (web 端)
尺寸编写
- 用 PxToViewport + rem + viewpoint 的最终方案后
- 本质上,所有元素转换成 /37.5rem,对于 1px 的 border 直接使用 1px 即可
- 字体也使用 /37.5rem 进行转换,这时候无需考虑 12px 限制(如 8px 字体直接用类名 .f-fs8 或写 font-size: 8px 即可)
离线包处理
对于离线包,由于不会出现大于 600px 的情况,都按照 root 元素 font-size: 10vw, viewport 根据 dpr 进行缩放。
由于离线包页面会出现视觉稿小于 375px 的情况(比如某些弹窗),可以在 index.html 中修改 fontNum。如果视觉稿中弹窗宽度为 300, 则 var fontNum = 8; // fontNum = 300 / 375 * 10