理解《CSS世界》盒模型、流、布局

CSS是为图文信息展示而诞生的。如果让你构建一个CSS世界,要求是非常便于图片和文字的呈现,你会怎么构建?本文总结了《CSS世界》《CSS新世界》中张鑫旭老师对CSS世界的理解。从CSS世界出发,重新去理解什么是盒模型?布局怎么影响一个个盒子?以及为什么要这样设计?

1. CSS世界

在CSS世界中,HTML是魔法石,选择器就是选择法器,CSS属性就是魔法师,CSS各种属性值就是魔法师的魔法技能,浏览器就是他们所在的"王国"。CSS 作用于 HTML 元素上,各种布局影响了元素的展示,从而构建出一个个丰富的页面。

2. 盒模型

每个HTML元素都有外在盒子和内在盒子。

  • 外在盒子:负责元素是可以一行显示,还是只能换行显示
  • 内在盒子:负责宽高、内容怎么呈现。width/height作用在内在盒子上

元素的 display 属性可以理解为 display: 外在盒子-内在盒子。 如display: inline-block,它的外在是inline盒子,一行显示。内在是block盒子,允许设置宽高。

2.1 外在盒子

外在盒子可以分成这几类:块级盒子,内联盒子,特殊盒子,表格盒子

外在盒子 display display: 外在-内在 表现 常见元素
块级盒子 display: block display: block-block 换行显示 <div><p><h1>
内联盒子 display: inline-block display: inline-block 一行显示,可以设置宽高 手动设置css属性
内联盒子 display: inline display: inline-inline 一行显示,无法设置宽高 <span><a><img><input>
特殊盒子 list-item 让元素额外显示符号 <ul><li>
表格盒子 display: table display: block-table 换行显示 <table>
表格盒子 display: inline-table display: inline-table 和文字图片一行显示 手动设置css属性

display: inline-table示例

2.2 内在盒子

内在盒子,也叫容器盒子。width/height会作用在容器盒子上。

内在盒子分成了4个盒子,分别是content box、padding box、border box和margin box。

  • box-sizing

    是改变 width / height 的作用细节

    • content-box 让宽度作用在content box上(默认值)
    • border-box 让宽度作用在border box上(width = content + padding + border)。对应JS的 offsetWidth, offsetHeight
    • JS中的 clientWidth, clientHeight 对应padding box的尺寸
  • width的默认值是auto,如何理解auto?

    • 充分利用空间:<div>、<p>元素的宽度默认是100%于父级容器的。display: block 的元素不用额外加 width: 100%
    • 收缩与包裹:inline-block, table会包裹元素内容至合适宽度,理解为fit-content
    • 收缩到最小:当空间不够的时候,如很多列的table有的列会收缩为一行,理解为min-content
    • 超出容器限制:一般子元素都不会主动超过父元素的容器宽度,除非内容是很长的连续英文和数字
    • 遵循无宽度准则,因为元素一旦设置了宽度,就失去了流动性
  • height: 100%

    注意,父级没有具体高度值的时候,height: 100%是无效的。

3. 内联元素与流

有了盒子,如何排列盒子?这个时候就要引出"流"的概念。

"流"是CSS世界中一种定位和布局机制,它是一条引导元素排列和定位的、看不见的"水流"。流作用于外在盒子,块级盒子负责结构,内联盒子接管内容。CSS世界是面向图文混排的,也就是为内联元素设计的。

内联布局比较重要的两个问题:对齐和行高。当一堆内联元素放在同一行:

  1. 它们在行上如何对齐?
  2. 已知 display: inline 元素无法设置width/height,那应该怎样去调整它们的高度?

3.1 vertical-align 基线

先回答第一个问题,如何对齐? 在各种内联相关模型中,凡是涉及垂直方向的排版或者对齐的,都离不开最基本的基线(baseline)。例如,line-height行高的定义就是两基线的间距,vertical-align的默认值就是基线。

什么是基线?

  • vertical-align: baseline:基线,字母x的下边缘线。内联元素默认是基线对齐的

什么是中线?

  • vertical-align: middle:中线,基线往上 1/2 * x-height 的高度,近似x的交叉点位置。vertical-align:middle并不是绝对的垂直居中对齐。因为大部分字体都要往下偏一点。
  • x-height:指小写字母x的高度。

3.2 line-height 占据高度

vertical-align提供了内联元素垂直对齐的功能。 再来回答第二个问题,已知 display: inline 元素无法设置width/height,那应该怎样去调整它们的高度?

此时,有一个空的<div>,高度是0,我们在里面写上几个文字,<div>高度就有了,这个高度由何而来,或者说是由哪个CSS属性决定的?

不少人会认为<div>高度是由里面的文字撑开的,也就是font-size决定的,但本质上是由line-height属性全权决定的。line-height如何通过改变行距实现文字排版?

line-height: 2: 两行文字中间的间隙一个文字尺寸大小

line-height: 1: 两行文字会紧密依偎在一起

line-height: 0.5: 两行文字就是重叠纠缠在一起

3.3 空白幽灵节点

line-height会影响内联元素(文字)的占据高度,那替换元素<img>和 inline-block 内联块级元素呢?

下面例子中, box里只有一个img元素。<img>元素的高度是128px, box元素的高度是256px。line-height把图片占据的高度变高了吗?

