目录
通过上一节的学习
移动端网页的布局
固定尺寸布局
百分比布局
rem布局
vw布局
仿京东移动端首页开发实例(rem布局、vw布局)
通过上一节的学习
CSS - 移动端布局(一)关键的前置知识_伏城之外的博客-CSDN博客
我们了解了物理像素、CSS像素、物理分辨率、逻辑分辨率、图片分辨率、视觉视口、布局视口、理想视口等概念,以及移动端显示屏、移动端浏览器相关知识;
我们可以设置网页的meta viewport标签,确保网页被移动端浏览器解析时,可以将默认的布局视口宽度变为适应移动端设备屏幕大小的理想视口宽度
<meta name="viewport" content="width=device-width, initial-scale=1.0">
而一旦网页按照理想视口宽度来设计,则此时的网页就能完美的在移动端浏览器视觉视口中展示,此时,我们不希望用户来放大或缩小网页,因此我们需要增加如下meta viewport如下配置,来禁止用户放大、缩小网页
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
也就是说,一个网页设置如上meta viewport标签后,当在移动端浏览器打开该网页,则网页的根元素html宽度(布局视口宽度)就等于移动端设备的显示屏宽度(设备独立像素宽度)
移动端网页的布局
固定尺寸布局
PC端网页的布局大多采用固定尺寸,如下图是某PC网页的设计稿,在设计稿中设定的尺寸都是固定尺寸,并且这些固定尺寸可以完全照搬到网页制作上。
而使用固定尺寸制作的网页,存在一个严重的问题,那就是无法自适应不同分辨率的屏幕。
比如在分辨率较小的设备上(如下图是在800x600分辨率屏幕下),网页无法展示完全,需要通过滚动条滚动来查看剩余部分,
比如在分辨率较大的设备上(如下图是在1920x1080分辨率屏幕下),网页虽然可以展示完全,但是却会出现较大的空白区域。
而这些问题同样存在于采用固定尺寸布局的移动端网页上,下面是采用固定尺寸开发的仿京东移动端首页的广告栏:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
margin: 0;
}
.container {
width: 414px;
}
.adv {
width: 414px;
height: 45px;
text-align: center;
line-height: 45px;
font-size: 14px;
color: #fff;
background-color: #333;
display: flex;
}
.adv-close {
width: 33px;
height: 45px;
}
.adv-close > img {
width: 10px;
height: 10px;
}
.adv-logo {
width: 41px;
height: 45px;
}
.adv-logo > img {
width: 30px;
height: 30px;
vertical-align: middle;
}
.adv-tips {
flex-grow: 1;
}
.adv-open {
width: 103.5px;
height: 45px;
background-color: #f63515;
}
</style>
</head>
<body>
<div class="container">
<div class="adv">
<div class="adv-close">
<img
src="https://m.360buyimg.com/mobilecms/jfs/t19480/10/1439571805/820/787bec2c/5ac9d730N04e6d766.png"
alt=""
/>
</div>
<div class="adv-logo">
<img
src="https://img11.360buyimg.com/jdphoto/s80x80_jfs/t27847/91/107794072/6854/14716732/5b850ecaN644d2983.png"
alt=""
/>
</div>
<div class="adv-tips">
<span>打开京东App,购物更轻松</span>
</div>
<div class="adv-open">
<span>立即打开</span>
</div>
</div>
</div>
</body>
</html>
通过真机演示效果可以发现,发现固定尺寸开发的网页无法在移动端上实现很好的适配。
因此,无论是PC端还是移动端,采用固定尺寸布局方案的网页必须要对不同分辨率的屏幕设备进行适配。
PC端网页的适配方案是:版心式布局。
即将PC网页的主体内容放在网页版心中,网页版心在网页中水平居中,版心使用固定尺寸,而版心两端的留白区域采用自适应宽度。
这样的好处在于,
当设备屏幕宽度较大时,版心尺寸保持不变,版心两端留白宽度吸收剩余宽度,并且版心处于网页水平居中位置,并不好让留白显得突兀,反而可以更好地让人眼注意聚焦在版心区域。
当设备屏幕宽度较小时,版心尺寸依旧保持不变,版心两端留白宽度减少,如果留白区域减少为0依旧不能适配设备屏幕,则版心才开始使用滚动条。
但是版心式布局只适合PC端网页,不适合移动端网页,因为移动设备屏幕的宽度都非常小,小到连网页主体内容都要精心排版才能勉强放下,更不用说有剩余宽度给到版心两端留白区域了。
因此,固定尺寸布局并不适合移动端网页。
百分比布局
由于移动端网页并不适合使用固定尺寸布局,因此我们更推荐使用动态尺寸。所谓动态尺寸,即网页布局尺寸的值会随着移动设备屏幕尺寸的变化而变化。
最常用的动态尺寸,就是百分比尺寸。
一个元素的width、height、padding、margin这些盒子模型属性,top、right、bottom、left这些位偏移属性都支持使用百分比尺寸。
但是在使用百分比尺寸时,我们必须要明确元素的百分比尺寸是相对于谁的百分比?
布局和包含块 - CSS(层叠样式表) | MDN (mozilla.org)
在MDN中,有这样一段介绍:
也就是说,元素的百分比尺寸相对的是该元素的包含块。
那么什么是包含块呢?
许多开发者认为一个元素的包含块就是他的父元素的内容区。但事实并非如此。- 确定一个元素的包含块的过程完全依赖于这个元素的position属性。
元素的position样式属性值 | 特点 | 元素的包含块 |
static、relative、sticky (PS:未定义position,相当于position=static) | 定位元素不脱标 | 该元素最接近的祖先块容器的内容区(content盒子) (PS:块容器包括:块级元素block、列表项块元素list-item、行内块inline-block等等) |
absolute | 定位元素脱标 |
|
fixed | 定位元素脱标 | 在连续媒体的情况下 (continuous media) 包含块是浏览器的视觉视口 |
我们来验证一下:
- 对于position为static、sticky、relative的元素的包含块验证:
- 对于position为absolute的元素的包含块的验证:
如果position:absolute元素的祖先中存在position != static 的元素
如果position:absolute元素的祖先中不存在position != static 的元素
对于初始包含块的深入理解
我们需要注意的是,初始包含块 != html根元素,而是html根元素所在的包含块,初始包含块的尺寸 就是 浏览器视觉视口的尺寸。
- 对于position为fixed元素的包含块的验证:
好了,现在我们已经了解了百分比尺寸的计算方法,可以发现,元素百分比尺寸的参照对象并不统一:
- 对于position为static、relative、sticky的元素,它们的百分比尺寸参照的是 最近祖先块容器 的 内容区尺寸
- 对于position为absolute的元素A
- 如果祖先存在position != static 的元素B,则A的百分比尺寸 参照的是 B 的 内边距区尺寸
- 如果祖先不存在position != static 的元素,则A的百分比尺寸 参照的是 浏览器视觉视口的尺寸
- 对于position为fixed的元素,它的百分比尺寸参照的是 浏览器视觉视口的尺寸
另外,元素的width和height百分比尺寸参照对象也不统一,元素的width百分比尺寸参照的往往是其祖先元素或视口的宽度,元素的height百分比尺寸参照的往往是其祖先元素或视口的高度。
因此我们很难使用百分比尺寸进行网页整体布局,只能对网页局部进行布局。
比如,我们基于百分比布局开发一下京东移动端首页的广告栏
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
html,
body {
margin: 0;
padding: 0;
}
.container {
position: absolute; /* 这里如果不使用absolute,则height:100%,其实是body元素,相当于html元素的高度,而使用了absolute后,则相当于初始包含块,即视觉视口的高度 */
width: 100%;
height: 100%;
}
.adv {
width: 100%;
height: calc(45 / 896 * 100%);
background-color: #333333;
font-size: 14px; /* 文字无法使用百分比尺寸 */
color: #fff;
display: flex;
}
.adv-close {
width: calc(33 / 414 * 100%);
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.adv-close > img {
width: calc(
10 / 33 * 100%
); /* 注意这里img的包含块就是.adv-close,因此img的百分比尺寸相对的是.adv-close,而不是视觉视口 */
height: calc(10 / 45 * 100%);
}
.adv-logo {
width: calc(41 / 414 * 100%);
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.adv-logo > img {
width: calc(30 / 41 * 100%);
height: calc(30 / 45 * 100%);
}
.adv-tips {
flex-grow: 1;
/* text-align: center;
line-height: 100%; */ /* line-height无法使用百分比尺寸,因此我们无法利用它进行文字垂直居中处理 */
display: flex;
justify-content: center;
align-items: center;
}
.adv-open {
width: calc(103.5 / 414 * 100%);
height: 100%;
background-color: #f63515;
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div class="container">
<div class="adv">
<div class="adv-close">
<img
src="https://m.360buyimg.com/mobilecms/jfs/t19480/10/1439571805/820/787bec2c/5ac9d730N04e6d766.png"
alt=""
/>
</div>
<div class="adv-logo">
<img
src="https://img11.360buyimg.com/jdphoto/s80x80_jfs/t27847/91/107794072/6854/14716732/5b850ecaN644d2983.png"
alt=""
/>
</div>
<div class="adv-tips">
<span>打开京东App,购物更轻松</span>
</div>
<div class="adv-open">
<span>立即打开</span>
</div>
</div>
</div>
</body>
</html>
通过代码,和真机效果演示,我们发现了百分比布局的几个问题:
- 计算困难,一方面要口头计算百分比,我上面代码是通过的CSS3的calc函数实现计算,但是calc函数是网页渲染实时计算的,用多了会影响网页渲染性能,因此我们可以用less或scss来代替。另一方面,计算时,我们需要考虑元素的百分比尺寸相对的是谁,这个是比较麻烦的,必须特别熟悉包含块概念,比如上面代码中x图片和京东狗logo图片的宽度百分比就是相对的父块级元素宽度,而不是视觉视口宽度。
- 只有元素的width、height、padding、margin这些盒子模型属性,left、right、top、bottom这些位偏移属性可以使用百分比尺寸,其他的诸如文字大小、line-height等都无法使用百分比尺寸,只能使用固定尺寸。
- 元素width百分比尺寸参照的是其包含块宽尺寸(可能是内容区、内边距区或者视口宽度),元素height百分比尺寸参照的是其包含块高尺寸(可能是内容区、内边距区或者视口高度),因此元素width、height百分比尺寸的放大极有可能不成比例,造成布局变形
rem布局
百分比布局输在没有一个统一的基数,即不同元素的百分比尺寸参照的基数不同,同一个元素的宽度百分比尺寸和高度百分比尺寸参照的基数也不同,这是导致百分比布局不能应用于网页整体布局的直接原因。还有一个重要的间接原因是,并非所有使用尺寸的样式属性都能使用百分比尺寸,比如文字大小,行高等。
因此,CSS设计出了rem单位。rem单位和px单位的作用类似,都是作为描述尺寸的逻辑单位,并且使用px单位的地方,都可以使用rem单位。二者的区域在于,px用于指代一个或多个的物理像素点,rem用于指代一个或多个px。
CSS将 html根元素的font-size的值作为 1 rem。
rem尺寸相较于百分比尺寸的优势在于:
- 所有能使用px单位的样式属性都可以使用rem单位,不像百分比尺寸,只有元素的width、height、padding、margin、left、top、right、bottom可以使用
- 1 rem 固定等于 html font-size的值,而 1% 无法确定等于什么尺寸,要看元素的包含块,以及百分比尺寸是宽值还是高值
rem尺寸相较于百分比尺寸的的缺点在于:
- 百分比尺寸的实际值可以随着设备屏幕尺寸的变化而自动变化,但是rem尺寸的实际值只会随着html font-size值得变化而变化,但是html font-size的值不会随着设备屏幕尺寸的变化而变化,因此我们需要监听屏幕尺寸的变化,然后实时计算1 rem的值,并将值赋给html font-szie
一般而言,网页设计稿中采用的总是固定尺寸,为了换算简单,我们假设设计稿的html font-size的值为100px,因此,网页设计稿中元素的rem尺寸 = 其固定尺寸 / 100。
当渲染网页的移动端设备的屏幕尺寸变更时,
新屏幕尺寸(宽度) / fs = 设计稿屏幕尺(宽度) / 100
也就是说,
在新屏幕尺寸设备下的html font-size的值 = 新屏幕尺寸(宽度) / 设计稿屏幕尺(宽度) * 100
比如,设计稿是按照 414px * 896px的屏幕设计的,设计稿的html font-size为100px,当网页被展示到了 768px * 1024px的屏幕上,则此时html font-size应该被更新为:768 / 414 * 100
更新html font-size的时机有两个:
- window.onload:网页重新加载时
- window.onresize:网页尺寸变更时
下面是基于rem尺寸开发的京东移动端首页的广告栏:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
html {
font-size: 100px;
}
body {
margin: 0;
}
.container {
width: 4.14rem; /* 414 / 100 */
}
.adv {
width: 4.14rem;
height: 0.45rem; /* 45 / 100 */
font-size: 0.14rem; /* 14 / 100 */
color: #fff;
background-color: #333;
text-align: center;
line-height: 0.45rem; /* 45 / 100 */
display: flex;
}
.adv-close {
width: 0.33rem; /* 33 / 100 */
height: 0.45rem;
}
.adv-close > img {
width: 0.1rem; /* 10 / 100 */
height: 0.1rem;
}
.adv-logo {
width: 0.41rem; /* 41 / 100 */
height: 0.45rem;
}
.adv-logo > img {
width: 0.3rem; /* 30 / 100 */
height: 0.3rem;
vertical-align: middle;
}
.adv-tips {
flex-grow: 1;
}
.adv-open {
width: 1.035rem; /* 103.5 / 100 */
height: 0.45rem;
background-color: #f63515;
}
</style>
</head>
<body>
<div class="container">
<div class="adv">
<div class="adv-close">
<img
src="https://m.360buyimg.com/mobilecms/jfs/t19480/10/1439571805/820/787bec2c/5ac9d730N04e6d766.png"
alt=""
/>
</div>
<div class="adv-logo">
<img
src="https://img11.360buyimg.com/jdphoto/s80x80_jfs/t27847/91/107794072/6854/14716732/5b850ecaN644d2983.png"
alt=""
/>
</div>
<div class="adv-tips">
<span>打开京东App,购物更轻松</span>
</div>
<div class="adv-open">
<span>立即打开</span>
</div>
</div>
</div>
<script>
function setRem() {
const layoutViewportWidth = document.documentElement.clientWidth;
// 414 / 100 = layoutViewportWidth / fs
const fs = layoutViewportWidth / 4.14;
document.documentElement.style.fontSize = fs + "px";
}
window.onload = setRem;
window.onresize = setRem;
</script>
</body>
</html>
vw布局
rem布局虽然已经可以很好地解决移动端网页布局的适配问题,但是依旧美中不足,因为rem尺寸无法自动适配屏幕,需要我们手动地通过JS来监听屏幕尺寸变化,并计算出1 rem的值设置给html font-size属性。
因此,CSS又推出了vw单位,vw单位也是一种描述尺寸的单位,作用和px、rem相同,也就是说可以使用px、rem单位的地方,都可以使用vw单位。
vw单位和px、rem的区别在于,1 vw 总是等于 浏览器视觉视口宽度的1%,如下图中,红色div盒子的width为10vw,高度也为10vw,当我们增加视觉视口宽度时,红色div盒子的width、height也在等比例地进行放大,我们可以观察浏览器视觉视口右上角的视口宽度的变化,和浏览器调试窗口中红色div盒子模型中内容区宽高的变化
因此,vw单位兼具了rem单位和百分比的优点:
- 1 vw 可以随着屏幕尺寸的变化,自动更新自身的值,就像百分比尺寸一样
- 1 vw 可以用在任何使用px单位的地方,并且1 vw 总是参照 视觉视口宽度的 1%,就像 1 rem 总是等于 html font-size的值
网页设计稿中总是使用固定尺寸,因此我们在开发时需要将固定尺寸换算为vw尺寸,换算方法为: 元素的vw尺寸 = (元素的固定尺寸 / 视觉视口宽度) * 100%
比如:网页设计稿中,视觉视口宽度为414px,元素高度为45px,则
视觉视口宽度 = 100vw
视觉视口宽度 = 414px
因此 1px = 100 / 414 vw
因此 高度为45px的元素,对于的vw高度为:45 * (100 / 414) = 10.8695652173913 vw
我们可以发现换算过程中元素的vw尺寸很难得到整数,而是除不尽的小数,但是我们不能对小数进行四舍五入取整数,这会产生严重的误差,因此我们只能保留小数。
但是实际开发过程中计算这种除不尽的小数非常麻烦,因此我们可以借助less或scss语法来处理。
而当网页所在的设备屏幕变化时,我们不需要做任何处理,因为1 vw可以自动适应为对于屏幕视觉视口宽度的1%。
下面是基于vw尺寸开发的京东移动端首页的广告栏:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
margin: 0;
}
.container {
width: 100vw;
}
.adv {
width: 100vw;
height: calc(45vw * 100 / 414);
background-color: #333;
font-size: calc(14vw * 100 / 414);
color: #fff;
text-align: center;
line-height: calc(45vw * 100 / 414);
display: flex;
}
.adv-close {
width: calc(33vw * 100 / 414);
height: 100%;
}
.adv-close > img {
width: calc(10vw * 100 / 414);
height: calc(10vw * 100 / 414);
}
.adv-logo {
width: calc(41vw * 100 / 414);
height: 100%;
}
.adv-logo > img {
width: calc(30vw * 100 / 414);
height: calc(30vw * 100 / 414);
vertical-align: middle;
}
.adv-tips {
flex-grow: 1;
}
.adv-open {
width: calc(103.5vw * 100 / 414);
height: 100%;
background-color: #f63515;
}
</style>
</head>
<body>
<div class="container">
<div class="adv">
<div class="adv-close">
<img
src="https://m.360buyimg.com/mobilecms/jfs/t19480/10/1439571805/820/787bec2c/5ac9d730N04e6d766.png"
alt=""
/>
</div>
<div class="adv-logo">
<img
src="https://img11.360buyimg.com/jdphoto/s80x80_jfs/t27847/91/107794072/6854/14716732/5b850ecaN644d2983.png"
alt=""
/>
</div>
<div class="adv-tips">
<span>打开京东App,购物更轻松</span>
</div>
<div class="adv-open">
<span>立即打开</span>
</div>
</div>
</div>
</body>
</html>
可以发现,采用vw尺寸的移动端网页的适配性非常好。
下面我们可以查查各大浏览器对于vw的兼容性:"vw" | Can I use... Support tables for HTML5, CSS3, etc
并且当前各大浏览器对于vw的支持非常好。当然不包含已经停止更新的IE,以及Opera Mini浏览器。
当然,对比rem来看,vw的兼容性略差一点
仿京东移动端首页开发实例(rem布局、vw布局)
仿京东移动端首页布局(固定尺寸、rem适配、vw适配)-HTML5文档类资源-CSDN文库https://download.csdn.net/download/qfc_128220/86438094?spm=1001.2014.3001.5501
仿京东移动端首页布局,包括固定尺寸布局、rem适配布局、vw适配布局,设计稿尺寸使用的iPhoneXR的414px * 896px。 我们可以通过在不同移动端设备上展示移动端网页,发现固定尺寸布局的不足之处,以及rem适配、vw适配的原理。 其中vw适配的网页css使用的是scss语法,使用了函数、变量、嵌套等语法。