针对移动端的适配方案目前大部分都是使用淘宝的 flexible
通过动态的根节点 font-size 和 rem 单位来做适配,不过是通过dpr 做了缩放,而实际上缩放并不和适配方案有关系,只是可以解决多倍屏下的0.5px像素问题,所以我们自己在移动端是去掉了根据dpr做缩放方案。
在面试的时候聊到移动端适配就会问下为什么要缩放,然后最近被人告知淘宝的方案没有缩放了,发现升级了,所以今天就整理下下移动端的适配方案;
如下所有的页面宽度都指:页面css宽度
淘宝旧的缩放实现方案:
代码大致如下三个步骤:
- 根据配置或者默认方法获取当前的
dpr
和 缩放比例scale
- 然后设置页面的meta viewport做好页面缩放,写入
html
data-dpr
属性 - 根据页面的
css像素宽度
/10
*dpr
得到跟节点fontSize
的值。(不过这里在一些奇葩的webview内导致设置的fontSize和计算出来的不一样,导致页面不能刚好全屏,可以通过下面的解决方案兼容)
实现思想大致如下:
- 页面按十个等分,
1rem
=1/10 * 页面宽度
,所以保证了无论什么设备10rem
都刚好是屏幕的宽度;- 约定设计稿为750px = 屏幕的宽度10rem,开发过程通过工具转换px为rem,理解这两点也就知道了整个是怎么回事。例如ui稿宽度 375px,实际代码就是 (375px/750px) * 10rem
width:5rem
,当屏幕宽度350px的设备时5rem
表示的实际px为 (350px / 10) * 5 =175px
- 页面访问时根据设备的dpr 做动态缩放,比如iphone xxx dpr 为3,页面viewport设置缩放为0.3333,同时在根节点写入 data-dpr=”3″,根节点的fontSize = 页面宽度 * 3,实际就是把页面放大3倍,再根据viewport 缩放回来。
这样做个人理解在那个年代可以比较轻易的解决 ios 0.5px 问题,但实际安卓是不做缩放,因为安卓兼容性问题庞大,有大量安卓 4.4.4 以上的手机被优化到无法支持viewport ,以及安卓本生的dpr太奇葩,比如2.5 3.5 等无法完全枚举,所以也就导致了fontsize是无法通过 px 做安卓适配的;
- 然后暴露了几个api (rem2px px2rem refreshRem ….)
- 再暴露设置viewport可以通过直接写死meta viewport 标签,不设置会获取当前设备的dpr动态处理;
淘宝新的实现方案:
直接根据 页面宽度/10 得到根节点的 fontSize 值,当dpr>= 2 的时候检测网站是否支持0.5px,如果是就直接在根节点html加上 class hairlines;
页面元素适配:
这里所有的图片宽高 元素宽度都推荐使用 rem ,可以根据屏幕的大小做自动适配;
字体大小适配:
字体不推荐使用 rem
方案,如果直接采用 rem
的方案那完全通过屏幕大小拉大或者变小,会导致部分设备字体过大或者过小。
一般使用 data-dpr
来设置2倍或者3倍的 fontSize
这样做可以保证字体不会跟着屏幕的大小改变,新的版本直接去掉dpr的判断,如果需要适配的跨度比较大或者其它要求可以根据 css media
查询来做特殊处理
相关问题
VM的实现方案 ?
这里类似rem,屏幕的宽度 100vw 类比 rem 方案为 10rem,其它都是类似,一样需要通过一个相对单位来实现。为何要设置body的fontSize:
这里官方说法会导致产生一些font的怪异渲染,遇到过的情况下面那种场景的会比较多;webview 设置的fontSize和实际获取的不相同:
1
2
3
4
5
6
7
8
9
10
11
12
13
14let width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
let rem = width / 10;
docEl.style.fontSize = `${rem}px`;
// 添加 校验fontSize是否偏差
const compFontSize = parseFloat(getComputedStyle(docEl).fontSize);
if (!isNaN(compFontSize)) {
if (compFontSize !== rem)
rem = rem * (rem / compFontSize);
docEl.style.fontSize = `${rem}px`;
}
其它备注
文章是很久前更新在公司的前端团队博客,现在转移到自己的个人博客上来,最近开始每周更新,对自己遇到的或者感兴趣的内容做记录,养成习惯保持下去。