前端开发者学堂 - fedev.cn

图解CSS: CSS 盒模型

发布于 大漠

在学习Web布局之前有一个非常重要的概念需要理解,这个概念就是盒模型。CSS盒模型是多个不同的CSS规则集合,定义了如何渲染Web页面。这一系列的不同的属性决定了HTML元素在页面上的位置。到目前为止,所有Web页面都只是一个接一个渲染的元素。可以说盒模型是我们定制默认布局方案的工具包。

作为Web开发人员,大部分工作是将应用CSS盒模型中的规则将设计模型转换为Web页面(简单点说,就是UI还原)。接下来要介绍的CSS盒模型又被视为UI还原的重中之重,因为它定义了盒子的单独行为。特别是在以后的章节中,我们学习的各种布局都将会围绕着HTML的结构和CSS的盒模型一起来展开。

基础盒模型介绍

在CSS中,一切都会生成一个框。而Web页面的本质上是一组块和内联框。如果在浏览器中使用开发者工具查看一个HTML中的元素,就可以很好的理解这些框。而这些框却是一组CSS规则的集合。主要用于确定页面中每个元素的尺寸。

在CSS的世界中将会视HTML中的每个元素比作一个盒子(也被称之为元素框)。

这个框体描述了元素在Web布局中所占的空间。因此元素之间涉及到位置和尺寸是会相互影响的。作为CSSer要彻底了解这些属性规则之间是如何相互影响的话,有一些理论和概念就很有必要了解清楚。

块元素和内联元素

任何一个Web页面都会有很多种不同的HTML元素组成,这也是众所周之的。前面我们也提到过,任何一个HTML元素都是一个框(盒子),这些框主要有两种类型,内联框。其对应的即是HTML中的块元素和内联元素。

  • 块框:如果不做任何的处理,其宽度会占满容器的整个宽度(或高度),而高度(或宽度)由元素内容决定,比如divpli等元素都是块元素,而这些块元素在Web上渲染出来的框就是块框
  • 内联框:如果不做任何的处理,其宽度和宽度都由内容来决定,比如spanstrongem等元素都是内联元素,而这些元素在Web上渲染出来的框就是内联框

用张图来描述,可能更易于理解:

这仅仅是常规的理解。

时至今日,CSS也有了较大的变化,而渲染也有着相应的变化。在块框和内联框和书写模式(writing-mode)有着紧密的联系。

对于块元素(块盒子)而言,如果书写模式是水平方向horizontal-tb,那么块是从上往下流;而书写模式是垂直方向horizontal-lr时,那么块是从左向右流。如下图所示:

对于内联元素而言,它会按照当前上下文、书写模式和方向进行布局。它们的宽度取决于它们的内容,并且在任何有空间的地方相邻放置。如下图所示:

简而言之,块元素遵循流方向,内联元素遵循写入方向

块轴和内联轴

块元素和内联元素是CSS中框模式中最基本的两种。而在Web的世界中还有坐标轴的概念,Web的坐标主要有两个轴,即:

  • x:水平方向的坐标轴
  • y:垂直方向的坐标轴

页面上的内容都尚着这两个轴进行排版。其中一个轴是内联轴,它是每行文本行的轴。默认情况下,在Web页面上,如果不指定任何书写模式,内联轴是水平的,从左到右(书写模式对其会有一定的影响)。另一轴是块轴,块轴是沿着这个轴堆积。同样,默认情况下,这个轴是垂直的,从上到下。如下图所示:

  • 内联轴(Inline Axis):拿英文网站为例。阅读方向是从左到右。好比多个内联元素一样,从左向右依次排开,也类似于在块元素中使用display: inline。每一项都出现在同一行
  • 块轴(Block Axis):大家应该都知道,对于块元素不做任何操作的情况下,他的排列顺序是从上到下依次堆积在一起。好比对内联元素采用了display: block

其实这两个概念理解起来比较费劲。拿Flexbox布局中的主轴和侧轴来说:

