「响应式网页设计」 响应式基础设计

CSS accessibility

Posted by Mingyu on May 13, 2022

响应式网页设计原则

创建媒体查询

媒体查询是 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”)上的最简单方式, 是定义它们的 widthheight 值为原始值的一半。 下面是一个仅使用原始高度和宽度一半的图像示例:

1
2
3
4
<style>
  img { height: 250px; width: 250px; }
</style>
<img src="coolPic500x500" alt="A most excellent picture">

使排版根据设备尺寸自如响应

除了使用 empx 设置文本大小,你还可以用视窗单位来做响应式排版。 视窗单位和百分比都是相对单位,但它们是基于不同的参照物。 视窗单位是相对于设备的视窗尺寸(宽度或高度),百分比是相对于父级元素的大小。

四个不同的视窗单位分别是:

  • 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-reversecolumn-reverse(reverse的意思是逆序,即从左到右变成从右到左)。

注意: flex-direction 的默认值为 row

使用 justify-content 属性对齐元素

flex 子元素有时不能充满整个 flex 容器, 所以我们经常需要告诉 CSS 以什么方式排列 flex 子元素,以及调整它们的间距。 幸运的是,我们可以通过 justify-content 属性的不同值来实现。 在介绍属性的可选值之前,我们要先理解一些重要术语。

image-20220714085814245

回忆一下,如果把 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-shrinkflex-grow都支持小数。

使用 flex-basis 属性设置元素的初始大小

flex-basis 属性定义了在使用 CSS 的 flex-shrinkflex-grow 属性对元素进行调整前,元素的初始大小。

flex-basis 属性的单位与其他表示尺寸的属性的单位一致(pxem% 等)。 如果值为 auto,则项目的尺寸随内容调整。

使用 flex 短方法属性

上面几个 flex 属性有一个简写方式。 flex-growflex-shrinkflex-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。 这个属性允许你调整单个子元素自己的对齐方式,而不会影响到全部子元素。 因为 floatclearvertical-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-gapgrid-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";

上面的代码将网格单元格分成四个区域:headeradvertcontentfooter。 每个单词代表一个单元格,每对引号代表一行。

使用 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-columnsgrid-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-columnsgrid-template-rows 的值。 它的作用是在网格容器改变大小时限制网格项的大小。 为此,你需要指定网格项允许的尺寸范围。 例如:

1
grid-template-columns: 100px minmax(50px, 200px);

在上面的代码中,我们通过 grid-template-columns 添加了两列,第一列宽度为 100px,第二列宽度最小值是 50px,最大值是 200px。

使用 auto-fill 创建弹性布局

repeat 方法带有一个名为自动填充(auto-fill)的功能。 它的功能是根据容器的大小,尽可能多地放入指定大小的行或列。 你可以通过结合 auto-fillminmax 来更灵活地布局。

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 的元素的 displaygrid-template-columns 属性,就会得到一个嵌套的网格。

参考文献

  1. freecodecamp 响应式网页设计原则教程
  2. freecodecamp CSS 弹性盒子教程
  3. freecodecamp CSS 网格教程
  4. html中figcaption标签的作用 原文链接:https://www.itcast.cn/news/20200909/17584245044.shtml
  5. HTML fieldset和legend标签 原文链接:http://t.zoukankan.com/potato-lee-p-6100148.html