设置微信字体大小引发的页面布局错乱问题

4,763 阅读5分钟

前序

作为公司的元老级人物,(前端实习一年半)练习生的我,就在昨天翻了车。我将做好的微信h5页面,打包部署好,信心满满的交付给了测试小哥,幻想着等待接收他赞赏的目光,结果却传来了噩耗。。。

测试小哥:你这页面布局怎么这么乱,这和设计图上的明显不符合嘛,水平不行吧。

理直气壮的我:what? 不可能,哥可是做过适配的,iPhone5都没问题,你刷新刷新。

测试小哥:没用。

渐渐卑微的我:不会吧,我来看看,我去,还真是,按道理不可能呀,我手机上好好的啊。

此处省略若干。。。

1. 问题原因

因为我们的页面是在微信webview打开的,经排查,得出,出现布局问题的手机,是因为用户调整了微信内的字体大小。

具体表现

我这里简单写了个demo,来还原当时的问题。

这是正常布局的页面,适配各种机型

'正常布局'

但是当用户设置字体大小不为默认大小后,页面的布局就乱掉了。

设置了字体大小后,文字掉了下来,布局错乱

2. 原因分析及解决方案

当我们设置了微信的字体大小不为标准后,在安卓和苹果上,微信对我们页面的行为是不同的。

1.安卓设备

在修改微信默认字体前,我们页面html元素的默认字体字号为16px,但当修改微信的字体大小后,同样的我们页面的html元素默认font-size也发生了变化,这是微信给重新设置了,只要你设置的微信字体越大,相应的页面的font-size也会变大。

那为什么默认的font-size变化了,会影响我这里的布局呢?

因为我用的rem做的适配,页面所有的字体大小,元素宽高度,都是基于rem单位写的,所以根元素的字体大小变化了,则rem所代表的值也就变化了。

之前的代码

  // 以iphone6宽度375px为基础尺寸时,html的字体大小为100px。其它设备宽度按比例计算
  function setRemUnit() {
    var rem = (docEl.clientWidth * 100) / 375
    docEl.style.fontSize = rem + 'px'
  }

这里虽然看上去我们给设置的html的font-size为100px,但随后,微信会给根元素重新按照一个比例设置一个新的值。

比如:

微信的文字大小为标准大小时,则页面根元素的font-size为16px

设置微信的文字变大,假如对应到根元素的font-size为24px

则增大比例为 24 / 16 = 1.5

回到我们的rem上

虽然我们的html元素的font-size设置为了100px,但随后,微信就会将其按照比例设为了 100 * 1.5 = 150px,这样我们基于rem单位设置的元素就都变大了。

关键奇葩的是,用docEl.style.fontSize取出来的值为100px,也就是我们设置的值,但是用getComputedStyle(docEl, false)['fontSize']取出来的值却为微信设置的150px, 而我们css代码所写的rem单位都是基于这个150px来算的。

解决方案

在我们根据设备宽度进行设置根元素的font-size前,先取出此时实际的font-size值,并除以默认的值16px,获得一个比例。

随后设置我们的rem时,除以这个比例,这样微信再重新设置font-size时,刚好就是我们想要的一个值了。

文字说的可能比较难懂,我列一个数学公式就够了。

默认的根元素font-size: 16px

修改微信字体后微信设置的根元素font-size:24px

rem适配公式(iphone6):(375 * 100 / 375) / (24 / 16) = 100 / 1.5

微信再做调整:rem * (25 / 16) = 100 / 1.5 * 1.5 = 100

就刚好是抵消掉变化了。

 const DEFAULT_FONT_SIZE = 16
 const docEl = document.documentElement
  let userWebsetFontDefaultSize = DEFAULT_FONT_SIZE
  // 用原生方法获取用户设置的浏览器的字体大小(兼容ie)
  if (docEl.currentStyle) {
    userWebsetFontDefaultSize = docEl.currentStyle['fontSize']
  } else {
    userWebsetFontDefaultSize = getComputedStyle(docEl, false)['fontSize']
  }
  // 取数字部分
  userWebsetFontDefaultSize = parseFloat(userWebsetFontDefaultSize)
  // 将实际的字号除以默认字号
  const sizeScale = userWebsetFontDefaultSize / DEFAULT_FONT_SIZE

  // 屏幕宽度375px时,html的字体大小为100px。其他宽度按比例计算
  function setRemUnit() {
    let width = docEl.clientWidth
    if (width > 750) {
      width = 750
    }
    // 满足等式width : size = 375 : 100
    const rem = (width * 100) / 375 / sizeScale
    docEl.style.fontSize = rem + 'px'
  }

2.苹果设备

苹果中微信的行为与安卓不同,在修改了微信的默认字体后,它不会改变我们的根元素的font-size大小,而是修改了一个text-size-adjust的css值。

该属性是用于移动设备下,使用文本溢出算法来放大文本的。点此处查看

默认情况下,该值是100%,修改微信字体后,该值也会做相应的改变。但相比于安卓,这个改动对我们的整体布局影响较小,主要的字体的大小。

解决方案

body  
    {  
        -webkit-text-size-adjust: 100% !important;  
        text-size-adjust: 100% !important;  
        -moz-text-size-adjust: 100% !important;  
    }  

总结

就一句话,坑就完了!!!

开个玩笑😆,以上的一些结论都是我基于真实页面表现得出来的,如果你知道更加专业的内容和更加具体的原因,欢迎评论与我交流。