移动端适配问题

针对移动端的适配方案目前大部分都是使用淘宝的 flexible
通过动态的根节点 font-sizerem 单位来做适配,不过是通过dpr 做了缩放,而实际上缩放并不和适配方案有关系,只是可以解决多倍屏下的0.5px像素问题,所以我们自己在移动端是去掉了根据dpr做缩放方案。
在面试的时候聊到移动端适配就会问下为什么要缩放,然后最近被人告知淘宝的方案没有缩放了,发现升级了,所以今天就整理下下移动端的适配方案;

如下所有的页面宽度都指:页面css宽度

淘宝旧的缩放实现方案:

代码大致如下三个步骤:

  1. 根据配置或者默认方法获取当前的 dpr 和 缩放比例 scale
  2. 然后设置页面的meta viewport做好页面缩放,写入 html data-dpr 属性
  3. 根据页面的 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 查询来做特殊处理

相关问题

  1. VM的实现方案 ?
    这里类似rem,屏幕的宽度 100vw 类比 rem 方案为 10rem,其它都是类似,一样需要通过一个相对单位来实现。

  2. 为何要设置body的fontSize:
    这里官方说法会导致产生一些font的怪异渲染,遇到过的情况下面那种场景的会比较多;

  3. 字体忽然变大:
    https://www.cnblogs.com/axl234/p/5895347.html;

  4. webview 设置的fontSize和实际获取的不相同:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    let 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`;
    }

其它备注

文章是很久前更新在公司的前端团队博客,现在转移到自己的个人博客上来,最近开始每周更新,对自己遇到的或者感兴趣的内容做记录,养成习惯保持下去。