CSS3布局笔记| 第五届字节跳动青训营

164 阅读12分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天

CSS3布局

1.Flex 布局

Flex 是 Flexible Box(弹性盒子)的缩写,意为“弹性布局”,用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为 Flex 布局。

div {
  display: flex;
}

行内元素也可以使用 Flex 布局

span {
  display: inline-flex;
}

Webkit 内核的浏览器,必须加上 -webkit 前缀。

div {
  display: -webkit-flex; /* Safari */
  display: flex;
}

弹性布局是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的布局方式。

引入弹性盒布局模型的目的是提供一种更加有效的方式来对一个容器中的子元素进行排列、对齐和分配空白空间。

2.基本概念

采用 Flex 布局的元素,称为 Flex 容器(flex container),简称“容器”。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称“项目”。

容器默认存在两根轴:水平的主轴和垂直的交叉轴

容器属性

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content

子元素属性

  • flex
  • align-self

3.flex-direction

flex-direction 属性指定了主轴线的方向,子元素默认是按照主轴线排列的,所以 flex-direction 也指定了弹性子元素在弹性容器中的排列方式, 有以下四个值:

  • row :(默认)横向从左到右排列。
  • row-reverse :顾名思义,从右向左横向排列,反向。
  • column : 纵向从上往下排列。
  • column-reverse : 纵向从下往上排列。

