一、什么是视区相对单位?
就是相对于浏览器viewport尺寸的单位,具体包括下面4个:
- vw – 视区宽度百分值
- vh – 视区高度百分值
- vmin – vw或vh,取小的那个
- vmax – vw或vh,取大的那个
这里100vw就是浏览器窗口的全部宽度,100vh是浏览器窗口的全部高度。
即100vw=window.innerWidth,100vh=window.innerHeight
二、基于vw的响应式排版和布局
一般而言,屏幕越大,我们希望文字大小也越大,元素的尺寸也能等比例放大。如果要实现这种弹性自适应效果,目前主流的实现是通过设定根元素的font-size
大小,具体元素或模块使用rem
或em
单位来实现。
一种是直接设定一个临界点字体大小,如:
html {
font-size: 16px;
}
@media screen and (min-width: 600px) {
html {
font-size: 18px;
}
}
@media screen and (min-width: 1000px) {
html {
font-size: 22px;
}
}
但是这种设置体验不好,页面会在临界点的时候突然改变。
还有一种就是使用JS在页面加载完成后,或者页面resize时或者屏幕旋转的时候,动态修改root的font-size
大小。
//适配不同尺寸
(function(doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function() {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
docEl.style.fontSize = 100 * (clientWidth / 750) + 'px';
};
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);
//其中在页面加载完成时,和页面大小改变时,会触发recalc 方法改变根元素的font-size
本文要讲的方法是vm,配合CSS3 calc
计算实现动态响应式的效果。
例如,我们希望浏览器宽度在375px~1000px变化的时候,html根元素的font-size
大小是16px~22px之间对应变化的,则可以:
html { font-size: calc(16px + (100vw - 375px) / 100); }
当视区宽度是375px
的时候,100vm
就等于375px
,于是:font-size=16px+0/100=16px;
当视区宽度是1000px时,100vm等于1000px,于是font-size=16px+625/100=22.25px;
不过这种写法有一个坑就是苹果的Safari浏览器不支持这种写法。好在,还是有办法,那就是我们基础字体大小不使用像素单位,使用百分比单位即可,如下:
html {
/* iPhone6的375px尺寸作为16px基准,600px正好18px大小 */
font-size: calc(100% + 2 * (100vw - 375px) / 225);
}
@media screen and (min-width: 600px) {
html {
/* 600px-1000px每100像素宽字体增加1px(18px-22px) */
font-size: calc(112.5% + 4 * (100vw - 600px) / 400);
}
}
@media screen and (min-width: 1000px) {
html {
/* 1000px往后是每100像素0.5px增加 */
font-size: calc(137.5% + 5 * (100vw - 1000px) / 1000);
}
}
有了动态的根字体大小,我们就可以使用rem
或em
这些相对单位,来让我们的页面排版和布局更富有弹性。
在大尺寸下:
在小尺寸下:
最后,在实际开发中,兼容性较好的实践代码:
html {
font-size: 16px;
}
@media screen and (min-width: 375px) {
html {
/* iPhone6的375px尺寸作为16px基准,414px正好18px大小, 600 20px */
font-size: calc(100% + 2 * (100vw - 375px) / 39);
font-size: calc(16px + 2 * (100vw - 375px) / 39);
}
}
@media screen and (min-width: 414px) {
html {
/* 414px-1000px每100像素宽字体增加1px(18px-22px) */
font-size: calc(112.5% + 4 * (100vw - 414px) / 586);
font-size: calc(18px + 4 * (100vw - 414px) / 586);
}
}
@media screen and (min-width: 600px) {
html {
/* 600px-1000px每100像素宽字体增加1px(20px-24px) */
font-size: calc(125% + 4 * (100vw - 600px) / 400);
font-size: calc(20px + 4 * (100vw - 600px) / 400);
}
}
@media screen and (min-width: 1000px) {
html {
/* 1000px往后是每100像素0.5px增加 */
font-size: calc(137.5% + 6 * (100vw - 1000px) / 1000);
font-size: calc(22px + 6 * (100vw - 1000px) / 1000);
}
}
结语:考虑到vw等视区单位的兼容性,IE8,Android4.4及以下都不兼容。对于绝大部分设备,我们还是可以用这套方法写,老的设备,我们可以使用上面JS的策略,打个脚本补丁,效果都是一样的,CSS代码也完全复用,一点都没必要特异处理,因为老机子不认识vw
,所以完全没必要担心新老冲突这样的问题。