背景
部分使用了REM方式来实现自适应的前端页面,随安卓系统字体放大会出现素材和布局跟随变化问题
应用层解决方式 解决方案:
原先获取根字体方案:
const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize)
更改为如下实现:(根据实际1rem单位元素的宽度作为基准fontsize)
var h = document.getElementsByTagName('head')[0],
d = document.createElement('div')
d.style.width = '1rem'
d.style.display = 'none'
h.appendChild(d)
const rootFontSize = parseFloat(getComputedStyle(d, null).getPropertyValue('width'))
根本原因简述 为什么第二种没有问题呢?根据以往的知识1rem等于根节点的fontsize值 两段代码应该一个意思。为什么两个表现不一样了?调试了下真实webview效果如下图
调整字体大小后根节点fontsize1rem的值和自己创建一个元素宽度给1rem的值不一样!
顺着这个逻辑我们需要去探究两个知识点1、rem的定义2、安卓webview如何实现字体大小调整
一、rem的定义 我们看下w3c中rem的定义
rem unit Equal to the computed value of font-size on the root element. If used in the font-size property of the root element, or in a document with no root element, 1rem is equal to the initial value of the font-size property.
等于根元素上 font-size的计算值。 如果在根元素的font-size属性中使用,或者在没有根元素的文档中使用,则 1rem等于font-size属性的初始值。
二、安卓webview如何实现字体大小调整 安卓同事会借助 setTextZoom这个API实现webview字体大小变化. 调用setTextZoom发生了什么? 长话短说,我们从setTextZoom的java代码定位到chromium内核源码,发现了安卓webview特有的一段
void AwRenderFrameExt::SetTextZoomFactor(float zoom_factor) {
// TODO(crbug.com/1085428): This will need to be set on every local root
// when site isolation is used in android webview.
DCHECK(render_frame()->IsMainFrame());
blink::WebView* webview = GetWebView();
if (!webview)
return;
// Hide selection and autofill popups.
webview->CancelPagePopup();
render_frame()->GetWebFrame()->FrameWidget()->SetTextZoomFactor(zoom_factor);
}
没有详细探究C代码 这边的变大逻辑看变量名应该是在渲染时执行的。 我们看到这个代码里面还有段注释标明这个地方还有bug // TODO(crbug.com/1085428): This will need to be set on every local root 有兴趣的可以看下 再结合源码中的一段注释
// Sets the zoom factor for text only. Used in layout modes other than
// Text Autosizing.
SetTextZoomFactor(float zoom_factor);
结合如上信息我们推断在安卓webview中1rem最先的取值是根节点fontsize初始值。 之后由于安卓webview中setTextZoom特殊逻辑会对文本节点的fontsize做调整,表面上fontsize属性值还是1rem,其实已经经过再次计算。 而rem来做自适应我们是需要初始固定的的rem对应的值来进行一系列计算。并没有考虑到系统大小字体变化的倍数所以会有问题。 我们原先需要一个标准尺度,但是尺度在变化,所以出现问题。 也可以发现关于rem的标准定义在安卓webview中调用setTextZoom的情况下并没有遵循。