在书写模式默认情况下,内联轴好比Flexbox上的主轴(Main Axis),而块轴好比Flexbox上的侧轴(Cross Axis)。事实上,这两个概念如果我们运用到网格布局中就更易于理解。因为在网格布局中,总是使用块和内联轴。

块轴对应于在页面上布局块的顺序。比如,页面中的文本内容,每一段都在另一段下面排列,这些排列的方向是块的维度,所以在网格布局中,这是块(Block Axis)。在CSS网格布局中,块轴也称为行轴,这就是为什么块轴属性是grid-row-startgrid-row-end

因此,内联轴将会穿过块轴,沿碰上词在句子中的方向分布。在英文语句中,这个轴从左到右。在网格布局中,内联轴属性是grid-column-startgrid-column-end

前面也提到过,内联轴和块轴与书写模式有较大的关联,书写模式不同时,内联轴和块轴会随之改变。如下图所示:

框模式的类型

虽然在CSS中每个元素都是一个框,而这个框的模式是有所不同的,常见的模框式有:

  • 块级框:HTML中的pdiv等元素生成的框。在常规流动模式下,块级框在框体前后都“换行”,因此块级框是缀向堆叠的
  • 行内框:HTML中的strongspan等元素生成的框。行内框前后不“换行”
  • 行内块级框:内部特征像块级框,外部特征像行内框。行内块级框的行为与置换元素相似,但不完全相同。比如说把一个div元素像行内图像那样插入一行文本

在理解框模式上有几个概念需要有一定的了解:

  • 常规流动:即渲染西方语言时从左至右、从上到下的顺序,以及传统的HTML文档采用的文本布局方式(这也是大家常说的文档流)。对于非西方语言来说,流动方向可能会变。多数元素都采用常规的流动方式,除非元素浮动了、定位了,放入Flexbox容器或Grid容器中。
  • 非置换元素:内容包含在文档中的元素,例如p元素就是非置换元素,因为p中的文本内容在元素自身中
  • 置换元素:为其他内容占位的元素。比如img元素就是一个典型的置换元素,另外,多数表单元素也是置换元素

理解这些概念对于深入学习CSS或者后面聊布局的相关知识时有较大的帮助。

其实在HTML中的任何一个元素都有其对应的框模式,但在CSS中,我们可以借助display属性来修改元素的框模式。比如说,当你在一个div上使用了display: flexdisplay: grid,那么该div的框模式和display:block并无差异,但它改为了它们子元素的框模式。当然,如果你在一个块级框的元素上使用display:inline的话,该元素就会变成一个行内框。

CSS中的display属性也是CSS的重要属性之一,也是重中之中的部分。我们后面将会单独花一个章节和大家一起讨论这方面的使用。

盒模型术语

既然元素是一个框(盒子),那么就可以通过CSS属性(物理属性)来决定盒子的大小。而决定盒子大小主要由四个属性来决定:

  • Content:元素中的文本、图像或其他媒体内容
  • padding:盒子内容格边框之间的空间
  • border:盒子的边框
  • margin:盒子与其他盒子之间的距离

如果我们用一张图来描述的话,可以类似下面这样的:

上面提到的几个属性就是浏览器渲染元素盒子所需要的一切。内容是你在HTML中编写的内容,其余部分纯粹是展示性的,主要由CSS规则来决定。而且对于CSSer来说,都喜欢用类似下图来阐述元素的盒模型:

而在浏览器调试器中“Computed”可以看到它是怎么来解释一个元素的盒模型:

拿个简单的示例来展示:

.box {
    width: 200px;
    height: 200px;
    background-color: darkviolet;
    border: 5px solid hotpink;
    padding: 25px;
    margin: 20px;
}

.box对应的盒子如下图所示:

CSS的逻辑属性对盒模型带来的变化

大家是否有留意到,在前面提到的paddingbordermargin等都是采用的物理特性来描述一个盒子,而且开发者讨论盒模型的时候,都习惯使用下图来阐述它:

