移动端用户设置字体放大导致的问题
2017-10-30 09:46
891 查看
问题背景
很多webview提供了调整页面字体大小的功能,例如手机QQ、微信、部分Android内置浏览器等。大部分浏览器调整字体只会导致字体显示大小发生改变,其他元素的大小不受影响。但对于结构稍微复杂一点的页面,字体大小的变动就足以导致页面布局乱掉,导致文本不居中、文字折行、布局混乱等问题。调整字体大小功能24-mobile-browser-font-size/1.png)
作为前端工程师,碰到页面乱掉的情况就会觉得很无辜了,明明是你自己放大的字体,放大了却还要我来承担排版乱掉的后果,多委屈啊。很久以前,在PC端,好歹我们还可以提示用户按CTLR + 0将页面的比例调整回来,现在在移动端,却很难阻止用户缩放字体大小。
然而即使再委屈,当问题来了之后还是需要处理的,谁让我们是前端工程师呢?(笑)
原理
由于并不是很清楚各个平台(浏览器)放大字体的机制,我分别咨询了我们 iOS 和 Android 的同事,得知在调整字体大小时时,2个客户端的处理方式不同。iOS
iOS上需要调整 webview 的字体大小时,是通过给 body 设置-webkit-text-size-adjust属性实现的:
iOS设置字体缩放代码
既然这样,我们应该可以通过JS取到这个属性:
var body = document.body; alert(body.getAttribute('style'));
iOS获取样式
图上可以看到,当页面文字被放大时,确实多了一个
-webkit-text-size-adjust属性。
Android
Android通过给 webview 设置字体的缩放来完成,具体的API是setTextZoom(int)。
Android设置字体缩放代码
我们通过一个demo页面来查看效果:
Android设置字体缩放代码
从图中可以看到,文字确实是被放大了。例如“文字大小10px”这一段文字被放大了两倍,随文字一同被放大的还有以
em为单位的尺寸和
line-height。
于是很自然地想到,我们是否可以取到这些属性呢?
// 取元素的fontSize document.querySelector('.s10').style.fontSize;
结果很失望,取不到什么有用的信息。
按iOS的方式,也取不到任何有用的样式,可见Android webview中并不是使用
-webkit-text-size-adjust这个属性来放大文字的。
一筹莫展之际,忽然想到是否应该取一下
computedStyle?
window.getComputedStyle(document.querySelector('.fs10'),null).getPropertyValue('font-size')
这次终于有结果了,“文字大小10px”这一段文字明明白白地被使用了
20px的文字大小!
至此,我们可以大概推测出 Android webview 放大文字的原理:在CSS解析之后,渲染之前,将所有的字体大小的值进行缩放,后面的排版和渲染都会直接使用缩放后的CSS值。
解决方案
针对iOS,调整字体大小本身只是改变body的css属性,因此可以通过覆盖样式来控制。
body { -webkit-text-size-adjust: 100% !important; }
Android因为改变的是字体的大小,所以可以考虑将字体大小在设置的时候进行等比例缩小。例如,一个文字希望以
10px来进行渲染,当webview被放大两倍时,此时
font-size会变为
20px。因此我们可以在取到这个放大比例之后,对原样式进行等比缩小,比如将原文字大小设置为
5px,渲染的时候就变成了
10px。
var $dom = document.querySelector('.fs10'); var originFontSize = 10; var scaledFontSize = parseInt(window.getComputedStyle($dom, null).getPropertyValue('font-size')); var scaleFactor = originFontSize / scaledFontSize; $dom.style.fontSize = originFontSize * scaleFactor;
但是这样做仍然有几个问题:
一次只能操作一个DOM元素,无法批量处理
需要知道DOM元素原来设置的字体大小
这几个问题并不如想象中的好解决。于是另辟蹊径,看看是否有一劳永逸的办法。脑海中很快冒出一个名词——
rem!
如果我们的页面字体大小都使用
rem进行声明,那么我们就只需要在页面加载的时候根据缩放比例计算出
html元素的字体大小即可!详见下方代码:
(function(){ var $dom = document.createElement('div'); $dom.style = 'font-size:10px;'; document.body.appendChild($dom); // 计算出放大后的字体 var scaledFontSize = parseInt(window.getComputedStyle($dom, null).getPropertyValue('font-size')); document.body.removeChild($dom); // 计算原字体和放大后字体的比例 var scaleFactor = 10 / scaledFontSize; // 取html元素的字体大小 // 注意,这个大小也经过缩放了 // 所以下方计算的时候 *scaledFontSize是原来的html字体大小 // 再次 *scaledFontSize才是我们要设置的大小 var originRootFontSize = parseInt(window.getComputedStyle(document.documentElement, null).getPropertyValue('font-size')); document.documentElement.style.fontSize = originRootFontSize * scaleFactor * scaleFactor + 'px'; })();
因为这段代码中创建了一个元素,并放入了
document.body中,所以不能放在
head中运行。如果放在页尾运行的话,则有可能会产生闪烁的情况,因此最好的办法是将这段代码放在
<body>开始的地方。
除了在Android webview以外,以上代码在 Android 微信中实测也有效。
其它方案
Android微信
在编写本文时,通过网上一些资料,发现在Android微信中,也可以借助WeixinJSBridge对象来阻止字体大小调整。实测也有效。
(function() { if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") { handleFontSize(); } else { document.addEventListener("WeixinJSBridgeReady", handleFontSize, false); } function handleFontSize() { // 设置网页字体为默认大小 WeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize' : 0 }); // 重写设置网页字体大小的事件 WeixinJSBridge.on('menu:setfont', function() { WeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize' : 0 }); }); } })();
Android QQ
作为用户量庞大的APP之一,QQ也提供了禁止调整字体大小的方案,android qq中可以自定义webview显示的控件,通过在url中加入指定参数即可。见如何定制手Q的Webview.手机QQ文档
理论上,www.futu5.com/?_wv=128访问这个链接,功能菜单中不会出现调整字体大小的按钮。但是,但是,但是,在我实测过程中,所有的参数中,就只有【128隐藏字体项不生效】。不知道是QQ的bug还是有意为之,目前已提交反馈,但未收到回应。
声音和思考
在组内分享的时候,大家对于字体大小调整这个头疼的问题各自有不同的看法,大概有怎么几种声音:从产品的角度来说,微信、QQ等客户端既然提供调整字体的功能,必然是想用它来提供更好的体验,不应该禁用。
从开发的角度来说,字体缩放之后,页面会乱掉,根本原因在于页面的适应性不够,应该从代码层面去优化。
继续从开发的角度说,虽然理论上开发应该做好适配,但是对于文字突然被放大两倍,很多时候确实心有余而力不足。如果要做好,需要花费大量的时间和精力,并且需要设计和产品同学从设计上留出一些适配空间。
既然用户选择了用大字体来浏览页面,他就应该知道这个页面是被自己放大了,需要承担页面布局乱掉的结果。
一、用户修改手机字体设置大小,影响App里打开的web页面。
手机字体设置大小,影响App的页面。
Android的可以通过webview配置webview.getSettings().setTextZoom(100)就可以禁止缩放,按照百分百显示。
二、用户调整浏览器字体大小,影响的是从浏览器打开的web页
浏览器设置字体大小,影响浏览器打开的页面。通过js可控制用户修改字体大小,使页面不受影响。
(function(doc, win) { // 用原生方法获取用户设置的浏览器的字体大小(兼容ie) if(doc.documentElement.currentStyle) { var user_webset_font=doc.documentElement.currentStyle['fontSize']; } else { var user_webset_font=getComputedStyle(doc.documentElement,false)['fontSize']; } // 取整后与默认16px的比例系数 var xs=parseFloat(user_webset_font)/16; // 设置rem的js设置的字体大小 var view_jsset_font,result_font; var docEl = doc.documentElement, resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize', clientWidth, recalc = function() { clientWidth = docEl.clientWidth; if(!clientWidth) return; if(!doc.addEventListener) return; if(clientWidth<750){ // 设置rem的js设置的字体大小 view_jsset_font=100 * (clientWidth / 750); // 最终的字体大小为rem字体/系数 result_font=view_jsset_font/xs; // 设置根字体大小 docEl.style.fontSize = result_font + 'px'; } else{ docEl.style.fontSize = 100 + 'px'; } }; win.addEventListener(resizeEvt, recalc, false); doc.addEventListener('DOMContentLoaded', recalc, false); })(document, window);
相关文章推荐
- 关于网上解决Android4.x系统设置字体大小导致应用布局混乱引起的问题
- 移动端字体放大导致布局错乱的解决方案
- win7安装SQL Server2008时,用户权限设置问题导致安装失败
- selinux 的设置导致vsftp权限问题(linux的ftp用户无法连接问题)
- 解决windows系统字体设置为125大小导致程序界面位置不一致的问题
- win7安装SQL Server2008时,用户权限设置问题导致安装失败
- android系统设置里的字体大小导致的布局混乱问题
- win7安装SQL Server2008时,用户权限设置问题导致安装失败
- 解决手机浏览器上input 输入框导致页面放大的问题(记录)
- Ubuntu8.04中字体设置的问题(最终版)
- 数据库设置缺陷导致的MySQL查询不准确问题
- 路由器设置SS连接PS4的游戏用户常见问题
- 解决ACTIVITI流程图设置字体不生效的问题
- SQLServer 数据库变成单个用户后无法访问问题的解决方法[在手动还原该数据库的时候,设置为单用户模式,然后其他用户访问的时候就。。。。]
- cookie——没有设置时间期限导致的问题
- MySQL的用户权限设置问题(如何解决Access denied)
- ArcGIS Server 用户权限设置问题(转)
- 解决因为手机设置字体大小导致h5页面在webview中变形的BUG
- 关于FF 设置字体为font-weight:blod;时 字体显示过粗的问题
- popupWindow+软键盘弹出,edittext设置,textview字体颜色设置,log打印过长显示不出来的问题