html 复制代码
.box {
  line-height: 256px;
}
<div class="box">
  <img src="1.jpg" height="128">
</div>

答案是:

line-height不能影响<img>的占据高度。而是把"幽灵空白节点"的高度变高了。<div><img /></div>会在<div>内构成一个"行框盒子"。在HTML5文档模式下,每一个"行框盒子"的前面都有一个宽度为0的"幽灵空白节点",其内联特性表现和普通字符一模一样,所以,这里的容器高度会等于line-height设置的属性值256px。

4. 流的破坏(float, absolute)

至此,内联布局、流布局解决了大部分图文排版的问题。但它们总是方方正正的,有时候我们希望有一些特殊的布局,如文字环绕效果,或者元素固定在某个位置,要实现这样的效果,正常流就有些捉襟见肘。因此,CSS使用float, absolute 通过破坏正常流来实现一些特殊的样式表现。

  • float

    浮动的本质就是为了实现文字环绕图片效果。float 通过破坏正常CSS流实现CSS环绕,脱离了正常流,让父元素高度坍塌。

  • absolute

    同样具有破坏性的是position: absolute | fixed | relative实现精确定位

5. 传统CSS布局

总结一下上面的内容,CSS 2.1 定义了4种布局方式:

  • 块布局:元素以 display: block 的方式布局,负责布局结构
  • 内联布局:元素以 display: inline 的方式布局,负责展示文本内容
  • 表格布局:元素以 display: table(inline-table) 布局,用于布局二维表格数据
  • 定位布局:元素以 position: absolute 定位, 不考虑文档中其他元素,用于精确定位

这4种布局都是为图文信息展示而生。但随着Web页面越来越复杂,二维布局的需求越来越多,用这4种方法实现一个左侧栏右内容的布局,我们会:

  • display:inline-block让div元素变成内联块
  • position: absolute 精确定位加上 margin-left: -200px
  • float实现

但它们都不是专门为二维结构设计的。在这种背景下,全新的CSS布局模式出现。它们就是 flex 弹性布局和 grid 网格布局。 这两种布局专门为现代Web应用设计,代码简单,样式丰富,逐渐成为主流的布局方式。

6. flex 弹性布局

flex 弹性布局通过流向控制、对齐设置、空间分配实现布局效果。

6.1 流向控制

  • flex-direction 布局方向 控制子项是从左往右、从右往左,从上往下,从下往上排列
  • flex-wrap 换行表现 控制子项是单行显示还是换行显示
    • nowrap:单行显示,且不换行,可能会出现子项宽度溢出
    • wrap:当容器宽度不足时,子项会换行显示

6.2 对齐设置

  • justify-content 水平对齐
  • align-items 垂直对齐

6.3 空间分配

我们可以把弹性布局的空间分配看成分配家产

  • flex-basis 分配家产的基础数量 相当于width
  • flex-grow 家产有富余时如何分配 默认值是0,表示多余空间不分配。所有剩余空间总量是1,如果flex-grow是0.3,表示分配剩余空间 * 0.3。如果大于1,则独享所有空间。如果子项都设置了flex-grow,总数>1,则按值/总数来分配
  • flex-shrink 家产不足时如何收缩 默认值是1,如果空间不足,子项等比例收缩,填满flex容器。一个子项的flex-shrink为0,其余为默认1,那么空间不足时,该项目不收缩,其他都收缩。

flex 是 flex-grow, flex-shrink, flex-basis 三个属性的缩写

6.4 顺序控制

通过 order 改变子项的排列顺序,数值越小,排列越靠前。默认为0

7. grid 网格布局

网格布局(Grid)是很强大的 CSS 布局方案。 Grid 布局将容器划分出"行"和"列",产生一个个单元格,然后指定"项目所在"的单元格,从而做出各种各样的布局。

7.1 划分单元格

  • grid-template-columns 定义每一列的列宽
  • grid-template-rows 定义每一行的行高
  • grid-gap: 20px 20px 定义行与行之间的间距,列与列的间距

7.2 指定区域

  • grid-template-areas 定义区域,多个单元格可以合并区域
css 复制代码
.container {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  grid-template-areas: 'a a a'
                     'b b b'
                     'c c c';
}

参考资料

相关推荐
林十一npc12 分钟前
MySQL索引与视图综合应用示例解析
android·前端·mysql
SuperherRo19 分钟前
Web开发-JavaEE应用&ORM框架&SQL预编译&JDBC&MyBatis&Hibernate&Maven
前端·sql·java-ee·maven·mybatis·jdbc·hibernate
这里有鱼汤19 分钟前
Python 图像处理必备的 15 个基本技能 🎨
前端·后端·python
这里有鱼汤20 分钟前
想学会Python自动化办公?这20个Excel表格操作脚本一定要掌握!
前端·后端·python
爱摄影的程序猿33 分钟前
Python Web 框架 django-vue3-admin快速入门 django后台管理
前端·python·django
洁洁!1 小时前
数据采集助力AI大模型训练
前端·人工智能·easyui
MiyueFE1 小时前
bpmn-js 源码篇9:Moddle - 对象格式的标准化定义库
前端·javascript
excel1 小时前
webpack 核心编译器 七 节
前端
一只月月鸟呀1 小时前
HTML中数字和字母不换行显示
前端·html·css3
天下代码客1 小时前
【八股】介绍Promise(ES6引入)
前端·ecmascript·es6