下面使用值 row 操作属性 flex-direction:

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <style>
      .container {
        display: flex;
        flex-direction: row;
        width: 400px;
        height: 450px;
        background-color: green;
      }
      .item {
        background-color: red;
        width: 100px;
        height: 100px;
        margin: 20px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item">item1</div>
      <div class="item">item2</div>
      <div class="item">item3</div>
    </div>
  </body>
</html>


如图所示,三个子元素按照值 row 的排列方式,在容器的横向从左到右排列。

当我们修改 flex-direction 为 column , 在容器的纵向从上往下排列。

## 4.flex-wrap
弹性盒子默认情况下所有子元素都是排在一行上的,但容器大小有限,很有可能出现子元素被截断的情况,这时候就需要换行,flex-wrap 就是用来操作子元素换行的属性。flex-wrap 有以下三个值:

>* nowrap :(默认) 不换行。
>* wrap :换行,第一行排满后自动换到第二行。
>* wrap-reverse :换行,与 wrap 不同的是如果出现换行,换行后的元素在第一行上方。

下面使用值 wrap 来操作属性 flex-wrap :
```bash
<style>
  .container {
    display: flex;
    flex-wrap: wrap;
    width: 350px;
    height: 450px;
    background-color: green;
  }
  .item {
    background-color: red;
    width: 120px;
    height: 100px;
    margin: 20px;
  }
</style>

运行效果图为 当我们的父元素(flex-container)宽度为 35px 时,子元素(flex item)为 120px,父元素的一排排不满三个盒子,那么设置 wrap 属性就能够换行,第一行排满后自动换到第二行。

而如果我们强制不换行,设置 nowrap 属性值 子元素的宽度就会被自动减少,挤在一行。

5.flex-flow

flex-flow 是 flex-direction 和 flex-wrap 的简写形式,默认值为 row nowrap。

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <style>
      .container {
        display: flex;
        flex-flow: row wrap;
        /*从左往右 换行*/
        width: 350px;
        height: 350px;
        background-color: green;
      }
      .item {
        background-color: red;
        width: 120px;
        height: 100px;
        margin: 20px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item">item1</div>
      <div class="item">item2</div>
      <div class="item">item3</div>
    </div>
  </body>
</html>

6.justify-content

子元素在容器中默认是以左对齐的布局排列在主轴线上的,属性 justify-content 用来调整子元素在主轴线上的对齐方式,它有以下五个值:

  • flex-start :左对齐
  • flex-end :右对齐
  • center :居中
  • space-between :两端对齐,项目之间的间隔都相等。
  • space-around :每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

使用值 space-between 来操作属性 justify-content :

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <style>
      .container {
        display: flex;
        justify-content: space-around;
        width: 400px;
        height: 250px;
        background-color: green;
      }
      .item {
        background-color: red;
        width: 100px;
        height: 100px;
        margin: 10px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item">item1</div>
      <div class="item">item2</div>
      <div class="item">item3</div>
    </div>
  </body>
</html>

容器的宽度为 400px,三个子元素的宽度和加上它们的边框小于 400px,所以不会出现换行。

7.align-items

与主轴垂直的轴我们称它为交叉轴,属性 align-items 用于定义子元素在交叉轴上的排列方式,它有下列五个值:

  • flex-start :交叉轴的起点对齐。
  • flex-end :交叉轴的终点对齐。
  • center :交叉轴的中点对齐。
  • baseline :项目的第一行文字的基线对齐。
  • stretch :如果子元素未设置高度或设置为 auto ,子元素将占满整个容器高度。

使用值 flex-end 来操作属性 align-items :

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <style>
      .container {
        display: flex;
        flex-direction: column;
        align-items: flex-end;
        width: 400px;
        height: 250px;
        background-color: green;
      }
      .item {
        background-color: red;
        width: 100px;
        height: 100px;
        margin: 10px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item">item1</div>
      <div class="item">item2</div>
      <div class="item">item3</div>
    </div>
  </body>
</html>

注:这里的 flex-direction 设置为 column ,即主轴线的方向是垂直的,即交叉轴的方向是水平的;align-items 设置为 flex-end,即子元素在交叉轴结束位置上的边界对齐,交叉轴的结束位置在右侧,所以三个子元素在右边界上对齐。

8.align-content

align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。,align-content 有以下六个值:

  • flex-start :与交叉轴的起点对齐。
  • flex-end :与交叉轴的终点对齐。
  • center :与交叉轴的中点对齐。
  • space-between :与交叉轴两端对齐,轴线之间的间隔平均分布。
  • space-around :每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch:轴线占满整个交叉轴。

下面使用值 center 来操作属性 align-content :

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <style>
      .container {
        display: flex;
        flex-wrap: wrap;
        align-content: center;
        width: 200px;
        height: 600px;
        background-color: green;
      }
      .item {
        background-color: red;
        width: 100px;
        height: 100px;
        margin: 10px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item">item1</div>
      <div class="item">item2</div>
      <div class="item">item3</div>
    </div>
  </body>
</html>

注:该处设置 flex-wrap 换行属性为 wrap,允许换行。align-content 属性在容器内不存在换行时不产生效果,所以我们将容器的 width 设置为 200px,一行只能放下一个子元素。align-content:center 表示每一行在交叉轴上居中排列,三个子元素只是在交叉轴上居中排列,因为我们没有设置主轴线的对齐方式,如果我们将 CSS 代码修改为如下所示,其余代码不变,那么子元素的排列效果就会发生变化。

.container {
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  justify-content: center;
  width: 200px;
  height: 600px;
  background-color: green;
}
.item {
  background-color: red;
  width: 100px;
  height: 100px;
  margin: 10px;
}

可以看到,三个子元素的排列已经完全居中了。

9.flex

flex 属性实际上是三个属性的简写形式:

flex: flex-grow || flex-shrink || flex-basis;

所以在介绍 flex 之前,先介绍这三个属性各自的特性。

flex-grow

当容器比子元素大很多,子元素的宽高又设置的很小,这个时候即使水平垂直居中,整个布局看起来仍然很奇怪:

又或者根据实际的需要,子元素需要将容器占满。这个时候,我们就可以使用属性 flex-grow 来操作。 flex-grow 是设置子元素如何分配容器的剩余空间的属性。

假设容器的宽度为 400px,A 元素的宽度为 100px,B 元素的宽度也为 100px。

  • 当 flex-grow 的值为 0 (默认),子元素不会分配剩余空间,所以 A 和 B 的宽度仍然是 100px 。
  • 当 flex-grow 的值为 1 ,子元素平均分配剩余空间,即:剩余宽度为 200px ,A 和 B 各分配得到 100px ,A 和 B 的宽度都变为了 200px 。
  • 当 flex-grow 的值大于 1,则按照各自所占的比例分配剩余空间。例如 A 元素的 flex-grow = 1 ,B 元素的 flex-grow = 2 ,则 A 分配到 1/3 的剩余空间,即 1/3 * 200px ,B 元素同理。
<!DOCTYPE html>
<html>
  <head>
    <style>
      .container {
        display: flex;
        justify-content: center;
        width: 600px;
        height: 200px;
        background-color: green;
      }
      .item {
        background-color: red;
        width: 100px;
        height: 100px;
        margin: 10px;
      }
      .item1 {
        flex-grow: 3;
      }
      .item2 {
        flex-grow: 6;
      }
      .item3 {
        flex-grow: 1;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item item1">item1</div>
      <div class="item item2">item2</div>
      <div class="item item3">item3</div>
    </div>
  </body>
</html>

三个子元素按照比例分配了剩余的空间,形成了布局。

flex-shrink 与 flex-grow 相反,当容器过小,子元素过大时,属性 flex-shrink 用来缩小子元素。 假设容器的宽度为 300px ,A 元素的宽度为 200px ,B 元素的宽度也为 200px 。

  • 当 flex-shrink 的值为 0 ,子元素不会缩小,可能会导致元素溢出容器。
  • 当 flex-shrink 的值为 1 (默认),子元素会按照同样的比例缩小自身的大小。A 的宽度 = (200-100*(2001/(2001+200*1)))= 150 。B 元素也同理。
  • 当 flex-shrink 的大于 1 ,子元素会按照给定的比例缩小自身的大小。例如 A 的 flex-shrink 设置为 2 ,B 的 flex-shrink 设置为 3 ,则 A 的宽度 = (200-100*(2002/(2002+200*3)))= 160 。B 元素也同理。
<!DOCTYPE html>
<html>
  <head>
    <style>
      .container {
        display: flex;
        justify-content: center;
        width: 300px;
        height: 200px;
        background-color: green;
      }
      .item {
        background-color: red;
        width: 200px;
        height: 100px;
        margin: 10px;
      }
      .item1 {
        flex-shrink: 3;
      }
      .item2 {
        flex-shrink: 6;
      }
      .item3 {
        flex-shrink: 1;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item item1">item1</div>
      <div class="item item2">item2</div>
      <div class="item item3">item3</div>
    </div>
  </body>
</html>

flex-basis

flex-basis 用于设置子元素的宽度,规定子元素的基准值,如果子元素另外设置了 width ,会被该属性的值覆盖。 flex-basis 有几个特殊的取值,我们介绍其中的 auto 取值(默认)。当 flex-basis 取值为 auto 时,如果子元素的宽度不为 auto ,那么子元素的宽度就设置为自身的宽度;如果子元素的宽度设置为 auto ,那么子元素的宽度就根据子元素的内容来自动布局。

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <style>
      .container {
        display: flex;
        justify-content: center;
        width: 400px;
        height: 200px;
        background-color: green;
      }
      .item {
        background-color: red;
        flex-basis: auto;
        width: auto;
        height: 100px;
        margin: 10px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item">item1</div>
      <div class="item">item2</div>
      <div class="item">item3</div>
    </div>
  </body>
</html>

运行效果图为:

10.align-self

属性 align-self 可以使某个子元素的对齐方式与其它的子元素不同,可以覆盖 align-items 的值。align-self 的取值与 align-items 的取值相比只多了一个 auto ,其余均与 align-items 相同。 下面我们操作一下属性 align-self:

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <style>
      .container {
        display: flex;
        align-items: flex-start;
        width: 400px;
        height: 250px;
        background-color: green;
      }
      .item {
        background-color: red;
        width: 100px;
        height: 100px;
        margin: 10px;
      }
      .item1 {
        align-self: inherit;
      }
      .item2 {
        align-self: flex-end;
      }
      .item3 {
        align-self: inherit;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item item1">item1</div>
      <div class="item item2">item2</div>
      <div class="item item3">item3</div>
    </div>
  </body>
</html>

11.多媒体查询

媒体类型

CSS3 的多媒体查询继承了 CSS2 的多媒体类型的所有思想,取代了查找设备的类型,CSS3 根据设置自适应显示,CSS3 有以下几种多媒体类型:

  • all :用于所有的多媒体类型设备。
  • print :用于打印机。
  • screen :用于电脑屏幕、智能手机、平板等。
  • speech :用于屏幕阅读器。

@media 的语法为:

@media not|only mediatype and (expressions) {
  /*css code here*/
}

下面操作一下 @media:

<!DOCTYPE html>
<html>
  <head>
    <style type="text/css">
      @media screen and (min-width: 480px) {
        body {
          background-color: red;
        }
      } /*窗口尺寸大于480px,背景颜色为红色*/
      @media screen and (min-width: 720px) {
        body {
          background-color: lightgreen;
        }
      } /*窗口尺寸大于720px,背景颜色为绿色*/
    </style>
  </head>
  <body></body>
</html>

调整浏览器的窗口大小,观察背景颜色的变化。

媒体查询使用方法

媒体查询能在不同的条件下使用不同的样式,使页面在不同在终端设备下达到不同的渲染效果。媒体查询有其自己的使用规则。具体来说,媒体查询的使用方法如下。

@media 媒体类型and (媒体特性){你的样式}

使用媒体查询必须要使用 @media 开头,然后指定媒体类型(也可以称为设备类型),随后是指定媒体特性(也可以称之为设备特性)。媒体特性的书写方式和样式的书写方式非常相似,主要分为两个部分,第一个部分指的是媒体特性,第二部分为媒体特性所指定的值,而且这两个部分之间使用冒号分隔。

媒体特性是通过 min/max 来表示大于等于或小于做为逻辑判断,接下来一起来看看媒体查询在实际项目中常用的方式。

1.最大宽度 max-width

max-width 是媒体特性中最常用的一个特性,其意思是指媒体类型小于或等于指定的宽度时,样式生效

@media screen and (max-width: 400px) {
  .box {
    display: none;
  }
}

上面表示的是:当屏幕小于或等于 400px 时,页面中的 .box 都将被隐藏。

2.最小宽度 min-width

min-width 与 max-width 相反,指的是媒体类型大于或等于指定宽度时,样式生效。

@media screen and (min-width: 1000px) {
  .box {
    width: 400px;
  }
}

上面表示的是:当屏幕大于或等于 1000px 时,容器 .box 的宽度为 980px。

3.多个媒体特性使用

媒体查询可以使用关键词 and 将多个媒体特性结合在一起。也就是说,一个媒体查询中可以包含 0 到多个表达式,表达式又可以包含 0 到多个关键字,以及一种媒体类型。

@media screen and (min-width: 700px) and (max-width: 1000px) {
  .box {
    width: 500px;
  }
}

当屏幕在 700px~1000px 之间时,容器 .box 的宽度为 500px。

4.not 关键词

使用关键词 not 是用来排除某种制定的媒体类型,也就是用来排除符合表达式的设备。换句话说,not 关键词表示对后面的表达式执行取反操作。

@media not print and (max-width: 1200px) {
  .box {
    width: 500px;
  }
}

在除打印设备和设备宽度小于 1200px 下所有设备中,容器 .box 的宽度为 500px。

12.用户界面

相比 CSS2 ,CSS3 增加了一些新的特性来调整元素尺寸、框尺寸和外边框。

  • resize
  • box-sizing
  • outline-offset

resize

属性 resize 允许用户调整元素的尺寸,但是需要将元素的 overflow 属性设置为 auto 、hidden 或 scroll,resize 属性才能生效。

resize 有以下四个值:

  • none :用户无法调整元素尺寸。
  • both :用户可以调整元素的高度和宽度。
  • horizontal :用户可以调整元素的宽度。
  • vertical :用户可以调整元素的高度。

4下面使用值 both 操作属性 resize:

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <style type="text/css">
      div {
        overflow: auto; /* auto 、hidden or scroll*/
        border: 2px solid;
        width: 300px;
        height: 250px;
        resize: both;
      }
    </style>
  </head>
  <body>
    <div>
      <p>用户可以调整该元素的大小</p>
    </div>
  </body>
</html>

box-sizing

属性 box-sizing 和盒子模型有关,它允许用户以特定的方式定义匹配某个区域的特定元素。

box-sizing 有以下三个值:

  • content-box :(默认)设置属性为该值时,设定的高度和宽度值只应用到 content 内容上,不包括 padding 和 border。
  • border-box :设置属性为该值时,设定的高度和宽度应用到 content + padding + border 上,也就是说如果要得到 >* content 的宽高需要减去 padding 和 border。 inherit :继承父元素的 box-sizing 取值。

下面对比一下 content-box 和 border-box:

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <style type="text/css">
      .container {
        width: 660px; /* width = item1.width + 2 * item1.border + item2.width */
        height: 310px; /* height = item1.height + 2 * item1.border */
        display: flex;
        flex-flow: row wrap;
        border: 2px solid;
      }
      .content-box {
        box-sizing: content-box;
        border: 30px solid yellow;
        width: 300px;
        height: 250px;
      }
      .border-box {
        box-sizing: border-box;
        border: 30px solid blue;
        margin-top: 30px;
        width: 300px;
        height: 250px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="content-box">item1</div>
      <div class="border-box">item2</div>
    </div>
  </body>
</html>

item1 和 item2 的边框都设置为 30px,宽高都设置成相同数值。按照 box-sizing 的属性规定,item1 的 box-sizing 为 content-box,item1 最终的宽高应该为设置的宽高加上边框和填充的大小,填充默认为 0,则 item1 最终的宽高应该为 360px 310px。item2 的 box-sizing 为 border-box,item2 最终的宽高就等于设置的宽高 300px 250px。运行后可以发现,item2 content 高加 padding 高加 border 高等于 item1 content 高,符合我们的预期。如果还有些疑惑,可以利用 container 的宽度计算一下 item1 和 item2 的宽度,会发现结果如上述对 box-sizing 属性描述的一样。

outline-offset

属性 outline-offset 对轮廓进行偏移,并在边框边缘进行绘制,轮廓不会占用空间,并且不一定是矩形。 下面操作 outline-offset 属性:

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <style type="text/css">
      div {
        margin: 100px;
        width: 200px;
        height: 200px;
        border: 2px solid;
        outline: 2px solid green;
        outline-offset: 20px;
      }
    </style>
  </head>
  <body>
    <div></div>
  </body>
</html>