4-CSS排版


title: 4-CSS排版
tags: CSS(设计Web)
category: MDN

介绍 CSS 布局

参考文档

正常布局流(Normal flow)

正常布局流(normal flow)是指在不对页面进行任何布局控制时,浏览器默认的HTML布局方式。

HTML元素完全按照源码中出现的先后次序显示

display属性

它的一些属性值如下:

block
    元素显示为块元素

inline
    元素显示为内联元素

flex
    设置弹性盒子

grid
    设置网格布局

弹性盒子(Flexbox)

Flexbox 是CSS 弹性盒子布局模块(Flexible Box Layout Module)的缩写,它被专门设计出来用于创建横向或是纵向的一维页面布局。要使用flexbox,你只需要在想要进行flex布局的父元素上应用display: flex ,所有直接子元素都将会按照flex进行布局。

如下例子,当我们把display: flex添加到它的父元素时,这三个元素就自动按列进行排列。这是由于它们变成了flex项(flex items),按照flex容器(也就是它们的父元素)的一些flex相关的初值进行flex布局:它们整整齐齐排成一行,是因为父元素上flex-direction的初值是row。它们全都被拉伸至和最高的元素高度相同,是因为父元素上align-items属性的初值是stretch。这就意味着所有的子元素都会被拉伸到它们的flex容器的高度,在这个案例里就是所有flex项中最高的一项。所有项目都从容器的开始位置进行排列,排列成一行后,在尾部留下一片空白。

.wrapper {
  display: flex;
}
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
</div>

我们可以在我们的所有子元素上添加flex 属性,并赋值为1,这会使得所有的子元素都伸展并填充容器,而不是在尾部留下空白,如果有更多空间,那么子元素们就会变得更宽,反之,他们就会变得更窄。除此之外,如果你在HTML标记中添加了一个新元素,那么它们也会变得更小,来为新元素创造空间——不管怎样,最终它们会调整自己直到占用相同宽度的空间。

.wrapper {
    display: flex;
}

.wrapper > div {
    flex: 1;
}
<div class="wrapper">
    <div class="box1">One</div>
    <div class="box2">Two</div>
    <div class="box3">Three</div>
</div>

网格布局

Flexbox用于设计横向或纵向的布局,而Grid布局则被设计用于同时在两个维度(即行和列)上把元素按行和列排列整齐。(该布局设置了一个个类似“单元格”的空间放置容器里的元素)

.wrapper {
/* 设置为网格布局 */
    display: grid;
/* 设置了 3列 */
    grid-template-columns: 1fr 1fr 1fr;
/* 设置了 2行 */
    grid-template-rows: 100px 100px;
/* 设置网格之间的间距 */
    grid-gap: 10px;
}
<div class="wrapper">
    <div class="box1">One</div>
    <div class="box2">Two</div>
    <div class="box3">Three</div>
    <div class="box4">Four</div>
    <div class="box5">Five</div>
    <div class="box6">Six</div>
</div>

在下面的第二个例子里,我们定义了一个和上面一样的grid,但是这一次我们只有三个子元素。我们利用 grid-columngrid-row 两个属性来指定每一个子元素应该从哪一行/列开始,并在哪一行/列结束。这就能够让子元素在多个行/列上展开。

.wrapper {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 100px 100px;
    grid-gap: 10px;
}

/* 该盒子占据了 第1行第2列 + 第1行第3列 + 两个网格之间的间距 */
.box1 {
    grid-column: 2 / 4;
    grid-row: 1;
}

/* 该盒子占据了 第1列第1行 + 第1列第2行 + 两个网格之间的间距 */
.box2 {
    grid-column: 1;
    grid-row: 1 / 3;
}

/* 将该盒子放置在 第2行第3列 的网格中  */
.box3 {
    grid-row: 2;
    grid-column: 3;
}
<div class="wrapper">
    <div class="box1">One</div>
    <div class="box2">Two</div>
    <div class="box3">Three</div>
</div>

浮动

float 属性有四个可能的值:

left
    将元素浮动到左侧。

right
    将元素浮动到右侧。

none
    默认值, 不浮动。

inherit
    继承父元素的浮动属性。

在下面这个例子当中,我们把一个<div>元素浮动到左侧,并且给了他一个右侧的margin,把文字推开。这给了我们文字环绕着这个<div>元素的效果

<h1>Simple float example</h1>

<div class="box">Float</div>

<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p>
.box {
    float: left;
    width: 150px;
    height: 150px;
    margin-right: 30px;
}

定位技术

定位(positioning)能够让我们把一个元素从它原本在正常布局流(normal flow)中应该在的位置移动到另一个位置。定位(positioning)并不是一种用来给你做主要页面布局的方式,它更像是让你去管理和微调页面中的一个特殊项的位置。

