理解响应式布局(进阶必备知识)

1,563 阅读6分钟

这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战

TIP 👉 三军可夺帅也,匹夫不可夺志也。——《论语·子罕》

前言

响应式布局是 CSS 布局中一个特别的分支。基于响应式布局,可以衍生出一个非常完整的移动端适配的知识链路。

理解viewport

viewport 也叫“视口”。 移动设备上的viewport就是设备的屏幕上能用来显示网页内容的区域。viewport不局限于浏览器可视区域的大小,可能比浏览器的可视区域大,也可能小。默认情况下,移动设备上的viewport大于浏览器可视区域,原因:考虑到移动设备的分辨率相对于桌面电脑来说都比较小,所以为了能在移动设备上正常显示传统为桌面浏览器设计的网页,移动设备上的浏览器都会把自己默认的viewport设为980px或1024px,但是结果可能是浏览器出现横向滚动条。

布局视口 layout viewport与视觉视口visual viewport

在移动端开发中,我们经常可以见到这样的meta标签写法:

<meta name="viewport" content="width=device-width">

这里设置的 width,就是布局视口的宽度。那么什么是布局视口呢?大家现在可以打开一个新的 chrome 标签页, 访问 www.baidu.com/(百度首页),点击右键,选择“检查”,选中 mobile 模式,然后刷新页面,你会得到一个类似这样的元素审查界面:

image.png

对 html 代码进行检索,我们会发现百度的移动端主页也在 meta 标签里对 viewport 进行了这个常见设置:

image.png

为什么一定要设置width=device-width?不设置会有什么后果?这里我随便把 width 改写成1000,发现页面变成了

image.png

我们注意到,页面的可视区域变小了,这是为什么呢?这是由于视觉视口和布局视口不相等导致的。

所谓视觉视口,它指的是你的设备实际的可见区域,也就是浏览器的宽高。在PC端,浏览器的宽高我们可以任意缩放;但在移动端,浏览器的宽高一般是不支持改变的,其大小由设备屏幕的大小决定。在当前的示例中,视觉视口就是下图红色箭头所标识的范围:

image.png

通过访问window.innerWidthwindow.innerHeight两个属性,我们可以获取到视觉视口的宽高:

image.png

那么布局视口又是什么?

布局视口指的是页面实际布局所占用的区域。关于布局视口,可以理解为“画布”,画布的大小约束了你能够在多大的范围内作画,我们将布局视口调整为1000,画布的区域超出了可见区域的范围也就是视觉视口的范围,如图:

image.png

我们可以通过document.documentElement.clientWidth来获取布局视口的宽度。

理想视口(ideal viewport)

通过上面我们可以发现,视觉视口和布局视口的大小并不总是一样的,当两者不等时,就会出现不符合预期的展示效果,实际上,很多时候,布局视口本身的宽度都是无法和视觉视口完全匹配的,为了解决这个问题,人们提出了“理想视口”的概念,它指的是布局视口最理想的尺寸。

“理想的尺寸”指的是整个页面刚好全部覆盖手机屏幕的尺寸。这个尺寸不需要我们手动计算,厂商根据手机屏幕尺寸大小,会提供一个最符合这个屏幕尺寸页面设计方案,我们通过这样一行代码就可以应用这个方案:

<meta name = "viewport" content="width=device-width">

此处width属性对应的就是布局视口的值。设置width = device-width的目的,正是为了使布局视口的狂堵刚好匹配上视觉视口的宽度。

rem和em

rem指的是相对于HTML根元素的字体大小来计算的长度单位,比如说我们给html设置一个font-size

html{
    font-size: 100px;
}

1rem = 100px

em也是一个相对长度单位,它相对的是适用他们的元素的字体大小,比如我们给一个div设置一个字体大小为20px

div{
    font-size: 20px;
    padding: 1em;
    width: 2em;
}

那么1em = 20px

很多人认为em单位取的是当前元素对应父元素的字体大小,这是不对的,的确在一些情况下,em确是会刚好渠道父元素的字体大小,但这并非em的本色,而是由继承导致的。

.farther{
    font-size: 20px;
}
.son{
    width: 20em;
    height: 20em;
}

<div class="farther">
    父元素
    <div class="son">
       子元素
    </div>
</div>

son元素的宽高分别是200px和400px,此时em取的忍让不是父元素的font-size,而是当前元素的font-size,只是应为继承的发生,导致当前元素的font-size和父元素的font-size值一样而已。我们给son一个自身的font-size属性,使继承不再发生,em就会直接取指定的这个font-size值了

.son{
    font-size: 16px;
    width: 20em;
    height: 20em;
}

son元素的宽高是320px,可见em取的是当前元素的font-size。

什么是响应式布局

响应式布局的目的是为了让我们的页面能够在不同大小的设备屏幕上正常展示。能够使一张页面适配多种屏幕的布局方案,就是所谓的“响应式布局方案”。

媒体查询

既然要解决的是屏幕大小不确定的问题,那么最直接的思路就是想办法去感知屏幕大小的变化,并根据不同的屏幕大小展示不同的样式。媒体查询做的就是这件事情,它是一个古老而经典的响应式布局解决方案,是BootStrap响应式特性的基石。

@media screen and (max-width: 320px) { 
    div {
        width: 160px;
    }
}

@media screen and (min-width: 768px) { 
    div {
        width: 300px;
    }
}
  • max-width:对最大宽度的限制。比如我们第一条媒体查询声明语句中,max-width: 320px,它的意思就是说当设备屏幕宽度不大于320px时,则采纳这条声明对应的样式规则。

  • min-width:对最小宽度的限制。比如我们第一条媒体查询声明语句中,min-width: 768px,它的意思就是说当设备屏幕宽度不小于768px时,则采纳这条声明对应的样式规则。

rem

这里推荐大家使用flexible.js,它是手淘团队整合的一套相对成熟的移动端自适应解决方案库。

vw/vh

vw 和 vh 是一种区别于rem和px的cas尺寸单位,它们天生自带等比缩放能力:

  • vw:1vw = 视觉视口宽度/100
  • vh: 1vh = 视觉视口高度/100
.responsive{
    width: 10vw;
    height: 10vh;
    background: blue;
}
<div class='responsive'></div>

10vw和10vh,这个元素应该始终占据整个页面宽度/高度的十分之一。