开发移动端页面的时候, 会有这样一种情景: 设计师给出的设计稿是 640 * 1136 尺寸。假如稿件上某区块宽度为 320px, 那么它的宽度就占据了整个视图区域的 50%。但是在实际做页面的时候, 是不能给它指定 width:320px
的, 因为整个视图区域很可能并不是 640px。
既然如此, 如果我们根据比例来换算具体宽度, 应该可以解决问题, 而 css 单位 rem
正是这个换算的比例系数。
rem 是根元素的字体大小(font size of Root Element), 如果以它作为度量单位, 那么实际尺寸只和根元素字体大小相关。当要调整比例的时候, 修改根元素字体大小, 即可进行整体缩放调整。
假设我的目的是把 rem 变成一个等同于 px 的单位, 即: 某元素在设计稿上的标注宽度是 320px, 那么我在 HTML 里给它指定 width: 320rem
, 即可保证在移动端适配, 无需进行其他计算转换。有没有办法做到呢?
测试屏幕宽度与像素的关系
在 chrome 里模拟 iPhone5 进行测试。页面代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="initial-scale=1" />
<title>Index</title>
</head>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.div1 {
background-color: antiquewhite;
width: 160px;
font-size: 160px;
}
</style>
<body>
<div class="div1">
<p>正方形</p>
</div>
<script>
alert(window.innerWidth);
</script>
</body>
</html>
可以看到, ‘正方形’的内容区域刚好占据浏览器视场区域宽度(window.innerWidth)的一半。也就是说, 通过 window.innerWidth / window.innerHeight, 可以获取视场区域的宽高的像素值。
初步计算 rem
依据等比例计算的思想, 计算 rem 的过程如下:
// 设计稿出图的宽度。 假设这里是640, 实际上可以变化
var designWidth = 640;
// 设计稿上单位像素1px 占据设计搞的宽度比例
var p1px = 1 / designWidth;
// 当前屏幕的实际(像素)宽度
var viewportWidth = window.innerWidth;
// 当前屏幕等比展示设计稿上1px的实际像素宽度, 也就是理论上同等数值的情况下的 rem 大小
var viewport1px = viewportWidth * p1px;
// 设置 rem
document.querySelector("html").style.fontSize = viewport1px + "px";
经过此番计算, 设计稿上宽度为 320px 的元素, 放置在页面里, 理论上只需要改写成 320rem 即可! 然而实际查看页面, 发现并不是期待的等比(50%的可视区域宽), 而是大的离谱, chrome 开发者工具显示有 3840px!
浏览器最小字体限制
原来, google 浏览器有一个最小的元素字体限制为 12px, 一旦给元素设定了小于 12px 的字体都会限制为 12px。
按照上面的代码, 给根元素设置的字体大小仅为 0.5px, 因此实际的根元素字体大小为 12px, 于是, 320rem 即等于 320 * 12px = 3840px
了!
改进计算 rem
于是, 不能把 rem 定义成那么小的数值, 只能够放大 rem 来实际应用了! 这里为了方便, 把 rem 按照上面的计算方式再放大 100 倍, 便于实际应用(设计稿上 320px 的, 就定义成 3.2rem, 即数值除以 100), 再适当封装一下即可!
完整代码如下:
(function(dw) {
dw = dw || 640;
var vw = window.innerWidth;
var calcREM = function() {
document.querySelector("html").style.fontSize = (100 * vw) / dw + "px";
};
calcREM();
window.addEventListener("resize", function() {
calcREM();
});
})(640); // 此处依据设计稿的像素宽度值真实填写 0.0
注意, 如果设计稿宽是其他数值比如 750px, 那么最后一行要传递 750。