# 了解真实的『REM』手机屏幕适配
2016-11-29 06:08
381 查看
rem作为一个低调的长度单位,由于手机端网页的兴起,在屏幕适配中得到重用。使用
rem前端开发者可以很方便的在各种屏幕尺寸下,通过
等比缩放的方式达到设计图要求的效果。
rem的官方定义『The font size of the root element.』,即以根节点的字体大小作为基准值进行长度计算。一般认为网页中的根节点是
html元素,所以采用的方式也是通过设置
html元素的
font-size来做屏幕适配,但实际情况真有这么简单吗?
首先我们来看看使用
rem实现手机屏幕适配的常用方案。
以设计稿的宽度为
640px,即:
designWidth = 640,同时设定在640px屏宽下
1rem=100px,即:
rem2px = 100。
设置
1rem=100px的优点不言而喻。前端开发者在切图、重构页面的时候,通过直接位移小数点的方式,就可以将UI图中测量到的
px值换算成对应的
rem值,方便快捷。
此外,在
head中我们还设置了:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
viewport的作用很重要,但不是本文的重点所以不展开,有兴趣的同学可以自行搜索。
先来看看具体方案:
下面四个方案来自同事共享,原理都是采用等比缩放的方式 —— 获得目标屏幕宽度和设计稿宽度的比,作为
rem的基值(缩放系数),设置为
html标签的字体大小。不同的只是在于性能取舍和书写习惯。
方案1
@media screen and (min-width: 320px) {html{font-size:50px;}} @media screen and (min-width: 360px) {html{font-size:56.25px;}} @media screen and (min-width: 375px) {html{font-size:58.59375px;}} @media screen and (min-width: 400px) {html{font-size:62.5px;}} @media screen and (min-width: 414px) {html{font-size:64.6875px;}} @media screen and (min-width: 440px) {html{font-size:68.75px;}} @media screen and (min-width: 480px) {html{font-size:75px;}} @media screen and (min-width: 520px) {html{font-size:81.25px;}} @media screen and (min-width: 560px) {html{font-size:87.5px;}} @media screen and (min-width: 600px) {html{font-size:93.75px;}} @media screen and (min-width: 640px) {html{font-size:100px;}} @media screen and (min-width: 680px) {html{font-size:106.25px;}} @media screen and (min-width: 720px) {html{font-size:112.5px;}} @media screen and (min-width: 760px) {html{font-size:118.75px;}} @media screen and (min-width: 800px) {html{font-size:125px;}} @media screen and (min-width: 960px) {html{font-size:150px;}}
方案2
@media screen and (min-width: 320px) {html{font-size:312.5%;}} @media screen and (min-width: 360px) {html{font-size:351.5625%;}} @media screen and (min-width: 375px) {html{font-size:366.211%;}} @media screen and (min-width: 400px) {html{font-size:390.625%;}} @media screen and (min-width: 414px) {html{font-size:404.2969%;}} @media screen and (min-width: 440px) {html{font-size:429.6875%;}} @media screen and (min-width: 480px) {html{font-size:468.75%;}} @media screen and (min-width: 520px) {html{font-size:507.8125%;}} @media screen and (min-width: 560px) {html{font-size:546.875%;}} @media screen and (min-width: 600px) {html{font-size:585.9375%;}} @media screen and (min-width: 640px) {html{font-size:625%;}} @media screen and (min-width: 680px) {html{font-size:664.0625%;}} @media screen and (min-width: 720px) {html{font-size:703.125%;}} @media screen and (min-width: 760px) {html{font-size:742.1875%;}} @media screen and (min-width: 800px) {html{font-size:781.25%;}} @media screen and (min-width: 960px) {html{font-size:937.5%;}}
方案3
var designWidth = 640, rem2px = 100; document.documentElement.style.fontSize = ((window.innerWidth / designWidth) * rem2px) + 'px';
方案4
var designWidth = 640, rem2px = 100; document.documentElement.style.fontSize = ((((window.innerWidth / designWidth) * rem2px) / 16) * 100) + '%';
为了更避免理解上的混乱,我在上面js的代码中加了
(
),实际代码中是不需要的。
详细分析一下,
rem和
px直接的转换公式可以写为:
1rem = 1 * htmlFontSize
htmlFontSize为
html元素的字体大小。
首先来看方案1中,在屏宽为
640px情况下的设置:
@media screen and (min-width: 640px) {html{font-size:100px;}}
可以很明显的表现出这一点
1rem = 1 * 100px,同我们最初的设定。那么我们要得到其它屏幕大小的
htmlFontSize值要怎么办。很简单如方案3,因为我们的采用等比缩放的方式适配,所以计算目标屏幕宽度和设计稿的宽度的比即可:
window.innerWidth / designWidth * rem2px + 'px'
由于浏览器默认字体大小为
16px,所以当我们使用百分比作为根节点
html的字体大小时,即
html元素的
font-size值设置为一个百分比值,
rem的计算方式就会改为:
defaultFontSize = 16px 1rem = 1 * htmlFontSize * defaultFontSize
如方案2中,在屏宽为
640px情况下的设置:
@media screen and (min-width: 640px) {html{font-size:625%;}}
应用上面的公式:
1rem = 1 * 625% * 16px 其中:625% * 16 = 6.25 * 16 = 100 所以:1rem = 1 * 100px
同样的可以得到所有屏幕大小下,
html的
font-size值的计算公式,即为方案4:
window.innerWidth / designWidth * rem2px / 16 * 100 + '%'
通过方案3和方案4的公式,就可以很方便的生成方案1和方案2中的css。
这里只给出了方案3和方案4对应验证页面(方案1和方案2是它们的变形): scheme3.html, scheme4.html
如下面两张图,是在屏宽为360px下的效果,通过计算目标为:
1rem = 56.25px。方案3设置值为:
56.25px,方案4设置值为:
351.5625%
方案3 | 方案4 |
---|---|
16px。
修改默认字体大小后,我们再看方案3和方案4。
同样在屏宽为360px下,我们调大系统字体大小,如下面的效果
设置前
html元素的字体大小的
计算值为
18px,设置后的
计算值为
65px,由于屏幕宽度没有改变,我们的目标值,即我们在
html元素上设置的
font-size值也没有变化任然为
56.25px,而最终
计算值出现了偏差。
方案3 | 方案4 |
---|---|
360px屏宽下,方案3和方案4的计算过程:
方案3:
document.documentElement.style.fontSize = 56.25px htmlFontSize = 56.25px 1rem = 1 * htmlFontSize = 56.25px 实际为: 1rem = 64.6875px
方案4:
document.documentElement.style.fontSize = 351.5625% htmlFontSize = 351.5625% defaultFontSize = 18px 1rem = 1 * htmlFontSize * defaultFontSize = 351.5625% * 18px = 63.28125px 351.5625% * 18 = 63.28125 实际为: 1rem = 64.6875px
貌似方案4的计算结果很接近实际效果,而方案3偏差很大。再来比较方案3和方案4的计算公式:
// 方案3 document.documentElement.style.fontSize = window.innerWidth / designWidth * rem2px + 'px'; // 方案4 document.documentElement.style.fontSize = window.innerWidth / designWidth * rem2px / 16 * 100 + '%';
方案4较于方案3其实多除了一个16,可以推测浏览器在计算
rem的具体值时,如果
html设置的
font-size为
px值时会先除以
16,然后再乘以
htmlFontSize。
1rem = 1 * (56.25px / 16) * 18 1 * (56.25 / 16) * 18 = 63.28125
方案4存在问题,是因为系统的默认字体改为了
18px,但是我们在计算百分比是时候,还是以
16px为基准值进行计算,所以出现偏差(计算值和实际值之间还有一点偏差这个在后面会提到)。
而在方案3中,我们其实是不考虑浏览器默认字体大小的,但在实际使用的过程中,浏览器还是除了
16,而此时默认字体大小为
18px。得出如下在
html的
fontSize设置为
px的情况下
rem的计算公式为:
1rem = 1 * (htmlFontSize / 16) * defaultFontSize
b605
在系统设置的字体大小发生改变时,
defaultFontSize会跟着改变,而
16不会变化。所以方案3虽然表面上不考虑默认字体大小的变化,只关注屏幕与设计稿之间的宽度比,但在实际计算中还是使用到了默认字体大小,而且还有一个不变的
16在作祟,导致方案3失败。
所谓的「
root element」其实不是想象的那样,一个是
16,一个是
18,到底取的是那个
root element的字体大小。
ok,
rem的计算的时候,
px的方式会有一个
16不随系统字体大小改变,所以我们采用百分比的方案,绕开这个问题。
采用百分比的
方案4因为在计算时写死了默认字体大小
16px。所以它的偏差在于没能动态的获取默认字体大小。更新如下:
方案4.1
var designWidth = 640, rem2px = 100; var h = document.getElementsByTagName('html')[0]; var htmlFontSize = parseFloat(window.getComputedStyle(h, null) .getPropertyValue('font-size')); document.documentElement.style.fontSize = window.innerWidth / designWidth * rem2px / htmlFontSize * 100 + '%';
效果如下图:
16px的图中,设置后的
html的
font-size与
1rem的实际值有偏差,同时
6.4rem的计算值也有偏差。通过查看代码发现
html的
font-size使用的是:
getPropertyValue('font-size')而
1rem使用的是
getPropertyValue('width'),偏差出在计算
font-size的时候浏览器进行了四舍五入。
rem定义中的另一个元素「
font size」也不能按字面意思使用,宣告失守。
18px中的偏差,以及上文中方案4在
18px实际值和计算值出现的偏差都是同样的问题。所以基准值还需要修改。
16px | 18px |
---|---|
var designWidth = 640, rem2px = 100; var d = window.document.createElement('div'); d.style.width = '1rem'; d.style.display = "none"; var head = window.document.getElementsByTagName('head')[0]; head.appendChild(d); var defaultFontSize = parseFloat(window.getComputedStyle(d, null).getPropertyValue('width')); d.remove(); document.documentElement.style.fontSize = window.innerWidth / designWidth * rem2px / defaultFontSize * 100 + '%';
效果如下图:
16px | 18px |
---|---|
rem在默认字体不是
16px的情况下的处理已经解决,考虑到还有设计屏幕旋转,最终手机端的解决方案为:
function adapt(designWidth, rem2px){ var d = window.document.createElement('div'); d.style.width = '1rem'; d.style.display = "none"; var head = window.document.getElementsByTagName('head')[0]; head.appendChild(d); var defaultFontSize = parseFloat(window.getComputedStyle(d, null).getPropertyValue('width')); d.remove(); document.documentElement.style.fontSize = window.innerWidth / designWidth * rem2px / defaultFontSize * 100 + '%'; var st = document.createElement('style'); var portrait = "@media screen and (min-width: "+window.innerWidth+"px) {html{font-size:"+ ((window.innerWidth/(designWidth/rem2px)/defaultFontSize)*100) +"%;}}"; var landscape = "@media screen and (min-width: "+window.innerHeight+"px) {html{font-size:"+ ((window.innerHeight/(designWidth/rem2px)/defaultFontSize)*100) +"%;}}" st.innerHTML = portrait + landscape; head.appendChild(st); return defaultFontSize }; var defaultFontSize = adapt(640, 100);
回过头来再看
rem的定义,『The font size of the root element.』。我们以为的
root element——
html其实还有个影子在作祟,而我们以为的
font-size其实是个近似值。
相关文章推荐
- 了解真实的『REM』手机屏幕适配
- 了解真实的『REM』手机屏幕适配
- 了解真实的『REM』手机屏幕适配
- 了解真实的『REM』手机屏幕适配
- 了解前端手机屏幕适配【REM 】真实原理
- 了解真实的『REM』手机屏幕适配
- 了解真实的『REM』手机屏幕适配
- 了解真实的『REM』多终端屏幕适配
- rem、px、em(手机端h5页面屏幕适配的几种方法)
- web app变革之rem(手机屏幕实现全适配)
- h5 手机屏幕适配—REM
- REM手机屏幕适配
- REM手机屏幕适配
- 经验总结-Android手机屏幕适配问题
- WebView适配手机屏幕显示
- 开发适配手机屏幕的网页注意问题
- 移动端适配不同手机 rem布局
- web page 适配 手机 屏幕,web 页面 改 适应 手机
- js+rem动态计算font-size的大小,适配各种手机设备!
- html5适配手机屏幕