响应式网页设计原则
创建媒体查询
媒体查询是 CSS3 中引入的一项新技术,它可以根据不同的视口大小调整内容的布局。 视口是指浏览器中,用户可见的网页内容。 视口会随访问网站的设备不同而改变。
媒体查询由媒体类型组成,如果媒体类型与展示网页的设备类型匹配,则应用对应的样式。 你可以在媒体查询中使用各种选择器和样式。
下面是一个媒体查询的例子,当设备宽度小于或等于 100px
时返回内容:
1
@media (max-width: 100px) { /* CSS Rules */ }
以下定义的媒体查询,是当设备高度大于或等于 350px
时返回内容:
1
@media (min-height: 350px) { /* CSS Rules */ }
注意,只有当媒体类型与所使用的设备的类型匹配时,媒体查询中定义的 CSS 才生效。
使图片自适应设备尺寸
用 CSS 来让图片自适应其实很简单。 你只需要给图片添加这些属性:
1
2
3
4
img {
max-width: 100%;
height: auto;
}
设置 max-width
值为 100%
可确保图片不超出父容器的范围;设置 height
属性为 auto
可以保持图片的原始宽高比。
针对高分辨率屏幕应使用视网膜图片
随着联网设备的增加,设备间的区别不仅发生在尺寸和规格上,还发生在用于显示的设备上。 像素密度就是区分不同显示设备的一个指标,它一般会以 PPI(Pixel Per Inch,即每英寸像素)或 DPI(每英寸点数)为计量单位。 最著名的显示器就是 Apple MacBook Pro 笔记本电脑上的“视网膜显示屏”(现亦用于 iMac)。 由于“视网膜显示屏”和“非视网膜显示屏”显示器之间像素密度的不同,某些未考虑高分辨率显示器的图像在高分辨率显示器上渲染时,可能因出现“像素化”而不够清晰。
让图像正确出现在高分辨率显示器(例如 MacBook Pros “Revistina display”)上的最简单方式, 是定义它们的 width
和 height
值为原始值的一半。 下面是一个仅使用原始高度和宽度一半的图像示例:
1
2
3
4
<style>
img { height: 250px; width: 250px; }
</style>
<img src="coolPic500x500" alt="A most excellent picture">
使排版根据设备尺寸自如响应
除了使用 em
或 px
设置文本大小,你还可以用视窗单位来做响应式排版。 视窗单位和百分比都是相对单位,但它们是基于不同的参照物。 视窗单位是相对于设备的视窗尺寸(宽度或高度),百分比是相对于父级元素的大小。
四个不同的视窗单位分别是:
vw
:如10vw
的意思是视窗宽度的 10%。vh:
如3vh
的意思是视窗高度的 3%。vmin:
如70vmin
的意思是视窗的高度和宽度中较小一个的 70%。vmax:
如100vmax
的意思是视窗的高度和宽度中较大一个的 100%。
下面这个例子是设置 body
标签的宽度为视窗宽度的 30%。
1
body { width: 30vw; }
CSS弹性盒子
使用 display: flex 定位两个盒子
这节我们会使用不同的挑战方式来学习如何使用 CSS 更灵活地布局元素。 首先我们会通过一个挑战来解释原理,然后通过操作一个简单的推文组件来应用弹性盒子(flexbox)。
只要在一个元素的 CSS 中添加 display: flex;
,就可以使用其它 flex 属性来构建响应式页面了。
使用 flex-direction 属性创建行或列
给元素添加 display: flex
属性可以让它变成 flex 容器, 然后可以让元素的项目排列成行或列。 只要给父元素添加 flex-direction
属性,并把属性值设置为 row 或 column,即可横向排列或纵向排列它的所有子元素。 创建一行将使子项水平对齐,创建一列将使子项垂直对齐。
flex-direction
的其他可选值还有 row-reverse
和 column-reverse
(reverse的意思是逆序,即从左到右变成从右到左)。
注意: flex-direction
的默认值为 row
。
使用 justify-content 属性对齐元素
flex 子元素有时不能充满整个 flex 容器, 所以我们经常需要告诉 CSS 以什么方式排列 flex 子元素,以及调整它们的间距。 幸运的是,我们可以通过 justify-content
属性的不同值来实现。 在介绍属性的可选值之前,我们要先理解一些重要术语。
回忆一下,如果把 flex 容器设为一个行,它的子元素会从左到右逐个排列; 如果把 flex 容器设为一个列,它的子元素会从上到下逐个排列。 子元素排列的方向被称为 main axis(主轴)。 对于行,主轴水平贯穿每一个项目; 对于列,主轴垂直贯穿每一个项目。
对于如何沿主轴线排放 flex 项目,有几种选择。 很常用的一种是 justify-content: center;
:即 flex 子元素在 flex 容器中居中排列。 其他选择包括:
flex-start
:从 flex 容器的起始位置开始排列项目。 对行来说是把项目移至左边, 对于列是把项目移至顶部。 如未设置justify-content
的值,那么这就是默认值。flex-end
:从 flex 容器的终止位置开始排列项目。 对行来说是把项目移至右边, 对于列是把项目移至底部。space-between
:项目间保留一定间距地沿主轴居中排列。 第一个和最后一个项目被放置在容器边沿。 例如,在行中第一个项目会紧贴着容器左边,最后一个项目会紧贴着容器右边,然后其他项目均匀排布。space-around
:与space-between
相似,但头尾两个项目不会紧贴容器边缘,所有项目之间的空间均匀排布。space-evenly
:在 flex 项目之间均匀分配空间,在 flex 容器的任一端都有一个完整的空间。
使用 align-items 属性对齐元素
align-items
属性与 justify-content
类似。 回忆一下,justify-content
属性使 flex 子元素沿主轴排列。 行的主轴是水平线,列的主轴是垂直线。
Flex 容器中,与主轴垂直的叫做 cross axis(交叉轴)。 行的交叉轴是垂直的,列的交叉轴是水平的。
CSS 中的 align-items
属性用来定义 flex 子元素沿交叉轴的对齐方式。 对行来说,定义的是元素的上下对齐方式; 对列来说,是定义元素的左右对齐方式。
align-items
的可选值包括:
flex-start
:从 flex 容器的起始位置开始对齐项目。 对行来说,把项目移至容器顶部; 对列来说,是把项目移至容器左边。flex-end
:从 flex 容器的终止位置开始对齐项目。 对行来说,把项目移至容器底部; 对列来说,把项目移至容器右边。center
:把项目居中放置。 对行来说,垂直居中(项目距离顶部和底部的距离相等); 对列来说,水平居中(项目距离左边和右边的距离相等)。stretch
:拉伸项目,填满 flex 容器。 例如,排成行的项目从容器顶部拉伸到底部。 如未设置align-items
的值,那么这就是默认值。baseline
:沿基线对齐。 基线是文本相关的概念,可以认为它是字母排列的下端基准线。
使用 flex-wrap 属性包裹一行或一列
CSS flexbox 具有将 flex 容器拆分为多行(或列)的功能。 默认情况下,flex 容器会调整项目大小,把它们都塞到一起。 对于行来说,所有项目都会在一条直线上。
不过,使用 flex-wrap
属性可以使项目换行展示。 这意味着多出来的子元素会被移到新的行或列。 换行发生的断点由子元素和容器的大小决定(当一行元素撑满之后就会自动换行了)。
换行方向的可选值有这些:
nowrap
:默认值,不换行。wrap
:如果排列以行为基准,就将行从上往下排列;如果排列以列为基准,就将列从左往右排列。wrap-reverse
:如果排列以行为基准,就将行从下往上排列;如果排列以列为基准,就将列从右往左排列。
使用 flex-shrink 属性定义 flex 子元素的收缩规则
目前为止,提到的属性都是应用于 flex 容器(flex 子元素的父元素)的。 除此之外,flex 子元素也有很多实用属性。
首先介绍的是 flex-shrink
属性。 使用之后,如果 flex 容器太小,则子元素会自动缩小。 当容器的宽度小于里面所有子元素的宽度之和时,所有子元素都会自动压缩。
子元素的 flex-shrink
接受数值作为属性值。 数值越大,则该元素与其他元素相比会被压缩得更厉害。 比如,一个项目的 flex-shrink
属性值为 1
,另一个项目的 flex-shrink
属性值为 3
,那么后者相比前者会受到 3
倍压缩。
使用 flex-grow 属性定义 flex 子元素的增长系数
与 flex-shrink
相对的是 flex-grow
。 你应该还记得,flex-shrink
会在容器太小时对子元素作出调整。 相应地,flex-grow
会在容器太大时对子元素作出调整。
例子与上一个挑战相似,如果一个项目的 flex-grow
属性值为 1
,另一个项目的 flex-grow
属性值为 3
,那么值为 3
的一个会较另一个扩大 3 倍,flex-shrink
和flex-grow
都支持小数。
使用 flex-basis 属性设置元素的初始大小
flex-basis
属性定义了在使用 CSS 的 flex-shrink
或 flex-grow
属性对元素进行调整前,元素的初始大小。
flex-basis
属性的单位与其他表示尺寸的属性的单位一致(px
、em
、%
等)。 如果值为 auto
,则项目的尺寸随内容调整。
使用 flex 短方法属性
上面几个 flex 属性有一个简写方式。 flex-grow
、flex-shrink
和 flex-basis
属性可以在 flex
中一并设置。
例如,flex: 1 0 10px;
会把项目属性设为 flex-grow: 1;
、flex-shrink: 0;
以及 flex-basis: 10px;
。
属性的默认设置是 flex: 0 1 auto;
。
使用 order 属性重新排列子元素
order
属性告诉 CSS flex 容器里子元素的顺序。 默认情况下,项目排列顺序与源 HTML 文件中顺序相同。 这个属性接受数字作为参数,可以使用负数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<style>
#box-container {
display: flex;
height: 500px;
}
#box-1 {
background-color: dodgerblue;
order:2;
height: 200px;
width: 200px;
}
#box-2 {
background-color: orangered;
order:1;
height: 200px;
width: 200px;
}
</style>
<div id="box-container">
<div id="box-1"></div>
<div id="box-2"></div>
</div>
使用 align-self 属性
flex 子项目的最后一个属性是 align-self
。 这个属性允许你调整单个子元素自己的对齐方式,而不会影响到全部子元素。 因为 float
、clear
和 vertical-align
等调整对齐方式的属性都不能应用于 flex 子元素,所以这个属性显得十分有用。
align-self
可设置的值与 align-items
的一样,并且它会覆盖 align-items
所设置的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<style>
#box-container {
display: flex;
height: 500px;
}
#box-1 {
background-color: dodgerblue;
align-self:center;
height: 200px;
width: 200px;
}
#box-2 {
background-color: orangered;
align-self:flex-end;
height: 200px;
width: 200px;
}
</style>
<div id="box-container">
<div id="box-1"></div>
<div id="box-2"></div>
</div>
CSS网格
创建一个 CSS 网格
通过将属性 display
的值设为 grid
,HTML 元素就可以变为网格容器。 通过前面的操作,你可以对该容器使用与 CSS 网格(CSS Grid)相关的属性。
注意: 在 CSS 网格中,父元素称为容器(container),它的子元素称为项(items)。
添加多列多行
简单地添加一个网格元素并不会有任何明显的效果。 你还需要明确网格的结构。 在一个网格容器中使用 grid-template-columns
属性可以添加一些列,示例如下:
1
2
3
4
.container {
display: grid;
grid-template-columns: 50px 50px;
}
上面的代码会在网格容器中添加两列,宽度均为 50px。 grid-template-columns
属性值的个数表示网格的列数,每个值表示相应的列宽度。
同样可以使用 grid-template-rows
属性添加多行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<style>
.d1{background:LightSkyBlue;}
.d2{background:LightSalmon;}
.d3{background:PaleTurquoise;}
.d4{background:LightPink;}
.d5{background:PaleGreen;}
.container {
font-size: 40px;
width: 100%;
background: LightGray;
display: grid;
/* 创建3列,分别为100 50 100 */
grid-template-columns:100px 50px 100px;
/* 创建2列,分别为50 100 */
grid-template-rows:50px 100px;
}
</style>
<div class="container">
<div class="d1">1</div>
<div class="d2">2</div>
<div class="d3">3</div>
<div class="d4">4</div>
<div class="d5">5</div>
</div>
使用 CSS 网格单位来更改列和行的大小
在 CSS 网格中,可以使用绝对单位(如 px
)或相对单位(如 em
)来定义行或列的大小。 下面的单位也可以使用:
fr
:设置列或行占剩余空间的比例,
auto
:设置列宽或行高自动等于它的内容的宽度或高度,
%
:将列或行调整为它的容器宽度或高度的百分比,
1
grid-template-columns: auto 50px 10% 2fr 1fr;
这段代码添加了五个列。 第一列的宽与它的内容宽度相等;第二列宽 50px;第三列宽是它容器的 10%;最后两列,将剩余的宽度平均分成三份,第四列占两份,第五列占一份。
创建多列多行之间的间距
目前为止,在你所创建的网格中,每列都相互紧挨着。 有时候你想要列之间有一个间距。 如果需要在列与列之间添加一些间距,我们可以使用 grid-column-gap
:
1
grid-column-gap: 10px;
这会为我们创建的所有列之间都添加 10px 的空白间距。我们还可以用 grid-row-gap
设置行间距。
grid-gap
属性是前两个挑战中出现的 grid-row-gap
和 grid-column-gap
的简写属性,它更方便使用。 如果 grid-gap
只有一个值,那么这个值表示行与行之间、列与列之间的间距均为这个值。 如果有两个值,那么第一个值表示行间距,第二个值表示列间距。
控制空间大小
到目前为止,所有的讨论都是围绕网格容器的。 grid-column
属性是我们要讨论的,第一个用于网格项本身的属性。
网格中,假想的水平线和垂直线被称为线(lines)。 这些线在网格的左上角从 1 开始编号,垂直线向右、水平线向下累加计数。
这是一个 3x3 网格的线条:
要设置一个网格项占据几列,你可以使用 grid-column
属性加上网格线条的编号来定义网格项开始和结束的位置。
示例如下:
1
grid-column: 1 / 3;
这会让网格项从左侧第一条线开始到第三条线结束,占用两列。
和设置一个网格项占用多列类似,你也可以设置它占用多行。 你可以使用 grid-row
属性来定义一个网格项开始和结束的水平线。
水平对齐项目
在 CSS 网格中,每个网格项的内容分别位于被称为单元格(cell)的框内。 你可以使用网格项的 justify-self
属性,设置其内容的位置在单元格内沿水平轴的对齐方式。 默认情况下,这个属性的值是 stretch
,这将使内容占满整个单元格的宽度。 该 CSS 网格属性也可以使用其他的值:
start
:使内容在单元格左侧对齐center
:使内容在单元格居中对齐end
:使内容在单元格右侧对齐
有时你想让 CSS 网格中的网格项共享对齐方式。 你可以像之前学习的那样分别设置它们的对齐方式,也可以对网格容器使用 justify-items
使它们一次性沿水平轴对齐。 这个属性能接受我们在之前两个挑战中学到的所有值作为属性值,但与之前不同的是,它会将网格中 所有 的网格项按所设置的方式对齐。
垂直对齐项目
正如能设置网格项沿水平方向的对齐方式一样,我们也可以设置网格项沿竖直方向的对齐方式。 为此,我们可以对网格项使用 align-self
属性来实现。 在上一个挑战中适用于 justify-self
属性的属性值同样也可用于这个属性。
对网格容器使用 align-items
属性可以让网格中所有的网格项沿竖直方向对齐。
将网格划分为区域模板
你可以将网格中的一些单元格组合成一个区域(area),并为该区域指定一个自定义名称。 可以通过给容器加上 grid-template-areas
来实现:
1
2
3
4
grid-template-areas:
"header header header"
"advert content content"
"advert footer footer";
上面的代码将网格单元格分成四个区域:header
、advert
、content
和 footer
。 每个单词代表一个单元格,每对引号代表一行。
使用 grid-area 属性将项目放置在网格区域中
像上一个挑战那样,在为网格添加区域模板后,可以通过引用你所定义的区域的名称,将元素放入相应的区域。 为此,你需要对网格项使用 grid-area
:
1
2
3
.item1 {
grid-area: header;
}
这样,class 为 item1
的网格项就被放到了 header
区域里。 在这种情况下,该项目将使用整个顶行,因为该整行被命名为 header
区域。
使用 grid-area 创建区域模板
我们在上一次挑战中学到的 grid-area
属性还有另一种使用方式。 如果网格中没有定义区域模板,你也可以像这样为它添加一个模板:
1
item1 { grid-area: 1/1/2/4; }
这里使用了你之前学习的网格线编号来定义网格项的区域。 上例中数字代表这些值:
1
grid-area: horizontal line to start at / vertical line to start at / horizontal line to end at / vertical line to end at;
因此,示例中的网格项将占用第 1 条水平网格线(起始)和第 2 条水平网格线(终止)之间的行,及第 1 条垂直网格线(起始)和第 4 条垂直网格线(终止)之间的列。
使用 repeat 函数减少重复
使用 grid-template-columns
或 grid-template-rows
定义网格结构时,你需要为添加的每一行或每一列都输入一个值。
如果一个网格共有 100 行且每行高度相同, 那我们就需要输入 100 个值,这显然不太实际。 为此,更好的方式是使用 repeat
方法指定行或列的重复次数,后面加上逗号以及需要重复的值。
以下为添加 100 行网格的例子,每行高度均为 50px:
1
grid-template-rows: repeat(100, 50px);
你还可以用 repeat 方法重复多个值,并在定义网格结构时与其他值一起使用。 比如:
1
grid-template-columns: repeat(2, 1fr 50px) 20px;
效果相当于:
1
grid-template-columns: 1fr 50px 1fr 50px 20px;
注意: 1fr 50px
重复了两次,后面跟着 20px。
使用 minmax 函数限制项目大小
此外,内置函数 minmax
也可用于设置 grid-template-columns
和 grid-template-rows
的值。 它的作用是在网格容器改变大小时限制网格项的大小。 为此,你需要指定网格项允许的尺寸范围。 例如:
1
grid-template-columns: 100px minmax(50px, 200px);
在上面的代码中,我们通过 grid-template-columns
添加了两列,第一列宽度为 100px,第二列宽度最小值是 50px,最大值是 200px。
使用 auto-fill 创建弹性布局
repeat 方法带有一个名为自动填充(auto-fill)的功能。 它的功能是根据容器的大小,尽可能多地放入指定大小的行或列。 你可以通过结合 auto-fill
和 minmax
来更灵活地布局。
1
repeat(auto-fill, minmax(60px, 1fr));
上面的代码效果是这样:首先,列的宽度会随容器大小改变。其次,只要容器宽度不足以插入一个宽为 60px 的列,当前行的所有列就都会一直拉伸。请自己调整宽度,动手试一下就不难理解了。 注意: 如果容器宽度不足以将所有网格项放在同一行,余下的网格项将会移至新的一行。
如上图,上半部分为repeat(auto-fill, minmax(60px, 1fr));
,下半部分为repeat(3, minmax(60px, 1fr));
,上半部分满足60px的空闲区域后就会允许4号挤上去。
使用 auto-fit 创建弹性布局
auto-fit
效果几乎和 auto-fill
一样。 不同点仅在于,当容器的大小大于各网格项之和时,auto-fill
会持续地在一端放入空行或空列,这样就会使所有网格项挤到另一边;而 auto-fit
则不会在一端放入空行或空列,而是会将所有网格项拉伸至合适的大小。
注意: 如果容器宽度不足以将所有网格项放在同一行,余下的网格项将会移至新的一行。
使用媒体查询创建响应式布局
将 CSS 网格与使用媒体查询结合使用,如使用媒体查询重新排列网格区域、更改网格尺寸以及重新排列网格项位置,我们可以让制作出的网站更具响应性。
在如下代码中,当网页可视区域的宽不小于 300px 时,列数从 1 变为 2。 并且,广告(advertisement)区域会完全占据左列。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<style>
.item1 {
background: LightSkyBlue;
grid-area: header;
}
.item2 {
background: LightSalmon;
grid-area: advert;
}
.item3 {
background: PaleTurquoise;
grid-area: content;
}
.item4 {
background: lightpink;
grid-area: footer;
}
.container {
font-size: 1.5em;
min-height: 300px;
width: 100%;
background: LightGray;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 50px auto 1fr auto;
grid-gap: 10px;
grid-template-areas:
"header"
"advert"
"content"
"footer";
}
@media (min-width: 300px){
.container{
grid-template-columns: auto 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"advert header"
"advert content"
"advert footer";
}
}
@media (min-width: 400px){
.container{
grid-template-areas:
"header header"
"advert content"
"footer footer";
}
}
</style>
<div class="container">
<div class="item1">header</div>
<div class="item2">advert</div>
<div class="item3">content</div>
<div class="item4">footer</div>
</div>
如下图,当宽度小于300px时并排展示
当宽度介于300px和400px之间时,advert部分分开
当宽度大于400px时,header和footer部分占满一行
在网格中创建网格
将元素转换为网格只会影响其子元素(即直接后代元素,英文为 direct descendants。意思是一个元素的所有后代元素中,父级元素为该元素的所有元素)。 因此,如果我们把某个子元素设置为网格,就会得到一个嵌套的网格。
例如,如果我们设置 class 为 item3
的元素的 display
和 grid-template-columns
属性,就会得到一个嵌套的网格。
参考文献
- freecodecamp 响应式网页设计原则教程
- freecodecamp CSS 弹性盒子教程
- freecodecamp CSS 网格教程
- html中figcaption标签的作用 原文链接:https://www.itcast.cn/news/20200909/17584245044.shtml
- HTML fieldset和legend标签 原文链接:http://t.zoukankan.com/potato-lee-p-6100148.html