不管是以前,还是现在,以上图来阐述CSS盒模型的概念都不存在任何的错误。不同的是,上图我们围绕着的还是以特理特性来进行阐述,但随着CSS的逻辑属性的出现。再次阐述CSS盒模型的时候,会停止物理属性*-top*-right*-bottom*-left来阐述,而应该改用*-inline-start*-inline-end*-block-start*-block-end来重新定义盒模型,类似下图这样的:

如此一来,根据不同的语种,盒模型中的margin、border和padding对于的内联轴和块轴也不一样。拿英文网站来说:

margin

  • margin-block-start = margin-top
  • margin-block-end = margin-bottom
  • margin-inline-start = margin-left
  • margin-inline-end = margin-right

padding

  • padding-block-start = padding-top
  • padding-block-end = padding-bottom
  • padding-inline-start = padding-left
  • padding-inline-end = padding-right

border

  • border-block-start = border-top
  • border-block-end = border-bottom
  • border-inline-start = border-left
  • border-inline-end = border-right

也就是说,如果将CSS逻辑属性引入进来之后,我们将来描述一个盒模型,应该用下图来阐述,更为准确:

盒子尺寸

每个盒子都有其自己的尺寸大小。在物理属性中,通过widthheight来描述一个盒子的大小。而在逻辑属性中会使用逻辑尺寸的属性inline-sizeblock-size来描述一个盒子的大小。

如果理解了内联和块轴的概念,就更容易理解逻辑尺寸。比如在英文网站中,inline-size替换了widthblock-size替换了height。也就是说:

  • block-size:定义一个元素块的水平或垂直方向的尺寸,这主要取决于它的书写模式。如果书写模式是垂直方向的,则block-size与元素的width有关,否则,它与元素的height有关
  • inline-size:定义一个元素的块的水平或垂直尺寸,这取决于它的书写模式。其对应于任一widthheight属性,这取决于的值writing-mode。如果写作模式是垂直定向的,则inline-size与元素的height有关;否则,则与元素的width有关

比如英文或阿拉伯语网站:

  • width = inline-size
  • height = block-size

而在日文网站中:

  • height = inline-size
  • width = block-size

在我们的理解中,除了widthheight之外,还有min-widthmax-widthmin-heightmax-height一说。那么在inline-sizeblock-size中同样存在,相应的也是在其前面添加minmax。比如:min-inline-size: 100pxmax-block-size: 100px

盒模型切换

上面提到了,CSS的widthheight(或者说逻辑属性inline-sizeblock-size)可以用来计算元素盒子尺寸的大小。为了让大家更好的理解,这里还是拿物理属性来阐述。

在一般情况之下,我们所说的盒子的width是元素内容的宽度,内距和边框的和,这也常常被称之为内盒的宽度。如果你在内盒的宽度上加外距的大小就可以计算出盒子外盒的宽度。

盒子的height计算和width类似。

但在布局中,盒子的宽度计算会直接影响到布局,甚至会直接打破页面的布局。比如说,一个div元素:

div {
    width: 100%;
    padding: 1rem;
}

会让div超出容器,类似下图这样:

面对这样的场景时,就需要借助CSS的box-sizing属性,它可以更好的帮助我们控制盒子的大小:

用个实例来解释,这样更易于理解:

小结

随着我们深入的构建复杂的Web页面,将会学习更多有关于CSS盒模型的实际运用。现在,把它看作是CSS中的“工具”,该“工具”可以把设计模型更好的转换为现实的Web页面。如果你还不知道如何在Web布局中更好的运用好CSS盒模型,并不重要,也不需要过于担心。在这一章节中,只需要记住:

  • Web页面中任何一个元素都是一个盒子(框)
  • CSS中的框可以是内联的,也可以是块级的
  • CSS中的任何一个框都包含了内容、内距、边框和外距

另外,CSS的逻辑属性将会给CSS盒模型带来较大的变化,逻辑属性的使用能更好的结合书写模式,更能符合视觉上的感观。但也带来了一些新的概念。不过,在接下来的实际中,暂且不会涉及到太多有关于盒模型中的逻辑属性。