前序
作为公司的元老级人物,(前端实习一年半)练习生的我,就在昨天翻了车。我将做好的微信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;
}
总结
就一句话,坑就完了!!!
开个玩笑😆,以上的一些结论都是我基于真实页面表现得出来的,如果你知道更加专业的内容和更加具体的原因,欢迎评论与我交流。