CSS 布局概览
7月 10, 2022
越来越觉得,与其说 CSS 是编程语言,不如说它是配置文件。CSS (Cascading Style Sheets,层叠样式表)的诞生是为了图文信息展示服务的。CSS 布局机制通常就是指对 display
属性的设置,Display - MDN 文档指明 display
属性可以用来指示六种维度的值,下面就看看 display
设置了不同的值到底意味着什么。
盒子模型 #
先认识下通常说的盒子模型。
块级盒子 #
常见的诸如标题 (<h1>
等) 和段落 (<p>
) 默认情况下都是块级的盒子。块级盒子具有以下行为:
- 每个元素都会换行
width
和height
将正常生效padding
、margin
、border
属性都会正常生效(将其他元素从当前盒子周围推开)
另外 CSS 中组成一个块级盒子需要:
- margin(外边距)
- border(边框)
- padding(内边距)
- content
- width
- height
在标准模型中,如果你给盒设置 width
和 height
,实际设置的是 content box。这一点很重要,因为这两个属性是“块级盒子”才能设置的。padding 和 border 再加上设置的宽高一起决定整个盒子的大小。如果有的时候我们不想这么计算,而是希望通过 width
和 height
来设置整个盒子(即 border 包含的范围)的宽高,则可以通过 box-sizing
属性决定:
box-sizing: content-box; /* 标准模型 */
box-sizing: border-box; /* 替代模型 */
首先默认浏览器会使用标准模型,但是也可以自己设置为替代模型。尤其注意:border-box
不包含 margin
。
内联盒子 #
还有另一个叫内联盒子,内联盒子具有以下行为:
- 不会产生换行
width
和height
将不产生作用- 垂直方向的
padding
、margin
以及border
会被应用但是不会把其他处于inline
状态的盒子推开 - 水平方向的
padding
、margin
以及border
会被应用且会把其他处于inline
状态的盒子推开
Display 总览 #
每个元素都有两个盒子:外在盒子和内在盒子,外在盒子决定盒子是块级还是内联,内在盒子决定盒子内部元素是如何布局的。注意:内联和内部完全不是一个概念,相对应的外部也不是指块级盒子。也就是说不管块级还是内联指的都是外在盒子。
我们通过对盒子 display
属性的设置,来控制盒子的外部显示类型和内部显示类型,下面会具体介绍,至此知道主要有外在和内在两个维度即可(实际上目前有六个维度),本篇文章的目录也可以清晰表示他们的关系。
<display-outside>
外在维度
#
指定了元素的外部显示类型,实际上就是其在流式布局中的角色,即 block
还是 inline
。
block(块级元素) #
display: block
这个值会生成一个块级元素盒子,同时在该元素之前和之后打断(换行)。简单来说就是,这个值会将该元素变成块级元素。
严格地说,可能 display: block-block
会更形象。
inline(内联元素) #
这个值会生成一个行内元素盒子,该元素之前和之后不会打断(换行)。如果空间充足,该元素后的元素将会在同一行显示。简单来说就是,这个值会将该元素变成内联元素。
根据内外两个盒子的模型,那
inline
可能写作display: inline-inline
会更形象。由此可推,
inline-block
就是外在的“内联”和内在的“块级盒子”组成的了。
用做链接的 <a>
元素、 <span>
、 <em>
以及 <strong>
都是默认处于 inline
状态的。
<display-inside>
内在维度
#
下面的关键字指定了元素的内部显示类型,它们定义了该元素内部内容的布局方式。
flow(流式布局) #
CSS 原本的样子就是流式布局,是指在不对页面进行任何布局控制时,浏览器默认的 HTML 布局方式:一个个元素从左到右、从上到下根据 HTML 代码定义的内容顺序进行显示。
flow-root #
考虑兼容性可能比较新,可以先不了解。
table(表格布局) #
如果说 CSS 布局有第 0 代,就是表格 table 了。但是 <table>
标签比 CSS 还要老,在所讨论的所有的流式布局的世界中,都不包含 <table>
,关于 <table>
的内容以后单独再说,本文就不讨论了。
flex(弹性盒子布局) #
练习游戏(玩一下就会了,讲了也是忘):
这是一个例子:
#parent {
display: flex;
flex-flow: column wrap; /*(direction+wrap)*/
flex-wrap: nowrap; /* wrap; wrap-reverse; */
flex-direction: row; /* column; row-reverse; column-reverse; */
align-items: flex-start;
align-content: flex-start;
justify-content: flex-start;
justify-items: flex-start;
}
#child {
order: 1; /* 默认为 0 */
align-self: flex-start; /* flex-end;center; */
}
属性:
- justify-content(“横向”,取决于flex-direction)
- flex-start
- flex-end
- center
- space-between
- space-around
- align-items(“纵向”)
- flex-start
- flex-end
- center
- flex-direction
- row(默认)
- row-reverse
- column
- column-reverse
- align-self(子元素)
- flex-start
- flex-end
- center
- order(子元素)
- 可选 0,1,2,3 etc
- align-content
- 只适用多行的flex容器,也就是说子项不止一行时该属性才有效果
- flex-wrap
- 指定 flex 元素单行显示还是多行显示 。如果允许换行,这个属性允许你控制行的堆叠方向。
- nowrap(默认)
- wrap
- wrap-reverse
grid(网格布局) #
练习游戏:
这是一个例子:
#garden {
display: grid;
grid-template-columns: 20% 20% 20% 20% 20%;
grid-template-rows: 20% 20% 20% 20% 20%;
grid-template-columns: repeat(1, 12.5%);
grid-template-columns: 1fr 5fr; /*(fractional 分数)*/
grid-template: 60% 40% / 200px;
}
#watch {
grid-column-start: 1;
grid-column-end: 2;
grid-column: 1/2;
grid-column-start: 1;
grid-column-end: span 2;
grid-area: 1 / 4 / 6 / 5;
}
属性:
- grid-template-columns
- grid-template-rows
- grid-column-start(子元素)
- grid-column-end(子元素)
- grid-column(等价于 3+4)
- grid-row-start(子元素)
- grid-row-end(子元素)
- grid-row(6+7)
- grid-area(等价于 row-start/column-start/row-end/column-end)
- order(元素间的排序)
- grid-template(1+2),中间要有斜线。
ruby #
类似于 <ruby>
标签的特性,被用来展示东亚文字注音或字符注释,暂无需求本文先不讨论了。
<display-listitem>
#
值为 list-item
类似 ul
、 li
标签一样的样式,可以使用 list-style-type
和 list-style-position
选项进行装饰。
<display-box>
#
这些关键词定义一个元素到底是否产生显示盒(display boxes):
- contents
- none
display 的 none
值比较常用,它会关闭元素的显示,且不影响布局(就当作文件中没有该元素)。
要一个元素占据空间(文件中存在),但不渲染,请使用 visibility
属性。
<display-internal>
#
一些布局模型(如 table 和 ruby)具有复杂的内部结构,暂不了解。
<display-legacy>
#
CSS 2 对 display 属性使用了单关键字语法,对于相同布局模式的块级和内联级的变体,需要单独的关键字。
inline-block #
除了完全的 block-block
和 inline-inline
之外,还有一个就是 inline-block
,它可以有以下能力:
- 设置
width
和height
属性会生效。 padding
、margin
以及border
会推开其他元素。
inline-table #
等效于 inline table
inline-flex #
等效于 inline flex
inline-grid #
等效于 inline grid
小结 #
See the Pen Untitled by tcitry (@tcitry) on CodePen.
上面 这个例子(来自 MDN )可以多尝几遍。最后,看完上面的宏观分类以后,知道了 display
的使用场景,下面针对常用每个微观领域进行描述。
可见仅仅是关于布局的属性也非常多,没必要都记住,本文也无意要区分各个相近名称的区别,真正要做的是能够清晰分类,在需要的时候通过快速查阅文档找到需要的属性,然后再通过一些 demo 来快速验证。
其他布局方式 #
其他脱离了 display
系统的布局方式。
传统布局 #
就是 width + float
https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods
多列布局 #
column-count
column-width
https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Multiple-column_Layout
浮动 Float #
float
CSS 属性指定一个元素应沿其容器的左侧或右侧放置,允许文本和内联元素环绕它。该元素从网页的正常流动(文档流)中移除,尽管仍然保持部分的流动性(与绝对定位相反)。由于 float
意味着使用块布局,它在某些情况下会修改 display
值的计算值。
它有以下几种枚举:
- left
- right
- none:
- inline-start
- inline-end
定位 Position #
CSS position
属性用于指定一个元素在文档中的定位方式。top
,right
,bottom
和 left
属性则决定了该元素的最终位置。它的取值枚举有以下几种。
- static
- relative
- absolute
- fixed
- sticky
参考 #
CSS 世界(这本书基本就全在讲布局体系)