有五种主要的定位类型需要我们了解:

  1. 静态定位:(Static positioning)是每个元素默认的属性——它表示将元素放在文档布局流的默认位置
  • 相对定位:(Relative positioning)允许我们相对于元素在正常的文档流中的位置移动它,甚至将两个元素叠放在页面上
  • 绝对定位:(Absolute positioning)将元素完全从页面的正常布局流(normal layout flow)中移出,类似将它单独放在一个图层中
  • 固定定位:(Fixed positioning)与绝对定位非常类似,但是它是将一个元素相对浏览器视口固定,而不是相对另外一个元素。
  • 粘性定位:(Sticky positioning)是一种新的定位方式,它会让元素先保持和`position: static`一样的定位,当它的相对视口位置(offset from the viewport)达到某一个预设值时,他就会像`position: fixed`一样定位。
  • 相对定位

    相对定位(relative positioning)让你能够把一个正常布局流(normal flow)中的元素从它的 默认位置 按坐标进行相对移动

    .positioned {
      position: relative;
      top: 30px;
      left: 30px;
    }
    

    这里我们给中间段落的position 一个 relative值——这属性本身不做任何事情,所以我们还添加了topleft属性。这些可以将受影响的元素向下向右移——这可能看起来和你所期待的相反,但你需要把它看成是左边和顶部的元素被“推开”一定距离,这就导致了它的向下向右移动。

    绝对定位

    绝对定位用于将元素移出正常布局流(normal flow),以坐标的形式相对于它的容器定位到web页面的任何位置

    .positioned {
      position: absolute;
      top: 30px;
      left: 30px;
    }
    

    注意绝对定位是按它的父容器进行定位的,则在这里则是该盒子相对于父盒子的左上角向下移动30px,向右移动30px

    固定定位

    固定定位(fixed positioning)同绝对定位(absolute positioning)一样,将元素从文档流(document flow)当中移出了。但是,定位的坐标不会应用于"容器"边框来计算元素的位置,而是会应用于视口(viewport)边框(视口即看到的浏览器部分)

    .positioned {
        position: fixed;
        top: 30px;
        left: 30px;
    }
    
    粘性定位

    粘性定位(sticky positioning)将默认的静态定位(static positioning)和固定定位(fixed positioning)相混合。当一个元素被指定了position: sticky时,它会在正常布局流中滚动,直到它出现在了我们给它设定的相对于容器的位置,这时候它就会停止随滚动移动,就像它被应用了position: fixed一样。

    .positioned {
      position: sticky;
      top: 30px;
      left: 30px;
    }
    

    表格布局

    一个<table>标签之所以能够像表格那样展示,是由于css默认给<table>标签设置了一组table布局属性。当这些属性被应用于排列非<table>元素时,这种用法被称为“使用CSS表格”。

    <form>
      <p>First of all, tell us your name and age.</p>
      <div>
        <label for="fname">First name:</label>
        <input type="text" id="fname">
      </div>
      <div>
        <label for="lname">Last name:</label>
        <input type="text" id="lname">
      </div>
      <div>
        <label for="age">Age:</label>
        <input type="text" id="age">
      </div>
    </form>
    
    html {
      font-family: sans-serif;
    }
    
    form {
    /* 表格布局 */
      display: table;
    /* 居中显示 */
      margin: 0 auto;
    }
    
    form div {
    /* 设置为表格的行 */
      display: table-row;
    }
    
    form label, form input {
    /* 设置为表格单元格 */
      display: table-cell;
      margin-bottom: 10px;
    }
    
    form label {
      width: 200px;
      padding-right: 5%;
      text-align: right;
    }
    
    form input {
      width: 300px;
    }
    
    form p {
    /* 将该 p元素 定义为表格标题 */
      display: table-caption;
    /* 标题展示在表格的底部 */
      caption-side: bottom;
      width: 300px;
      color: #999;
      font-style: italic;
    }
    

    多列布局

    要把一个块转变成多列容器(multicol container),我们可以使用 column-count属性来告诉浏览器我们需要多少列,也可以使用column-width 来告诉浏览器以至少某个宽度的尽可能多的列来填充容器。

    我们指定了该容器的column-width为200像素,这让浏览器创建了尽可能多的200像素的列来填充这一容器。接着他们共同使用剩余的空间来伸展自己的宽度。

    .container {
        column-width: 200px;
    }
    

    正常布局流

    参考文档

    默认情况下,元素是如何布局的

    首先,取得元素的内容来放在一个独立的元素盒子中,然后在其周边加上内边距、边框和外边距 — 就是我们之前看到的盒子模型。

    默认的,一个块级元素的内容宽度是其父元素的100%,其高度与其内容高度一致。内联元素的height width与内容一致。你无法设置内联元素的height width — 它们就那样置于块级元素的内容里。 如果你想控制内联元素的尺寸,你需要为元素设置display: block; (或者,display: inline-block; inline-block 混合了inline 和 block的特性。)

    正常布局流(在布局介绍里提到过)是一套在浏览器视口内放置、组织元素的系统。默认的,块级元素按照基于其父元素的书写顺序(默认值: horizontal-tb)的块流动方向(block flow direction)放置 — 每个块级元素会在上一个元素下面另起一行,它们会被设置好的margin分隔。在英语,或者其他水平书写、自上而下模式里,块级元素是垂直组织的。

    内联元素的表现有所不同 — 它们不会另起一行;只要在其父级块级元素的宽度内有足够的空间,它们与其他内联元素、相邻的文本内容(或者被包裹的)被安排在同一行。如果空间不够,溢出的文本或元素将移到新的一行。

    弹性盒子

    参考文档

    弹性盒子是一种用于按行或按列布局元素的一维布局方法 。元素可以膨胀以填充额外的空间, 收缩以适应更小的空间。

    指定元素的布局为 flexible

    首先,我们需要选择将哪些元素将设置为柔性的盒子。我们需要给这些 flexible 元素的父元素 display 设置一个特定值。在本例中,我们想要设置 <article> 元素,因此我们给 <section>(变成了 flex 容器)设置 display:

    section {
      display:flex
    }
    

    注意:假如你想设置行内元素为 flexible box,也可以置 display 属性的值为 inline-flex。

    flex 模型说明

    当元素表现为 flex 框时,它们沿着两个轴来布局:

    主轴(main axis)是沿着 flex 元素放置的方向延伸的轴(比如页面上的横向的行、纵向的列)。该轴的开始和结束被称为 main start 和 main end。

    交叉轴(cross axis)是垂直于 flex 元素放置方向的轴。该轴的开始和结束被称为 cross start 和 cross end。

    设置了 display: flex 的父元素(在本例中是 <section>)被称之为 flex 容器(flex container)。

    在 flex 容器中表现为柔性的盒子的元素被称之为 flex 项(flex item)(本例中是 <article> 元素。

    列还是行

    弹性盒子提供了 flex-direction 这样一个属性,它可以指定主轴的方向(弹性盒子子类放置的地方)— 它默认值是 row,这使得它们在按你浏览器的默认语言方向排成一排(在英语/中文浏览器中是从左到右)。

    如果想将那些元素设置为列布局,则修改如下属性:

    flex-direction: column;
    

    注意:你还可以使用 row-reversecolumn-reverse 值反向排列 flex 项目

    换行

    当你在布局中使用定宽或者定高的时候,可能会出现问题即处于容器中的 弹性盒子子元素会溢出,破坏了布局。

    解决此问题的一种方法是将以下声明添加到 section css 规则(弹性盒子的容器)中:

    /* 设置为允许换行 */
    flex-wrap: wrap
    

    同时,把以下规则也添加到<article> 规则(弹性盒子的子元素)中:

    /* 设置每个元素的宽度至少为 200px */
    flex: 200px;
    

    flex-flow 缩写

    存在着 flex-directionflex-wrap — 的缩写 flex-flow。比如,你可以将

    flex-direction: row;
    flex-wrap: wrap;
    

    替换为

    flex-flow: row wrap;
    

    flex 项的动态尺寸

    为弹性盒子中的子元素设置比例:

    article {
      flex: 1;
    }
    

    这是一个无单位的比例值,表示每个 flex 项沿主轴的可用空间大小。本例中,我们设置 <article> 元素的 flex 值为 1,这表示每个元素占用空间都是相等的,占用的空间是在设置 paddingmargin 之后剩余的空间。

    因为它是一个比例,这意味着将每个 flex 项的设置为 400000 的效果和 1 的时候是完全一样的。(在这里每个子元素占据 1 / (1 + 1+ 1) 大小的空间)

    现在在上一个规则下添加:

    article:nth-of-type(3) {
      flex: 2;
    }
    

    则此时前两个 flex 项各有一个,因此它们占用每个可用空间的1/4。 第三个有两个单位,所以它占用2/4或这说是1/2的可用空间。

    您还可以指定 flex 的最小值:

    article {
      flex: 1 200px;
    }
    
    article:nth-of-type(3) {
      flex: 2 200px;
    }
    

    这表示“每个flex 项将首先给出200px的可用空间,然后,剩余的可用空间将根据分配的比例共享“。

    flex: 缩写与全写

    flex 是一个可以指定最多三个不同值的缩写属性:

    第一个就是上面所讨论过的无单位比例。可以单独指定全写 flex-grow 属性的值。

    第二个无单位比例 — flex-shrink — 一般用于溢出容器的 flex 项。这指定了从每个 flex 项中取出多少溢出量,以阻止它们溢出它们的容器。

    第三个是上面讨论的最小值。可以单独指定全写 flex-basis 属性的值。

    水平和垂直对齐

    div {
    /* 弹性盒子 */
      display: flex;
    /* 垂直对齐 */
      align-items: center;
    /* 水平对齐 */
      justify-content: space-around;
    }
    

    align-items 控制 flex 项在交叉轴上的位置。

    1、默认的值是 stretch,其会使所有 flex 项沿着交叉轴的方向拉伸以填充父容器。如果父容器在交叉轴方向上没有固定宽度(即高度),则所有 flex 项将变得与最长的 flex 项一样长(即高度保持一致)。

    2、在上面规则中我们使用的 center 值会使这些项保持其原有的高度,但是会在交叉轴居中。这就是那些按钮垂直居中的原因。

    3、你也可以设置诸如 flex-startflex-end 这样使 flex 项在交叉轴的开始或结束处对齐所有的值。

    justify-content 控制 flex 项在主轴上的位置。

    1、默认值是 flex-start,这会使所有 flex 项都位于主轴的开始处。

    2、也可以用 flex-end 来让 flex 项到结尾处。

    3、centerjustify-content 里也是可用的,可以让 flex 项在主轴居中。

    4、而我们上面用到的值 space-around 是很有用的——它会使所有 flex 项沿着主轴均匀地分布,在任意一端都会留有一点空间。

    5、还有一个值是 space-between,它和 space-around 非常相似,只是它不会在两端留下任何空间。

    flex 项排序

    弹性盒子也有可以改变 flex 项的布局位置的功能,而不会影响到源顺序(即 dom 树里元素的顺序)

    button:first-child {
      order: 1;
    }
    

    所有 flex 项默认的 order 值是 0。

    order 值大的 flex 项比 order 值小的在显示顺序中更靠后。

    相同 order 值的 flex 项按源顺序显示。所以假如你有四个元素,其 order 值分别是2,1,1和0,那么它们的显示顺序就分别是第四,第二,第三,和第一。

    你也可以给 order 设置负值使它们比值为 0 的元素排得更前面。比如

    button:last-child {
      order: -1;
    }
    

    flex 嵌套

    弹性盒子也能创建一些颇为复杂的布局。设置一个元素为flex项目,那么他同样成为一个 flex 容器,它的孩子(直接子节点)也表现为 flexible box 。

    跨浏览器兼容性

    大多数浏览器都支持 弹性盒子,诸如 Firefox, Chrome, Opera, Microsoft Edge 和 IE 11,较新版本的 Android/iOS 等等。但是你应该要意识到仍旧有被人使用的老浏览器不支持 弹性盒子(或者支持,但是只是支持非常非常老版本的 弹性盒子)。

    弹性盒子相较其他一些 CSS 特性可能更为棘手。 例如,如果浏览器缺少 CSS 阴影,则该网站可能仍然可用。 但是假如不支持 弹性盒子功能就会完全打破布局,使其不可用。

    网格

    参考文档

    什么是网格布局

    网格是由一系列水平及垂直的线构成的一种布局模式。一个网格通常具有许多的列(column)与行(row),以及行与行、列与列之间的间隙,这个间隙一般被称为沟槽(gutter)。

    在CSS中创建网格

    定义网格

    首先,将容器的display属性设置为grid来定义一个网络。与弹性盒子一样,将父容器改为网格布局后,他的直接子项会变为网格项。

    .container {
        display: grid;
    }
    

    与弹性盒子不同的是,在定义网格后,网页并不会马上发生变化。因为display: grid的声明只创建了一个只有一列的网格,所以你的子项还是会像正常布局流那样从上而下一个接一个的排布。

    为了让我们的容器看起来更像一个网格,我们要给刚定义的网格加一些列。那就让我们加三个宽度为200px的列。当然,这里可以用任何长度单位,包括百分比。

    .container {
        display: grid;
        grid-template-columns: 200px 200px 200px;
    }
    
    使用fr单位的灵活网格

    除了长度和百分比,我们也可以用fr这个单位来灵活地定义网格的行与列的大小。这个单位表示了可用空间的一个比例

    使用下面的规则来创建3个1fr的列:

    .container {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
    }
    

    将窗口调窄,你应该能看到每一列的宽度可以会随着可用空间变小而变小。fr 单位按比例划分了可用空间

    .container {
        display: grid;
        grid-template-columns: 2fr 1fr 1fr;
    }
    

    这个定义里,第一列被分配了2fr可用空间,余下的两列各被分配了1fr的可用空间,这会使得第一列的宽度是第二第三列的两倍。另外,fr可以与一般的长度单位混合使用,比如grid-template-columns: 300px 2fr 1fr,那么第一列宽度是300px,剩下的两列会根据除去300px后的可用空间按比例分配。

    注意:fr单位分配的是可用空间而非所有空间,所以如果某一格包含的内容变多了,那么整个可用空间就会减少,可用空间是不包括那些已经确定被占用的空间的。

    网格间隙

    使用 grid-column-gap属性来定义列间隙;使用 grid-row-gap 来定义行间隙;使用 grid-gap 可以同时设定两者。

    .container {
        display: grid;
        grid-template-columns: 2fr 1fr 1fr;
        grid-gap: 20px;
    }
    

    间隙距离可以用任何长度单位包括百分比来表示,但不能使用fr单位。

    gap属性曾经有一个grid-前缀,不过后来的标准进行了修改,目的是让他们能够在不同的布局方法中都能起作用。尽管现在这个前缀不会影响语义,但为了代码的健壮性,你可以把两个属性都写上。

    .container {
      display: grid;
      grid-template-columns: 2fr 1fr 1fr;
      grid-gap: 20px;
      gap: 20px;
    }
    
    重复构建行/列

    你可以使用repeat来重复构建具有某些宽度配置的某些列。举个例子,如果要创建多个等宽轨道,可以用下面的方法。

    .container {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        grid-gap: 20px;
    }
    

    这相当于构建了3个1fr的列。第一个传入repeat函数的值(3)表明了后续列宽的配置要重复多少次,而第二个值(1fr)表示需要重复的构建配置,这个配置可以具有多个长度设定。例如repeat(2, 2fr 1fr),这相当于填入了2fr 1fr 2fr 1fr

    显式网格与隐式网格

    显式网格是我们用grid-template-columnsgrid-template-rows 属性创建的。而隐式网格则是当有内容被放到网格外时才会生成的。显式网格与隐式网格的关系与弹性盒子的main和cross轴的关系有些类似。简单来说,隐式网格就是为了放显式网格放不下的元素,浏览器根据已经定义的显式网格自动生成的网格部分。

    隐式网格中生成的行/列大小是参数默认是auto,大小会根据放入的内容自动调整。当然,你也可以使用grid-auto-rowsgrid-auto-columns属性手动设定隐式网格的大小。下面的例子将grid-auto-rows设为了100px,然后你可以看到那些隐式网格中的行(因为这个例子里没有设定grid-template-rows,因此,所有行都位于隐式网格内)现在都是100像素高了。

    .container {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      grid-auto-rows: 100px;
      grid-gap: 20px;
    }
    
    方便的minmax() 函数

    minmax 函数为一个行/列的尺寸设置了取值范围。比如设定为 minmax(100px, auto),那么尺寸就至少为100像素,并且如果内容尺寸大于100像素则会根据内容自动调整。

    .container {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        grid-auto-rows: minmax(100px, auto);
        grid-gap: 20px;
    }
    

    如果所有网格内的内容均小于100像素,那么看起来不会有变化,但如果在某一项中放入很长的内容或者图片,你可以看到这个格子所在的哪一行的高度变成能刚好容纳内容的高度了。注意我们修改的是grid-auto-rows ,因此只会作用于隐式网格。当然,这一项属性也可以应用于显示网格

    自动使用多列填充

    某些情况下,我们需要让网格自动创建很多列来填满整个容器。通过设置grid-template-columns属性,我们可以实现这个效果,不过这一次我们会用到repeat函数中的一个关键字auto-fill来替代确定的重复次数。而函数的第二个参数,我们使用minmax函数来设定一个行/列的最小值,以及最大值1fr

    .container {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
      grid-auto-rows: minmax(100px, auto);
      grid-gap: 20px;
    }
    

    能看到形成了一个包含了许多至少200像素宽的列的网格,将容器填满。随着容器宽度的改变,网格会自动根据容器宽度进行调整,每一列的宽度总是大于200像素,并且容器总会被列填满。(网格是子元素,容器是父元素)

    基于线的元素放置

    在定义完了网格之后,我们要把元素放入网格中。我们的网格有许多分隔线,第一条线的起始点与文档书写模式相关。在中文与英文中,第一条列分隔线(即网格边缘线)在网格的最左边,而第一条行分隔线在网格的最上面。而对于阿拉伯语,第一条列分隔线在网格的最右边,因为阿拉伯文是从右往左书写的。

    我们根据这些分隔线来放置元素,通过以下属性来指定从那条线开始到哪条线结束。

    grid-column-start 
    
    grid-column-end 
    
    grid-row-start 
    
    grid-row-end 
    

    这些属性的值均为分隔线序号,你也可以用以下缩写形式来同时指定开始与结束的线。

    grid-column
    
    grid-row
    

    注意开始与结束的线的序号要使用/符号分开

    注意:你也可以用-1来定位到最后一条列分隔线或是行分隔线,并且可以用负数来指定倒数的某一条分隔线。但是这只能用于显式网格,对于隐式网格-1不一定能定位到最后一条分隔线。

    使用grid-template-areas属性放置元素

    另一种往网格放元素的方式是用grid-template-areas属性,并且你要命名一些元素并在属性中使用这些名字作为一个区域。

    .container {
      display: grid;
      grid-template-areas:
          "header header"
          "sidebar content"
          "footer footer";
      grid-template-columns: 1fr 3fr;
      grid-gap: 20px;
    }
    
    header {
      grid-area: header;
    }
    
    article {
      grid-area: content;
    }
    
    aside {
      grid-area: sidebar;
    }
    
    footer {
      grid-area: footer;
    }
    

    grid-template-areas属性的使用规则如下:

    1、你需要填满网格的每个格子

    2、对于某个横跨多个格子的元素,重复写上那个元素grid-area属性定义的区域名字

    3、所有名字只能出现在一个连续的区域,不能在不同的位置出现

    4、一个连续的区域必须是一个矩形

    5、使用.符号,让一个格子留空

    一个用CSS网格实现的网格排版框架

    网格排版框架一般由12到16列的网格构成,你可以用CSS网格系统直接实现而不需要任何第三方的工具

    在包含了12列网格的容器中,我们暂时可以先用基于线的元素放置模式来将我们的内容放到这个12列的网格中。

    header {
      grid-column: 1 / 13;
      grid-row: 1;
    }
    
    article {
      grid-column: 4 / 13;
      grid-row: 2;
    }
    
    aside {
      grid-column: 1 / 4;
      grid-row: 2;
    }
    
    footer {
      grid-column: 1 / 13;
      grid-row: 3;
    }
    

    浮动

    参考文档

    浮动的背景知识

    最初,引入 float 属性是为了能让 web 开发人员实现简单的布局,包括在一列文本中浮动的图像,文字环绕在它的左边或右边。

    浮动曾被用来实现整个网站页面的布局,它使信息列得以横向排列(默认的设定则是按照这些列在源代码中出现的顺序纵向排列)。目前出现了更新更好的页面布局技术,所以使用浮动来进行页面布局应被看作传统的布局方法。

    文字环绕

    img {
      float: left;
      margin-right: 30px;
    }
    

    让我们考虑一下浮动是如何工作的——浮动元素 (这个例子中的<img> 元素)会脱离正常的文档布局流,并吸附到其父容器的左边。在正常布局中位于该浮动元素之下的内容,此时会围绕着浮动元素,填满其右侧的空间。

    注意浮动内容仍然遵循盒子模型诸如外边距和边界。我们设置一下图片右侧的外边距就能阻止右侧的文字紧贴着图片。

    向右浮动的内容是一样的效果,只是反过来了——浮动元素会吸附到右边,而其他内容将从左侧环绕它。

    首字下沉

    p::first-letter {
      font-size: 3em;
      border: 1px solid black;
      background: red;
      float: left;
      padding: 2px;
      margin-right: 4px;
    }
    

    第一个字母后面的其余部分是浮动的

    多列浮动布局

    两列布局

    在这里我们设置了他们的父亲的宽度的48% —— 这总计96%,留下我们4%自由作为两列之间的沟槽,给内容一些空间间隙。现在我们只需要浮动列,像这样:

    div:nth-of-type(1) {
      width: 48%;
      float: left;
    }
    
    div:nth-of-type(2) {
      width: 48%;
      float: right;
    }
    

    你会注意到,我们所有列使用宽度百分比——这是一个很好的策略,因为它创建一个流式布局(liquid layout),一种调整为不同的屏幕尺寸,并在较小的屏幕尺寸下保持相同的列宽度比例。

    另一种选择是将宽度设置为一个固定的单位如rem或像素,或者通过删除max-width 声明来转换您自己的示例,并改变各个宽度。这就是固定宽度布局(fixed-width layout)——如果您现在调整浏览器大小,您将看到布局不再调整以适应视图宽度,在尺寸更小时您将需要滚动来查看它的全部。

    三列布局
    
    div:nth-of-type(1) {
      width: 36%;
      float: left;
    }
    
    div:nth-of-type(2) {
      width: 30%;
      float: left;
      margin-left: 4%;
    }
    
    div:nth-of-type(3) {
      width: 26%;
      float: right;
    }
    

    为了让它放到合适的位置我们已经把它放在左边了;我们还给了它一个4%的 margin-left,来在第一和第二列之间拉开一段距离。我们设置了列的宽度以便它们都能匹配——36% + 30% + 4% + 26% = 96%,在第二和第三列之间有4%的空间。(这个空间总是出现在向左浮动的第二列和向右浮动的第三列之间。)

    清除浮动

    所有在浮动下面的自身不浮动的内容都将围绕浮动元素进行包装,如果没有处理这些元素,就会变得很糟糕。

    幸运的是,有一种简单的方法可以解决这个问题—— clear 属性。当你把这个应用到一个元素上时,它主要意味着"此处停止浮动"——这个元素和源码中后面的元素将不浮动,除非您稍后将一个新的float声明应用到此后的另一个元素。

    clear 可以取三个值:

    left
      停止任何活动的左浮动
    
    right
      停止任何活动的右浮动
    
    both
      停止任何活动的左右浮动
    

    浮动问题

    整个宽度可能难以计算

    到目前为止,我们的例子是没有应用样式的浮动框——这很容易。当你开始给这些框加上样式时,比如添加背景、外边距、内边距等等,问题就来了。

    由于内边距和边界引入的额外宽度,一行容纳不下三列了,因此第三列下降到另外两列之下。

    有两个方法可以解决问题,最好的方法是给你的html加上下面的css。

    * {
      box-sizing: border-box;
    }
    

    box-sizing 通过更改盒模型来拯救我们,盒子的宽度取值为 content + padding + border,而不仅是之前的content——所以当增加内边距或边界的宽度时,不会使盒子更宽——而是会使内容调整得更窄。

    浮动的元素存在于正常的文档布局流之外,在某些方面的行为相当奇怪:

    1. 首先,他们在父元素中所占的面积的有效高度为0
  • 其次,非浮动元素的外边距不能用于它们和浮动元素之间来创建空间
  • 所以,让我们解决这个! 首先,在HTML的代码里添加新的<div> 元素,位于在<footer>标签的上方:

    <div class="clearfix"></div>
    
    .clearfix {
      clear: both;
    }
    

    我们的页脚现在有一个很好的顶部外边距,但也有另一个问题——clearfix div 背景、内边距和边界与我们的列和页脚相同!为了解决这个问题,让我们先给每个列块一个类( class )column:

    <div class="column">
      ...
    </div>
    

    现在让我们改变应用盒子样式的规则到这些块和页脚,这样只有列块被样式化:

    .column, footer {
      padding: 1%;
      border: 2px solid black;
      background-color: red;
    }
    
    浮动项目的背景高度

    另一个问题是列高度是不同的—— 如果列都是相同的高度,它看起来会更好。

    我们可以通过给所有的列固定height 来解决这个问题

    .column {
      height: 550px;
    }
    

    然而在许多情况下这并不理想——它使设计呆板。如果你能保证列中总是有相同数量的内容,这是可以的,但这并不总是如此——在很多类型的网站上,内容也会定期更改。

    你也可以考虑:

    1、将这些列的背景颜色设置为父元素的背景颜色,这样您就不会看到高度是不同的。这是目前最好的选择。

    2、将它们设置为固定的高度,并使overflow 属性使得内容滚动

    3、使用一种叫做伪列(faux columns)的技术——这包括将背景(和边界)从实际的列中提取出来,并在列的父元素上画一个伪造的背景,看起来像列的背景一样。不幸的是,这将无法处理列边界。

    清除浮动会变复杂

    当布局变得更加复杂清理(clearing)也会变得更加复杂。你需要确保所有的浮动都能尽快清除,以避免它们给下方的内容制造麻烦。如果您没有一个方便的容器来进行清理,那么在必要的时候使用clearfix块。

    定位

    参考文档

    文档流

    首先,围绕元素内容添加任何内边距、边界和外边距来布置单个元素盒子——这就是 盒模型。默认情况下,块级元素的内容宽度是其父元素的宽度的100%,并且与其内容一样高。内联元素高宽与他们的内容高宽一样。您不能对内联元素设置宽度或高度——它们只是位于块级元素的内容中。 如果要以这种方式控制内联元素的大小,则需要将其设置为类似块级元素 display: block;

    这只是解释了单个元素,但是元素相互之间如何交互呢? 正常的布局流是将元素放置在浏览器视口内的系统。默认情况下,块级元素在视口中垂直布局——每个都将显示在上一个元素下面的新行上,并且它们的外边距将分隔开它们。如果两个相邻元素都在其上设置外边距,并且两个外边距接触,则两个外边距中的较大者保留,较小的一个消失——这叫外边距折叠

    内联元素表现不一样——它们不会出现在新行上;相反,它们互相之间以及任何相邻(或被包裹)的文本内容位于同一行上,只要在父块级元素的宽度内有空间可以这样做。如果没有空间,那么溢流的文本或元素将向下移动到新行。

    介绍定位

    静态定位

    静态定位是每个元素获取的默认值——它只是意味着“将元素放入它在文档布局流中的正常位置

    .positioned {
      position: static;
    }
    
    相对定位

    相对定位与静态定位非常相似,占据在正常的文档流中,除了你仍然可以修改它的最终位置,包括让它与页面上的其他元素重叠。

    .positioned {
      position: relative;
    }
    

    如果您在此阶段保存并刷新,则结果根本不会发生变化。那么如何修改元素的位置呢? 您需要使用topbottomleftright属性

    介绍 top, bottom, left, right

    top, bottom, left, 和 right 来精确指定要将定位元素移动到的位置

    .positioned {
      position: relative;
      top: 30px;
      left: 30px;
    }
    

    注意:这些属性的值可以采用逻辑上期望的任何单位 ——pxmmrems等。

    为什么它移动到底部和右边,但我们指定顶部和左边? 听起来不合逻辑,但这只是相对定位工作的方式——你需要考虑一个看不见的力,推动定位的盒子的一侧,移动它的相反方向。 所以例如,如果你指定 top: 30px;一个力推动框的顶部,使它向下移动30px。

    绝对定位
    .positioned {
      position: absolute;
      top: 30px;
      left: 30px;
    }
    

    绝对定位的元素不再存在于正常文档布局流中。相反,它坐在它自己的层独立于一切。

    第二,注意元素的位置已经改变——这是因为topbottomleftright以不同的方式在绝对定位。 它们指定元素应距离每个包含元素的边的距离,而不是指定元素应该移入的方向。 所以在这种情况下,我们说的绝对定位元素应该位于从“包含元素”的顶部30px,从左边30px。

    注意:如果需要,您可以使用top,bottom,left和right 调整元素大小。 尝试设置 top: 0; bottom: 0; left: 0; right: 0;margin: 0;

    定位上下文

    哪个元素是绝对定位元素的“包含元素“?这取决于绝对定位元素的父元素的position属性。

    如果所有的父元素都没有显式地定义position属性,那么所有的父元素默认情况下position属性都是static。结果,绝对定位元素会被包含在初始块容器中。这个初始块容器有着和浏览器视口一样的尺寸,并且<html>元素也被包含在这个容器里面。简单来说,绝对定位元素会被放在<html>元素的外面,并且根据浏览器视口来定位。

    绝对定位元素在HTML源代码中,是被放在<body>中的,但是在最终的布局里面,它离页面(而不是<body>)的左边界、上边界有30px的距离。我们可以改变定位上下文 —— 绝对定位的元素的相对位置元素。通过设置其中一个父元素的定位属性 —— 也就是包含绝对定位元素的那个元素(如果要设置绝对定位元素的相对元素,那么这个元素一定要包含绝对定位元素)。 为了演示这一点,将以下声明添加到您的body规则中:

    body {
      position: relative;
    }
    

    定位的元素现在相对于<body>元素。

    介绍 z-index

    当元素开始重叠,什么决定哪些元素出现在其他元素的顶部? 在我们已经看到的示例中,我们在定位上下文中只有一个定位的元素,它出现在顶部,因为定位的元素胜过未定位的元素。 当我们有不止一个的时候呢?

    您可以更改堆叠顺序吗?是的,您可以使用z-index属性。 “z-index”是对z轴的参考。你可以从源代码中的上一点回想一下,我们使用水平(x轴)和垂直(y轴)坐标来讨论网页,以确定像背景图像和阴影偏移之类的东西的位置。 (0,0)位于页面(或元素)的左上角,x和y轴跨页面向右和向下(适合从左到右的语言)。

    网页也有一个z轴:一条从屏幕表面到你的脸(或者在屏幕前面你喜欢的任何其他东西)的虚线。z-index 值影响定位元素位于该轴上的位置;正值将它们移动到堆栈上方,负值将它们向下移动到堆栈中。默认情况下,定位的元素都具有z-indexauto,实际上为0

    z-index: 1;
    

    请注意,z-index只接受无单位索引值;你不能指定你想要一个元素是Z轴上23像素—— 它不这样工作。 较高的值将高于较低的值,这取决于您使用的值。 使用2和3将产生与300和40000相同的效果。

    固定定位

    这与绝对定位的工作方式完全相同,只有一个主要区别:绝对定位固定元素是相对于 <html> 元素或其最近的定位祖先,而固定定位固定元素则是相对于浏览器视口本身

    h1 {
      position: fixed;
      top: 0;
      width: 500px;
      margin: 0 auto;
      background: white;
      padding: 10px;
    }
    

    top: 0;是要使它贴在屏幕的顶部;我们然后给出标题与内容列相同的宽度,并使用可靠的老技巧 margin: 0 auto; 使它居中。 然后我们给它一个白色背景和一些内边距,所以内容将不会在它下面可见。

    粘性定位

    还有一个可用的位置值称为 position: sticky,比起其他位置值要新一些。它基本上是相对位置和固定位置的混合体,它允许被定位的元素表现得像相对定位一样,直到它滚动到某个阈值点(例如,从视口顶部起1​​0像素)为止,此后它就变得固定了。例如,它可用于使导航栏随页面滚动直到特定点,然后粘贴在页面顶部。

    .positioned {
      position: sticky;
    }
    

    粘性定位的另一种有趣且常用的用法,是创建一个滚动索引页面。在此页面上,不同的标题会停留在页面顶部

    在正常布局流中,<dt>元素将随内容滚动。当我们在<dt>元素上添加position: sticky,并将top的值设置为0,当标题滚动到视口的顶部时,支持此属性的浏览器会将标题粘贴到那个位置。随后,每个后续标题将替换前一个标题,直到它向上滚动到该位置。

    dt {
      background-color: black;
      color: white;
      padding: 10px;
      position: sticky;
      top: 0;
      left: 0;
      margin: 1em 0;
    }
    

    多列布局

    参考文档

    一个简单的例子

    多列布局,通常也简写为 multicol

    我们从一些很简单的HTML开始; 用带有类 container 的简单包装,里面是标题和一些段落。

    带有 .container<div> 将成为我们 multicol 的容器。 通过这两个属性开启 multicol column-count 或者 column-widthcolumn-count 将创建指定数量的列,所以如果你把下面的CSS加到样式表里让后重载入页面,你将得到3列:

    .container {
      column-count: 3;
    }
    

    创建的这些列具有弹性的宽度 — 由浏览器计算出每一列分配多少空间。

    像下面这样使用 column-width 更改CSS。浏览器将按照你指定的宽度尽可能多的创建列;任何剩余的空间之后会被现有的列平分。 这意味着你可能无法期望得到你指定宽度,除非容器的宽度刚好可以被你指定的宽度除尽。

    .container {
      column-width: 200px;
    }
    

    给多列增加样式

    Multicol 创建的列无法单独的设定样式。 不存在让单独某一列比其他列更大的方法,同样无法为某一特定的列设置独特的背景色、文本颜色。你有两个机会改变列的样式:

    1、使用 column-gap 改变列间间隙。

    2、用 column-rule 在列间加入一条分割线。

    以上面的代码为例,增加 column-gap 属性可以更改列间间隙:

    .container {
      column-width: 200px;
      column-gap: 20px;
    }
    

    你可以尝试不同的值 — 该属性接受任何长度单位。现在再加入 column-rule。和你之前遇到的 border 属性类似, column-rulecolumn-rule-colorcolumn-rule-style的缩写,接受同 border 一样的单位。

    .container {
      column-count: 3;
      column-gap: 20px;
      column-rule: 4px dotted rgb(79, 185, 227);
    }
    

    值得一提的是这条分割线本身并不占用宽度。它置于用 column-gap 创建的间隙内。如果需要更多空间,你需要增加 column-gap 的值。

    列与内容折断

    在多列布局中,当内容过多时,在切换列的时候,有些内容块会出现跨列的情况,那么我们可以控制multicol 和多页媒体中的内容拆分、折断。比如, 在规则 .card 上添加属性break-inside,并设值 avoid.card 是标题和文本的容器,我们不想拆开这个盒子。

    现阶段,增加旧属性 page-break-inside: avoid 能够获得更好的浏览器支持。

    .card {
      break-inside: avoid;
      page-break-inside: avoid;
      background-color: rgb(207,232,220);
      border: 2px solid rgb(79,185,227);
      padding: 10px;
      margin: 0 0 1em 0;
    }
    

    响应式布局

    参考文档

    随着人们使用的屏幕尺寸的种类越来越多,出现了响应式网页设计的概念(responsive web design,RWD),RWD指的是允许Web页面适应不同屏幕宽度因素等,进行布局和外观的调整的一系列实践。这是改变我们设计多设备网页的方式的思想

    历史上的网站布局

    在历史上的某个时刻,设计网站时,你有两个选择:

    1、你可以创建一个“液态”站点,它会拉伸以充满整个浏览器视窗;

    2、或者是一个“固定宽度”站点,它有一个以像素计的固定尺寸。

    这两种途径会倾向于导致它的表现只有在设计者的屏幕上才是最佳的!液态站点导致了小屏幕上的设计会挤成一团,以及大屏幕上难以阅读的很长的行长度。

    固定宽度站点的一个可能的后果是,在比站点更窄的屏幕上会出现一个水平滚动条,在大屏幕上的设计边缘还会有许多空白。

    响应式设计之前的灵活布局

    有一种可以创造适应多种屏幕分辨率的设计的方式。这种方式需要JavaScript来探测屏幕的分辨率,载入恰当的CSS。

    还有一种描述并标准化了可变站点建立的不同方式,试图在充满屏幕和完全保持固定尺寸之间找到最佳平衡。

    响应式设计

    响应式设计是三种技术的混合使用。

    1、第一个是液态网格

    2、第二个是液态图像。通过使用相当简单的将设置max-width属性设置为100%的技术,图像可以在包含它们的列变得比图像原始尺寸窄的时候,缩放得更小,但总不会变得更大。这使得图像可以被缩放,以被放到一个灵活尺寸的列,而不是溢出出去,同时也不会在列宽于图像的时候,使图像变得太大以至于画质变得粗糙。

    3、第三个是媒体查询。媒体查询使以往Cameron Adams探讨过的、由JavaScript实现的布局类型切换,可以只使用CSS实现。和所有尺寸的屏幕都使用一种布局不同的是,布局是可以改变的:侧栏可以在小屏幕上重新布局,而替代用的导航栏也可以显示出来。

    需要你理解的很重要的一点是响应式Web设计不是单独的技术,它是描述Web设计的一种方式、或者是一组最佳实践的一个词,它是用来建立可以响应查看内容的设备的样式的一个词。

    媒体查询

    媒介查询允许我们运行一系列测试,例如用户的屏幕是否大于某个宽度或者某个分辨率,并将CSS选择性地适应用户的需要应用在样式化页面上。

    例如,下面的媒体查询进行测试,以知晓当前的Web页面是否被展示为屏幕媒体(也就是说不是印刷文档),且视口至少有800像素宽。用于.container选择器的CSS将只会在这两件前提存在的情况下应用。

    @media screen and (min-width: 800px) {
      .container {
        margin: 1em 2em;
      }
    } 
    

    你可以在一张样式表上加入多条媒体查询,调整整个页面或者部分页面以达到适应各式屏幕尺寸的最佳效果。媒体查询,以及样式改变时的点,被叫做断点(breakpoints)。

    使用媒体查询时的一种通用方式是,为窄屏设备(例如移动设备)创建一个简单的单栏布局,然后检查是否是大些的屏幕,在你知道你有足够容纳的屏幕宽度的时候,开始采用一种多栏的布局 。这经常被描述为移动优先设计。

    灵活网格

    响应式站点不只是在断点之间改变它们的布局,它们是建立在灵活网格上的。一个灵活网格意味着你不需要适配每个可能使用的设备尺寸,然后为其建立一个精确到像素级的适配布局。那种方式在现存有如此多种不同大小设备的前提下是不可能实现的,比如至少在台式机上,人们并不总是让他们的浏览器窗口最大化的。

    使用灵活网格,你只需要加进去一个断点,在内容看起来不齐整的时候改变设计。例如如果一行随着屏幕大小增加而增长得不可读的长,或者是一个盒子在变窄时把每行的两个单词挤到一起。

    灵活浮动布局是这样实现的,让每个元素都有一个作为宽度的百分数(通过使用像素并把布局转化为百分数的方式设计),而且确保整个布局的和不会超过100%。

    例如如果我们的预期栏尺寸为60像素,而且它所在的上下文(或者容器)为960像素,用 60 除以 960,得到我们能够使用在我们的CSS上的值。

    .col {
      width: 6.25%; /* 60 / 960 = 0.0625 */
    } 
    

    现代布局技术

    多列布局

    即当你指定一个column-count的时候,这意指你希望把你的内容分成多少列。浏览器之后会算出这些列的大小,这是一个随着屏幕尺寸变化的尺寸。

    .container {
      column-count: 3;
    } 
    

    如果你指定column-width的话,你是在指定一个最小宽度。浏览器会尽可能多数量地创建这一宽度的列,只要它们可以恰当地放进容器里面,然后将所有列之间的剩余空间共享出去。因而列的数量会随着空间的多少而改变。

    .container {
      column-width: 10em;
    } 
    
    弹性盒子

    在弹性盒子中,初始的行为是,弹性的物件将参照容器里面的空间的大小,缩小和分布物件之间的空间。通过更改flex-growflex-shrink的值,你可以指示在物件遇到周围有更多或者更少的空间的情况下,你所期望的物件表现。

    使用了flex: 1的简写,每个可伸缩物件将会占据一份可伸缩容器中相等大小的空间。

    .container {
      display: flex;
    }
    
    .item {
      flex: 1;
    } 
    
    网格

    fr单位许可了跨网格轨道可用空间的分布。下面的示例创建了一个有着3个大小为1fr的轨道的网格容器。这会创建三个列轨道,每个占据了容器中可用空间的一部分。

    .container {
      display: grid;
      grid-template-columns: 1fr 1fr 1fr;
    } 
    

    响应式图像

    基本来说,你可以用一张有着所需最大尺寸的图像。然后缩放它。这仍然是今日所使用的一种方式,而且在大多数样式表里面,你在某些地方可以找到下面的CSS:

    img {
      max-width: 100%:
    } 
    

    这种方式有显然的弊端。图像有可能会显示得比它的原始尺寸小很多,以至于浪费带宽——一个移动端用户会下载几倍于他们在浏览器窗口中实际看到的大小的图像。此外,你可能不想在移动端和桌面端有相同的图像宽高比例。例如,在移动端,方形图像的表现会很好,但是在桌面端显示同样的内容则应用宽图像。或者,认识到移动端更小尺寸的图像的你也许会希望同时展示一张不同的图像,一张在小一点的屏幕上更容易理解的图像。这些东西不能简单通过缩放图像解决。

    响应式图像,使用了<picture>元素和<img>srcsetsizes 特性,解决了这两个问题。你可以提供附带着“提示”(描述图像最适合的屏幕尺寸和分辨率的元数据)的多种尺寸,浏览器将会选择对设备最合适的图像,以确保用户下载尺寸适合他们使用的设备的图像。

    你也可以给用于不同尺寸的图像做“艺术指导”,为不同的屏幕尺寸提供不同的图像裁切或者完全不同的图像。

    响应式排版

    本质上讲,这描述了根据屏幕真实使用范围的多少,在媒体查询的同时改变字体大小。

    我们只想在大些的屏幕上有这么个超大的标题,那我们先弄个小点的标题,再使用媒体查询,在我们知道用户使用至少1200px的屏幕的时候,拿大些的尺寸覆写它。

    html {
      font-size: 1em;
    }
    
    h1 {
      font-size: 2rem;
    }
    
    @media (min-width: 1200px) {
      h1 {
        font-size: 4rem;
      }
    } 
    

    正如这种排版方式展示的这样,你不需要让媒介查询只能改变页面的布局。它们也能用来调节每个元素,让它们在别的大小的屏幕上更加可用或者更具吸引力。

    使用视口单位实现响应式排版

    一个有趣的方式是使用视口单位vw来实现响应式排版。1vw等同于视口宽度的百分之一,即如果你用vw来设定字体大小的话,字体的大小将总是随视口的大小进行改变。

    h1 {
      font-size: 6vw;
    }
    

    问题在于,当做上面的事情的时候,因为文本总是随着视口的大小改变大小,用户失去了放缩任何使用vw单位的文本的能力。所以你永远都不要只用viewport单位设定文本。

    这里有一个解决方法,它使用了calc(),如果你将vw单位加到了使用固定大小(例如em或者rem)的值组,那么文本仍然是可放缩的。基本来说,是vw加在了放缩后的值上。

    h1 {
      font-size: calc(1.5rem + 3vw);
    }
    

    视口元标签

    在一个响应式页面的HTML源代码,你通常将会在文档的<head>看到下面的<meta>标签。

    <meta name="viewport" content="width=device-width,initial-scale=1">
    

    这个元标签告诉移动端浏览器,它们应该将视口宽度设定为设备的宽度,将文档放大到其预期大小的100%,在移动端以你所希望的为移动优化的大小展示文档。

    你的带断点和媒介查询的响应式设计不会在移动端浏览器上像预期那样工作。如果你有个窄屏布局,在480像素及以下的视口宽度下生效,但是视口是按960像素设定的,你将不会在移动端看到你的窄屏布局。通过设定width=device-width,你用设备的实际宽度覆写了苹果默认的width=960px,然后你的媒介查询就会像预期那样生效。

    所以你应该在你的文档头部总是包含上面那行HTML。

    和视口元标签一起,你可以使用另外几个设定,但大体说来,上面那行就是你想要使用的。

    initial-scale
      设定了页面的初始缩放,我们设定为1。
    
    height
      特别为视口设定一个高度。
    
    minimum-scale
      设定最小缩放级别。
    
    maximum-scale
      设定最大缩放级别。
    
    user-scalable
      如果设为no的话阻止缩放。
    

    你应该避免使用minimum-scalemaximum-scale,尤其是将user-scalable设为no。用户应该有权力尽可能大或小地进行缩放,阻止这种做法会引起访问性问题。

    媒体查询

    参考文档

    媒体查询基础

    最简单的媒体查询语法看起来是像这样的:

    @media 媒体类型 and (媒体特征规则) {
      /* CSS规则 */
    }
    

    它由以下部分组成:

    1. 一个媒体类型,告诉浏览器这段代码是用在什么类型的媒体上的(例如印刷品或者屏幕);
  • 一个媒体特征规则,是一个被包含的CSS生效所需的规则或者测试;
  • 一组CSS规则,会在测试通过且媒体类型正确的时候应用。
  • 媒体类型

    你可以指定的媒体类型为:

    all
    
    print
    
    screen
    
    speech
    

    备注:媒体类型是可选的,如果你没有在媒体查询中指示一个媒体类型的话,那么媒体查询默认会设为用于全部媒体类型。

    下面的媒体查询将会在页面被打印的时候把body设定为只有12pt大小。当页面在浏览器中载入的时候,它将不会生效。

    @media print {
        body {
            font-size: 12pt;
        }
    }
    
    媒体特征规则

    在指定了类型以后,你可以用一条规则指向一种媒体特征。

    宽和高

    我们可以使用min-width、max-width和width媒体特征,在视口宽度大于或者小于某个大小——或者是恰好处于某个大小——的时候,应用CSS。这些特征是用来创建响应不同屏幕大小的布局的。例如,要想在视口正好是600像素的时候,让body的文本变为红色,你可能会使用下面的媒体查询。

    @media screen and (width: 600px) {
        body {
            color: red;
        }
    }
    

    width(和height)媒体特征可以以数值范围使用,于是就有了min-或者max-的前缀,指示所给的值是最小值还是最大值。例如,要让颜色在视口窄于400像素的时候变成蓝色的话,可以用max-width

    @media screen and (max-width: 400px) {
        body {
            color: blue;
        }
    }
    
    朝向

    一个受到良好支持的媒体特征是orientation,我们可以用它测得竖放(portrait mode)和横放(landscape mode)模式。要在设备处于横向的时候改变body文本颜色的话,可使用下面的媒体查询。

    @media (orientation: landscape) {
        body {
            color: rebeccapurple;
        }
    }
    
    使用指点设备

    作为四级规范的一部分,hover媒体特征被引入了进来。这种特征意味着你可以测试用户是否能在一个元素上悬浮,这也基本就是说他们正在使用某种指点设备(指点设备如鼠标、数位板等),因为触摸屏和键盘导航是没法实现悬浮的。

    @media (hover: hover) {
        body {
            color: rebeccapurple;
        }
    }
    

    如果我们知道用户不能悬浮的话,我们可以默认显示一些交互功能。对于能够悬浮的用户,我们可以选择在悬浮在链接上的时候,让这些功能可用。

    还是在四级规范中,出现了pointer媒体特征。它可取三个值:nonefinecoarse

    fine
      指针是类似于鼠标或者触控板的东西,它让用户可以精确指向一片小区域。
    
    coarse
      指针是你在触摸屏上的手指。
    
    none
      值意味着,用户没有指点设备,也许是他们正只使用键盘导航,或者是语音命令。
    

    使用pointer可以在用户使用屏幕时进行交互时,帮你更好地设计响应这种交互的界面。例如,如果你知道用户正在用触摸屏设备交互的时候,你可以建立更大的响应区域。

    更复杂的媒体查询

    有了所有不同的可用的媒体查询,你可能想要把它们混合起来,或者建立查询列表——其中的任何一个都可以匹配生效。

    媒体查询中的“与”逻辑

    为了混合媒体特征,你可以以与在上面使用and很相同的方式,用and来混合媒体类型和特征。例如,我们可能会想要测得min-widthorientation,使得body的文字只会在视口至少为400像素宽,且设备横放时变为蓝色。

    @media screen and (min-width: 400px) and (orientation: landscape) {
        body {
            color: blue;
        }
    }
    
    媒体查询中的“或”逻辑

    如果你有一组查询,且要其中的任何一个都可以匹配的话,那么你可以使用 逗号 分开这些查询。在下面的示例中,文本会在视口至少为400像素宽的时候或者设备处于横放状态的时候变为蓝色。如果其中的任何一项成立,那么查询就匹配上了。

    @media screen and (min-width: 400px), screen and (orientation: landscape) {
        body {
            color: blue;
        }
    }
    
    媒体查询中的“非”逻辑

    你可以用not操作符让整个媒体查询失效。这就直接反转了整个媒体查询的含义。因而在下面的例子中,文本只会在朝向为竖着的时候变成蓝色。

    @media not all and (orientation: landscape) {
        body {
            color: blue;
        }
    }
    

    怎么选择断点

    这也就是说,将所有的设计用在特定的尺寸上以外,一个更好的方法是在内容某种程度上开始变得混乱的时候,改变尺寸的设计。也许线太长了,或者盒子状的外侧栏开始挤在一起而难以阅读。那就是你想要使用媒体查询,将设计变得对剩余可用空间更加友好的时候。这种方式意味着,它无关使用的设备的确切大小,每个范围都被照顾到了。引入媒体查询的点就叫做断点。

    移动优先的响应式设计

    你可以采用两种方式实现响应式设计。你可以从桌面或者最宽的视图开始,然后随着视口变得越来越小,加上断点,把物件挪开;你也可以从最小的视图开始,随着视口变得越来越大,增添布局内容。第二种方式被叫做移动优先的响应式设计,很多时候是最值得仿效的做法。

    用在最小的那个设备上的视图很多时候都是一个简单的单列内容,很像正常文本流显示的那样。这意味着,你很可能不需要为小设备做多少布局设计,合适地安排下你的源代码,默认情况下你就可以得到可读的布局。

    你真的需要媒体查询吗

    弹性盒、网格和多栏布局都给了你建立可伸缩的甚至是响应式组件的方式,而不需要媒体查询。这些布局方式能否在不加入媒体查询的时候实现你想要的设计,总是值得考虑的一件事。例如,你可能想要一组卡片,至少为二百像素宽,并在主文章里尽可能多地放下这些二百像素的卡片。这可以用网格布局实现,而完全不使用媒体查询。

    你可能根本不需要它!但是,实践中你会发现,由媒体查询改进的现代布局方式的恰当使用,将会产生最佳效果。

    传统的布局方法

    参考文档

    两列布局

    body {
      width: 90%;
      max-width: 900px;
      margin: 0 auto;
    }
    

    body将会占据90%的视口宽度,直到达到900像素,在这种情况下,它将固定并保持在视口正中。 默认情况下,它的子项( <h1>和两个 <div>)将会达到正文宽度的100%。如果我们希望两个<div>,一个浮在窗口的一边,另一个浮动在另一边的话, 我们需要将它们的宽度设置为其父元素的100%或者更小,以便他们可以并排放置。将下面的代码加在CSS的底部:

    div:nth-of-type(1) {
      width: 48%;
    }
    
    div:nth-of-type(2) {
      width: 48%;
    }
    

    这里我们将它们都设置为了父元素宽度的48%——总共是96%,在两栏之间留4%的空隙,为它们提供一些宽松的空间。现在我们只需要将让列浮动,像这样:

    div:nth-of-type(1) {
      width: 48%;
      float: left;
    }
    
    div:nth-of-type(2) {
      width: 48%;
      float: right;
    }
    

    你有没有注意到我们在宽度的表示上都用的是百分比——这是一个很好的策略,这创建了一个流动布局(liquid layout),能够适应不同的屏幕大小,在小一些的屏幕上也能使列保持一样的比例。

    创建简单的传统网格框架

    一个简单的固定宽度网格
    <div class="wrapper">
      <div class="row">
        <div class="col">1</div>
        <div class="col">2</div>
        <div class="col">3</div>
        <div class="col">4</div>
        <div class="col">5</div>
        <div class="col">6</div>
        <div class="col">7</div>
        <div class="col">8</div>
        <div class="col">9</div>
        <div class="col">10</div>
        <div class="col">11</div>
        <div class="col">12</div>
      </div>
      <div class="row">
        <div class="col span1">13</div>
        <div class="col span6">14</div>
        <div class="col span3">15</div>
        <div class="col span2">16</div>
      </div>
    </div>
    

    我们的目标是把它变成一个有两行十二列的演示网格——第一行显示各列的大小,第二行显示网格上不同大小的区域。

    <style>中,加入下面的代码:

    /* 设置为 IE盒模型,即宽高不变 */
    * {
      box-sizing: border-box;
    }
    
    /* 总的宽度变为980像素,且整体居中 */
    body {
      width: 980px;
      margin: 0 auto;
    }
    
    /* 使容器右侧的内边距为20像素,这样给我们留出960像素可以放置列和它们的间隔 */
    .wrapper {
      padding-right: 20px;
    }
    
    /* 使用包装了网格每行的列容器,清除网格中每行的浮动。意味着我们不用在每行上都填充12列元素。行与行之间不会互相干扰,并保持分隔 */
    .row {
      clear: both;
    }
    
    /* 让它向左浮动,给它设置20像素的margin-left来实现一个间隔,再设置60像素的width,并设置背景颜色 */
    .col {
      float: left;
      margin-left: 20px;
      width: 60px;
      background: rgb(255, 150, 150);
    }
    
    /* 在下方的规则中可以选择跨多行,这样需要在html文件中添加如下类 */
    /* 两列宽 (120px) 加上一个间隔的宽度 (20px) */
    .col.span2 { width: 140px; }
    /* 三列宽 (180px) 加上一个间隔的宽度 (40px) */
    .col.span3 { width: 220px; }
    /* 如下同理... */
    .col.span4 { width: 300px; }
    .col.span5 { width: 380px; }
    .col.span6 { width: 460px; }
    .col.span7 { width: 540px; }
    .col.span8 { width: 620px; }
    .col.span9 { width: 700px; }
    .col.span10 { width: 780px; }
    .col.span11 { width: 860px; }
    .col.span12 { width: 940px; }
    
    创建液态网格

    固定列宽网格表现的不错,但是它长度固定。 我们实际却想要一个弹性(流体)的网格,它可以随着浏览器的视口(viewport)大小的变化自动伸缩。为了达成这个目标,我们需要把相应的像素的长度变为百分比长度。

    把固定宽度转为伸缩的基于百分比宽度的算式在下面:

    目标列宽 / 上下文(或者叫容器宽度) = 目标比例
    

    在我们的列宽里,我们的目标列长度是60像素,我们的上下文是960像素的包装。我们可以这么计算百分比:

    60 / 960 = 0.0625
    

    然后我们挪动小数点两位,得到百分数6.25%。所以在CSS里面,我们可以用6.25%代替60像素。

    我们需要同样这么算间隔:

    20 / 960 = 0.02083333333
    

    所以我们需要用2.08333333%代替.colmargin-left的20像素,和.wrapperpadding-right的20像素。(详情见上一小章)

    使用calc()函数的更简单计算

    我们网格里跨越超过一列的列,它的总长是6.45%乘跨越的列数加 2.08333333%,乘间隔数(间隔数总等于行数减一)。calc() 函数允许我们就在宽度值里面这么计算,所以对跨越4列的列我们可以这么算:

    .col.span4 {
      width: calc((6.25%*4) + (2.08333333%*3));
    }
    
    语义vs.“无语义”网格系统

    在标记中添加类以定义布局,意味着您的内容和标记与您的可视化表示相关联。你将会偶尔听到,这种使用CSS类的方式,被描绘成“无语义”:描述了内容的外观,而不是描述内容的语义性的类的使用。这是我们的span2、span3等类所面临的情况。

    那么可以修改这些类名,例如将内容的类设置为 content

    .content {
      width: calc((6.25%*8) + (2.08333333%*7));
    }
    
    在我们的网格里启用偏移容器

    如果我们想在第一个容器前来个空列,或者容器之间来个空列,我们需要新建一个偏移类,为站点加上左外边距,来可见地推动网格。

    我们在CSS上搞一个类,它会给一个容器元素来个一列宽度的偏移。

    /* 这里的的两个间隙值是因为最左边还有一个内边距 */
    .offset-by-one {
      margin-left: calc(6.25% + (2.08333333%*2));
    }
    

    想要给一个容器的左边加个有一列宽的空白的话,你可以在容器上添加这个类。例如,如果你在HTML中有这个内容的时候:

    <!-- 
      原本跨了6列
     -->
    <div class="col span6">14</div>
    

    试着用下面的替换:

    <!-- 
      此时盒子向右移动了一列,并且盒子变为只跨5列
     -->
    <div class="col span5 offset-by-one">14</div>
    
    浮动网格的限制

    当你想用这个网格系统时,你得仔细看看你的总长是否正确,并且每行中的元素所横跨的列数不超过这一行可容纳的列数。

    由于浮动布局实现的方式,如果网格列的数目对与网格来说太大,在最后边的元素会跑到下一行去,搞坏了布局 。

    还要记住,如果元素内容比行宽,它会溢出,看起来一团糟。

    这个系统的最大限制是,它本质上是一维的。我们在处理列、让元素跨越列,但是处理不了行。如果不设置一个确定的高度,用老方法很难控制元素高。这个方法很不灵活 —它只有在你确定你的内容有个明确的高的情况下有用。

    弹性盒网格

    body {
      width: 90%;
      max-width: 980px;
      margin: 0 auto;
    }
    
    .wrapper {
      padding-right: 2.08333333%;
    }
    
    /* 把每行变成一个弹性容器 */
    .row {
      display: flex;
    }
    
    .col {
      margin-left: 2.08333333%;
      margin-bottom: 1em;
      width: 6.25%;
    /* 设定flex属性的第一个值(flex-grow)为1,这样我们的物件可以变大;
    第二个值(flex-shrink)为1,这样我们的物件可以缩小;
    第三个值(flex-basis)为auto。因为我们的元素的width被设定了, auto将会使用和flex-basis 值一样的宽度(即列的宽度相同) */
      flex: 1 1 auto;
      background: rgb(255,150,150);
    }
    

    弹性盒设计上是一维。它处理单个维度,行的或者列的。我们不能创建一个对行列严格要求的网格,意即如果我们要在我们的网格上使用弹性盒的话,我们仍然需要计算浮动布局的百分比。

    第三方网格系统

    让我们看下这些独立系统其中的一个,它阐释了利用网格框架工作的常见技术。我们将要使用的网格是Skeleton的一部分,它是一种简单的CSS框架。

    访问Skeleton网站以开始,选择“Download”下载ZIP文件。解压文件,把skeleton.css和normalize.css复制到一个新路径下。

    在HTML页面包含skeleton和normalize CSS,通过把以下内容加到文件头部的方式:

    <link href="normalize.css" rel="stylesheet">
    <link href="skeleton.css" rel="stylesheet">
    

    将以下内容添加到主体部分:

    <div class="container">
      <div class="row">
        <div class="col">1</div>
        <div class="col">2</div>
        <div class="col">3</div>
        <div class="col">4</div>
        <div class="col">5</div>
        <div class="col">6</div>
        <div class="col">7</div>
        <div class="col">8</div>
        <div class="col">9</div>
        <div class="col">10</div>
        <div class="col">11</div>
        <div class="col">12</div>
      </div>
      <div class="row">
        <div class="col">13</div>
        <div class="col">14</div>
        <div class="col">15</div>
        <div class="col">16</div>
      </div>
    </div>
    

    你可以看看skeleton.css文件里,CSS在我们应用这个类的时候是如何使用的。

    .container {
      position: relative;
      width: 100%;
      max-width: 960px;
    /* 用值为auto的左右外边距居中 */
      margin: 0 auto;
    /* 左边和右边还应用了20像素的内边距 */
      padding: 0 20px;
    /* 使得元素的内边距和边框将会被包含在整个width里面 */
      box-sizing: border-box;
    }
    

    以下类表示横跨3列:

    .three.columns { width: 22%; }
    

    支持旧浏览器

    参考文档

    在CSS中构建回滚

    如果浏览器器支持网格布局,它会显示网格视图,否则它会忽略display: grid相关的属性,使用浮动布局。

    * {box-sizing: border-box;}
    
    /* 如果容器支持网格布局,则变为网格布局 */
    .wrapper {
      background-color: rgb(79,185,227);
      padding: 10px;
      max-width: 400px;
      display: grid;
      grid-template-columns: 1fr 1fr 1fr;
    }
    
    /* 每个元素会浮动 */
    .item {
      float: left;
      border-radius: 5px;
      background-color: rgb(207,232,220);
      padding: 1em;
    }
    
    回滚方式

    浮动和清除:如果浮动和清除的物件变成了弹性或网格物件,浮动和清除属性不再影响布局。

    display: inline-block:这种方式能被用来建立列布局,如果一个物件被设为display: inline-block,但是之后变成了弹性或者网格物件,inline-block行为将会被忽略。

    display: table: 这种在这几节课的介绍中描述的建立CSS表格的方式可以被用作回滚。被设为CSS表格布局的物件将会在它们变为弹性或者网格物件的时候不再表现出这种行为。重要的是,被建立起来用于修复表格结构的匿名盒子没有被建立起来。

    Multiple-column Layout: 对于某些布局,你能用multi-col作为回滚。如果你的容器有任何一个column-*属性被定义,之后变成了网格容器,那么多列行为不会实现。

    作为网格的回滚的弹性盒: 弹性盒由于受到了IE10和IE11的支持,比网格有着更好的浏览器支持。不过,在这节课的稍后部分,你一定要看下旧浏览器对弹性盒相当参差不齐而且令人困惑的支持的相关信息。如果你把弹性容器做成了网格容器,任何应用到子元素的flex属性都会被忽略。

    特性查询

    特性查询允许你测试一个浏览器是否支持任何特定的一个CSS特性。这就是说,你可以写一些面向不支持某项特性的浏览器的CSS,然后检查以了解浏览器是否支持,如果支持的话就可以加进你的复杂布局了。

    如果我们向上面的示例中加入了一条特征查询,要是我们知道网格受到支持的话,我们可以用它把我们的物件宽度设定回auto

    * {box-sizing: border-box;}
    
    .wrapper {
      background-color: rgb(79,185,227);
      padding: 10px;
      max-width: 400px;
      display: grid;
      grid-template-columns: 1fr 1fr 1fr;
    }
    
    .item {
      float: left;
      border-radius: 5px;
      background-color: rgb(207,232,220);
      padding: 1em;
      width: 33.333%;
    }
    
    /* 特性查询 */
    @supports (display: grid) {
      .item {
          width: auto;
      }
    }
    
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宁静_致远_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值