基础回顾
约 10090 字大约 34 分钟
2026-01-20
关于 box-sizing: border-box 的作用
在开发页面时,常见会加上如下的 CSS 重置代码:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}其中:
margin: 0、padding: 0:用于清除浏览器默认样式,比较好理解box-sizing: border-box:主要是为了 简化布局计算,避免很多“反直觉”的问题
默认情况(box-sizing: content-box),CSS 默认使用的是 content-box,width / height 只作用于内容区域(content),实际占用空间为:content + padding + border + margin
也就是说,你设置了一个 width: 100px 的元素,如果再加上 padding 和 border,元素在页面上实际占用的宽度会 大于 100px,这在布局时非常容易踩坑。
使用 box-sizing: border-box 之后,当设置为 border-box,width / height 包含 content + padding + border,元素在页面中占用的尺寸更加直观、可控,布局时不需要反复计算 padding 和 border 对整体尺寸的影响,而 width = content + padding + border
alpha 通道
rgba(r, g, b, a) 里的 a 叫 alpha 通道,表示 透明度:
取值范围:0 ~ 1
0= 完全透明1= 完全不透明- 例如:
rgba(0,0,0,0.5)= 半透明黑色
特点:只影响这条颜色本身(比如背景色、文字色、边框色),不影响元素里其它内容。
alpha 和 opacity 的影响范围不同
alpha(rgba / hsla / #RRGGBBAA)
- 只让“某个颜色”变透明
- 不影响子元素、文字、图片等其它内容
opacity
- 作用于整个元素(含子元素)
- 会让元素内部的所有内容一起变透明(文字也会跟着淡)
叠加行为(容易踩坑),父元素 opacity: 0.5,子元素就算 opacity: 1 也救不回来,它会一起半透明
新式写法:rgb(0 0 0 / 50%) 这是 CSS Color Module Level 4 的写法(更现代):
color: rgb(0 0 0 / 50%);
background: rgb(255 0 0 / 0.2);它等价于:
color: rgba(0,0,0,0.5);
background: rgba(255,0,0,0.2);16 进制一般是:#RRGGBB(不带透明度),#RGB(缩写)
带 alpha 的 16 进制是:#RRGGBBAA(最后两位 AA 是透明度),#RGBA(缩写)
AA 是 00~FF 的 16 进制:
00= 0%(全透明)FF= 100%(不透明)80≈ 50%(常用半透明)
/* 半透明黑色 */
color: #00000080;
/* 约 20% 透明度的红 */
background: #ff000033;常见速记(大概值):
- 100% →
FF - 75% →
BF(约 191/255) - 50% →
80(128/255) - 25% →
40(64/255) - 20% →
33(51/255) - 10% →
1A(26/255)
尺寸百分比
百分比(%)是一种 相对单位,它一定是 相对于某个参考系 计算的
普通元素(非定位):百分比的参考系:父元素的内容区域(content box)
绝对 / 固定定位元素:
- 百分比的参考系:最近的一个定位父元素(
position≠static)的 padding 区域(padding + content(也就是 padding box),不是只有 padding 那一圈) - 如果一直找不到定位父元素,则参考 初始包含块(通常是 viewport)
常见 CSS 属性中百分比的计算方式
| CSS 属性 | 百分比相对于 | 备注 |
|---|---|---|
width | 参考系的 宽度 | 最常见、最直观 |
height | 参考系的 高度 | ⚠️ 前提是参考系有“明确高度” |
padding | 参考系的 宽度 | 包括 padding-top / bottom |
border | ❌ 不支持百分比 | 只能用固定单位 |
margin | 参考系的 宽度 | 包括上下方向 |
CSS 规范规定所有方向的 padding 百分比 统一相对于参考系的宽度
如果父元素没有 明确高度(不是 auto),那么 height: 100% → 无效,因为“参考系高度”本身不存在
可以用 JS 动态设置 padding/margin,但能不用就别用,JS 动态改样式常见隐患是:容易触发 reflow/layout(尤其频繁更新时),逻辑分散:样式跑到 JS 里,后期维护更痛,响应式/主题切换时,CSS 本来更顺手
更推荐 CSS 变量 + JS 改变量,JS 只负责改值,布局规则仍在 CSS 里,维护舒服,或者用 class 切换(最常见)
改动 css 变量是否会触发 reflow/layout 取决于改的这个 CSS 变量“最终影响了什么属性”
- 如果变量用于 会影响布局的属性(如
width/height/padding/margin/top/left/font-size/gap等),改它 会触发 reflow/layout。 - 如果变量只用于 不影响布局的属性(如
color/background-color/border-color/box-shadow/opacity/filter等),通常 不会 reflow(最多 repaint/composite)。
浏览器渲染
重排(layout / reflow)一定会引发重绘(paint),但重绘不一定会触发重排。
现代流程一般是三段:Layout → Paint → Composite
- Layout(重排):算几何信息(位置、大小、换行、盒模型等)
- Paint(重绘):把像素画出来(颜色、背景、边框、阴影、文字等)
- Composite(合成):把各个图层在 GPU 上拼起来(比如 transform、opacity 动画)
所以有时会出现:
- 只合成:不重排、不重绘(最便宜)
- 重绘但不重排:中等成本
- 重排 + 重绘:最贵
“重排必定重绘”通常成立,但有极少数边界情况,一般来说布局变了,画面也要重新画,所以我们工程实践里就当它成立就行。 (真实实现里会有一些优化/裁剪,但不影响你平时的判断。)
快速对照:改哪些属性会发生什么?
只合成(最好)
transformopacity(通常不触发 layout/paint)
重绘,不重排
colorbackground-colorbox-shadow(通常会 paint,且可能比较贵)outline(不改几何,只改外观)
重排(通常还会重绘)
width/heightpadding/margin/border-widthfont-size/line-heightdisplay/position/top/left(改了几何/排版)
现代框架(React/Vue/Angular/Svelte 等)出现的目的,可以总结成几条核心:
- 用“声明式”替代“命令式”DOM 操作,你描述“界面应该长什么样”,框架负责把状态映射成 UI,减少手动
create/append/update的易错代码。 - 用“状态驱动 UI”建立可靠的工程模型,把 UI 当成状态的函数:
UI = f(state),让复杂交互、异步数据、组件协作更可控、更好维护。 - 组件化与复用,支撑大型项目协作,把 UI 拆成可组合的组件,统一规范(props/事件/生命周期),降低团队协作成本和重复劳动。
- 把更新做得更“聪明”(不是消灭重排,而是减少无谓开销),通过 diff/patch、批量更新、调度、缓存等机制:
- 尽量 少改真实 DOM
- 尽量 合并多次更新
- 尽量 把更新放在合适时机,从而让性能“默认不差”,并更容易做进一步优化。
- 提供一整套生态与最佳实践,路由、状态管理、构建工具、类型支持、SSR/SSG、测试等,形成“可复制的工程方案”。
一句话:现代框架的核心是让 UI 开发在复杂场景下依然可维护、可协作、可演进,同时把性能问题尽量变成“默认不糟 + 有路可优化”。
最大/小宽度
- 最大宽度:
max-width - 最小宽度:
min-width - 最大高度:
max-height - 最小高度:
min-height
这些属性用于 限制元素尺寸的变化范围,防止在自适应或内容变化时变得 过大或过小。
当元素的尺寸是:
- 百分比
- 自适应
- 由内容撑开
就可能在不同屏幕尺寸或不同内容下出现不可控的情况,min-* / max-* 的作用就是:在“自适应”的前提下,给尺寸加一道安全边界
在 PC 端开发中,设计稿通常是 固定宽度(如 1200px、1226px、1440px 等),为了保证布局不被压坏,常见做法是给整个页面(或最外层容器)设置一个最小宽度:
html {
min-width: 1226px;
}作用效果
- 当浏览器窗口 ≥ 1226px:页面正常展示
- 当浏览器窗口 < 1226px:页面不再继续压缩,浏览器出现 横向滚动条
这是 PC 端非常常见、也非常合理的做法。
如果图片尺寸大于父容器,而又没有限制,图片可能会撑破布局,尤其在响应式或富文本场景中很常见,因此通常会给所有图片设置最大宽度:
img {
max-width: 100%;
}这样做的好处是图片 最多占满父容器,不会超出容器宽度,同时又不会强制放大小图(比 width: 100% 更安全)
min-width > width > max-width 浏览器会在三者之间取一个 最终合法值
max-width 和百分比搭配非常常见,min-height 常用于:
- 页面最小高度
- 卡片、模块对齐
max-height 常用于:
- 折叠面板
- 内容展开 / 收起(配合
overflow)
表单容器
form 是 HTML 语义化中 专门用于表单提交 的元素,自带一些默认行为:
点击 <button type="submit"> 会触发表单提交
在输入框中按 Enter(回车) 会触发表单提交
会触发 submit 事件
原生支持:表单校验(required、pattern 等)
<form>
<input type="text" />
<button type="submit">提交</button>
</form>div 本身只是一个 普通容器,没有任何表单语义:
- 不会自动触发提交行为
- 在输入框中按回车 不会 有默认提交
- 所有交互行为都需要 JS 手动控制
<div>
<input type="text" />
<button>提交</button>
</div>在现代前端开发(React / Vue 等)中:表单提交通常由 JavaScript 控制,很少直接依赖浏览器的默认提交行为,常见做法是:拦截 submit 事件,使用 AJAX / Fetch / Axios 提交数据,阻止页面刷新(preventDefault)
因此:form 和 div 在功能上的差距被 JS 缩小了,但 form 仍然在语义、可访问性(a11y)和回车提交体验上更合理
在 form 表单中,button 的 type 非常关键:
type="submit"(默认值),点击会触发表单提交
type="button" 点击 不会 触发表单提交,常用于纯交互按钮(弹窗、校验、切换状态等)
如果不写 type,button 默认就是 submit。
input 提供了大量内置属性,用于提升交互体验和基础校验:
placeholder:占位提示文本maxlength:限制最大输入长度disabled:禁用输入readonly:只读(可选中但不可修改)required:必填项(配合form使用)
通过 multiple 属性可以让 select 支持多选,option 可以通过 selected 设置默认选中项
HTML 中的布尔属性特点:selected="selected" 和 selected 效果完全一致,实际开发中通常直接写 selected,更简洁
以下都是 布尔属性:
selectedcheckeddisabledreadonlymultiplerequired
特点:
- 存在即为 true
- 不存在即为 false
- 不需要写两次属性名
定位与背景
CSS 定位(position)定位类型总览
| 值 | 是否脱离文档流 | 参考系 | 常见用途 |
|---|---|---|---|
static | 否(默认) | 无 | 普通布局 |
relative | 否 | 自身原位置 | 微调位置 / 作为定位参考 |
absolute | 是 | 最近定位父元素 | 弹窗、角标 |
fixed | 是 | 视口(viewport) | 悬浮按钮、吸顶 |
sticky | 半脱离 | 最近滚动容器 | 吸顶效果 |
相对定位(relative):不脱离文档流,原位置仍然占着,最常见用途:给子元素的 absolute 提供参考系,或者微调自己的位置
绝对定位(absolute):脱离文档流,参考最近一个 position ≠ static 的祖先,如果找不到 → 参考初始包含块(通常是 viewport),绝对定位的元素会自动变成块级元素,可以直接设置 width / height,不再受行内元素限制
固定定位(fixed):永远相对于 视口,不随页面滚动,常见于:悬浮按钮、客服入口、返回顶部
定位元素居中方式:
已知宽高(经典)
.box {
position: absolute;
top: 50%;
left: 50%;
/* 元素宽度的一半 */
margin-left: -100px;
/* 元素高度的一半 */
margin-top: -50px;
}不定宽高(最常用)
现代最推荐,不依赖尺寸
.box {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}z-index(层级):只对 定位元素(position ≠ static)生效,数值越大,层级越高
常用 background 属性
.box {
background-color: #f5f5f5;
background-image: url(bg.png);
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}background-position
background-position: left top;
background-position: center center;
background-position: 10px 20px;
background-position: 50% 50%;background-size(重点)
| 值 | 说明 |
|---|---|
auto | 原始大小 |
cover | 覆盖容器(可能裁剪) |
contain | 完整显示(可能留白) |
100% 100% | 强行拉伸 |
background 简写(顺序无严格要求)
background: #000 url(bg.png) no-repeat center / cover;CSS 精灵图(Sprite):把多个小图合并成一张大图,用 background-position 显示不同区域
目的:减少 HTTP 请求,提升加载性能
.icon {
width: 32px;
height: 32px;
background-image: url(sprite.png);
background-repeat: no-repeat;
background-position: -64px -32px;
}元素尺寸 = 单个图标尺寸,background-position 用负值
通常配合:hover 切换位置,不同 class 显示不同图标
text-align 和 vertical-align 有什么关系?
基本没直接关系,它们管的是两件不同的事:
text-align:控制 行内内容在一行里的水平对齐方式(横向)
left / right / center / justify- 作用对象:块级容器里的 行内内容(文字、inline 元素、inline-block)
vertical-align:控制 行内级元素在同一行里的垂直对齐方式(纵向)
baseline / middle / top / bottom / text-top / text-bottom / sub / super / <length/%>- 作用对象:inline / inline-block / table-cell(以及某些场景下的替换元素如 img)
text-align:center 不能 让块级元素自身居中(块级靠 margin: 0 auto / flex)。
vertical-align 用于让图片/图标和文字在同一行“垂直对齐”
常用于:图标 + 文本按钮、行内 svg/img 对齐,消除 img 底部那条“神秘空隙”
原因:img 默认是 inline-level,并且默认 vertical-align: baseline,会为文字下行留出下降部件空间,于是底部看起来有缝。
解决:
img { vertical-align: middle; } /* 或 bottom / top */或
img { display: block; } /* 直接不参与行内排版 */vertical-align 对普通块级布局(div 之间)基本没用;块级垂直居中通常用 flex/grid。
基线 可以理解为:一行文字“坐着的那条线”,大部分字形都“落在基线之上”,某些字符会有“下伸部分”(比如英文的 g / p / y),会伸到基线下方(叫 descender)。
在同一行里排版时,浏览器需要一个“对齐基准”:文字与文字对齐,文字与图片/图标(inline/inline-block)对齐,不同字体大小混排时仍然看起来“站在同一条线上”
所以默认 vertical-align: baseline 时:
图片/inline-block 的“底部”会尽量和文字基线对齐,于是就经常出现“图片底部留空隙”的现象(因为要给 descender 留空间)
浮动
float 是 CSS 中的布局属性,用于 让元素脱离标准文档流,向左或向右移动,直到其边缘碰到包含块边缘或另一个浮动元素的边缘。
基本属性值
| 属性值 | 作用 |
|---|---|
none | 默认值,元素不浮动,遵循标准文档流 |
left | 元素向左浮动 |
right | 元素向右浮动 |
脱离标准文档流,但不脱离文本流
浮动元素会脱离标准文档流,父元素默认不会包裹浮动子元素(父元素高度塌陷)。
浮动元素周围的 行内元素(如文本、span)会环绕其排列,这是浮动的核心应用场景(如文字环绕图片)。
/* 示例:文字环绕图片 */
.img-box {
float: left;
width: 100px;
height: 100px;
margin-right: 10px;
}<div class="container">
<img src="pic.jpg" class="img-box">
<p>这里是环绕图片的文本内容,会沿着图片右侧排列...</p>
</div>浮动元素的默认显示模式变化
行内元素(如 span、a)设置浮动后,会自动变成块级元素,可以直接设置 width、height,无需额外加 display: block。
块级元素(如 div)设置浮动后,宽度默认由内容撑开(标准文档流中块级元素宽度默认 100%)。
多个浮动元素的排列规则
同方向浮动的元素,会 从左到右 / 从上到下依次排列,不会重叠(除非宽度不足)。
不同方向浮动的元素,会分别靠向包含块的左右两侧。
浮动元素的排列 受包含块宽度限制,宽度不足时会自动换行。
浮动元素脱离文档流会导致父元素高度为 0,需要通过以下方法清除浮动影响:
- 在父元素内末尾添加一个空的块级元素,设置
clear: both。 - 给父元素添加
overflow: hidden或overflow: auto,触发 BFC(块级格式化上下文),使父元素包裹浮动子元素,但可能隐藏元素溢出部分(如下拉菜单)。 - 通过父元素的
::after伪元素实现清除浮动,是行业最佳实践,语义化、无额外标签,适配所有场景。
.clearfix::after {
content: "";
display: block; /* 伪元素默认是行内,需转块级 */
clear: both;
height: 0; /* 兼容旧浏览器 */
visibility: hidden; /* 兼容旧浏览器 */
}
.clearfix {
*zoom: 1; /* 兼容IE6/7 */
}<div class="parent clearfix">
<div class="child" style="float: left;"></div>
</div>clear 用于指定元素 不允许 有浮动元素的一侧,只对 块级元素 生效。
| 属性值 | 作用 |
|---|---|
none | 默认值,允许两侧有浮动元素 |
left | 左侧不允许有浮动元素 |
right | 右侧不允许有浮动元素 |
both | 左右两侧都不允许有浮动元素 |
浮动的经典应用场景
文字环绕图片:最原生的用途,实现图文混排。
多列布局:早期 CSS 没有 Flex 和 Grid 时,浮动是实现多列布局的核心方案(如两栏 / 三栏布局)
现代布局优先使用 Flex 布局 或 Grid 布局,两者更灵活、强大,无需处理清除浮动问题:
属性值的计算
页面最终展示的效果,取决于 CSS 属性的“计算结果”,而不是你在代码里写了什么。
CSS 代码 不会直接成为最终样式,它只是参与了一个 属性值计算过程
浏览器会保证:每一个 CSS 属性,最终一定都有一个值
从「无属性值」到「每个属性都有值」,CSS 属性的计算过程,可以概括为 4 个步骤:
无属性值
↓
1. 确定声明值
↓
2. 解决层叠冲突
↓
3. 使用继承
↓
4. 使用默认值
↓
每个属性都有值(最终计算结果)确定声明值(Declared Value)
声明值:指在样式表中,能直接匹配到该元素、且没有冲突的 CSS 声明。
来源包括:作者样式表(自己写的 CSS),浏览器默认样式表(UA stylesheet)
层叠冲突(Cascade)
当 同一个属性 有多个声明时,就会发生 层叠冲突。
浏览器会按照以下顺序比较,层叠规则(从高到低):
- **重要性(importance) **
!important> 普通声明 - **特殊性(specificity) ** 行内 > id > class > 标签
- **源次序(source order) ** 后写的覆盖先写的
注意:层叠冲突 只发生在“同一个属性”上
使用继承(Inheritance)
如果某个属性 仍然没有值,并且它是 可继承属性,浏览器会从父元素继承该属性的值,可以通过显式指定继承:color: inherit;
使用默认值(Initial / UA Default)
如果:没有声明值,不能继承,或继承链断了
那么浏览器会使用该属性的 默认值(initial value)。
所有属性最终一定有值,这是 CSS 的底层保证:不存在“没值的属性”,哪怕你没写,浏览器也会:继承或使用默认值
代码 ≠ 最终结果,真正显示的是 计算后的像素值,页面展示的永远是 computed value / used value
inherit 的意义:强制从父元素继承,即使该属性默认不可继承,常用于“打破默认行为”
Flex 布局
Flex(Flexible Box)是一种 一维布局模型,用于在 行或列方向 上对元素进行灵活排列、对齐和分配空间。
设置了 display: flex 的元素将变成 Flex 容器,Flex 容器的 直接子元素 是 flex item,子元素的子元素 不参与 flex 布局
容器属性
flex-direction
主轴(main axis)由 flex-direction 决定,即元素排列的方向
flex-direction确实决定了主轴方向(也就决定了交叉轴方向),等于把布局坐标系转了:row / row-reverse / column / column-reverse= 4 个方向
justify-content控制 主轴(main axis) 上 项目如何分布/对齐
align-items控制 交叉轴(cross axis) 上 每一行内项目如何对齐(默认stretch)多行时(
flex-wrap: wrap产生多行)
align-items还是管“每一行里面怎么对齐”- 但“多行整体在交叉轴怎么排”要用
align-content
flex-direction(主轴方向)
flex-direction: row | row-reverse | column | column-reverse;flex-wrap
flex-wrap(是否换行)
flex-wrap: nowrap | wrap | wrap-reverse;nowrap(默认):不换行,可能挤压元素
wrap:换行
wrap-reverse:反向换行
flex-flow(direction + wrap 简写)
flex-flow: row wrap;justify-content
justify-content(主轴对齐)
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;align-items
align-items(交叉轴对齐:单行)
align-items: stretch | flex-start | flex-end | center | baseline;stretch(默认):拉伸填满交叉轴(需未设高度)
baseline:按文本基线对齐
align-content
align-content(交叉轴对齐:多行)
只有在 flex-wrap: wrap 且多行时才生效
align-content: flex-start | flex-end | center | space-between | space-around | stretch;align-items:控制 每一行内部align-content:控制 多行整体
gap
gap(项目间距)
gap: 20px;
row-gap: 10px;
column-gap: 20px;flex / grid 通用,比 margin 更干净
项目属性
order
order(显示顺序)
order: 0; /* 默认 */数值越小,越靠前,可以是负数,只改变视觉顺序,不改变 DOM 顺序
flex-grow
flex-grow(放大比例)
flex-grow: 1;剩余空间分配比例,0:不放大(默认)
flex-shrink
flex-shrink(缩小比例)
flex-shrink: 1;空间不足时的压缩比例,0:不允许被压缩
flex-basis
flex-basis(初始尺寸)
flex-basis: auto | 0 | 200px | 30%;优先级:max-width/min-width > flex-basis > width
flex
flex(grow + shrink + basis 简写)
flex: 1; /* = 1 1 0 */
flex: auto; /* = 1 1 auto */
flex: none; /* = 0 0 auto */
flex: 0 1 auto;flex: 1:平分剩余空间,flex: none:固定大小
align-self
align-self(单个项目对齐)
align-self: auto | flex-start | flex-end | center | stretch;覆盖 align-items
justify-self 同理
速记:direction 定轴;justify 管主轴;align-items 管交叉轴;多行再加 align-content。
Grid 布局
Grid 布局将容器划分成 "行" 和 "列",可以看作是 二维布局,Grid 布局远比 Flex 布局强大。
采用网格布局的区域,称为 "容器"(container),容器内部采用网格定位的子元素,称为 "项目"(item),项目只能是容器的顶层子元素,不包含项目的子元素,Grid 布局只对项目生效。
容器里面的水平区域称为 "行"(row),垂直区域称为 "列"(column)。
容器属性
display: grid; 指定一个容器采用网格布局,默认情况下,容器元素都是块级元素,但也可以通过 display: inline-grid; 设成行内元素。
注意:设为网格布局以后,容器子元素(项目)的 float、display: inline-block、display: table-cell、vertical-align 和 column-* 等设置都将失效。
grid-template-rows/columns
容器指定了网格布局以后,接着就要划分行和列,grid-template-rows 属性定义每一行的行高,grid-template-columns 属性定义每一列的列宽。
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
}上面代码指定了一个三行三列的网格,列宽和行高都是 100px,除了使用绝对单位,也可以使用百分比。
有时候,重复写同样的值非常麻烦,尤其网格很多时,这时,可以使用 repeat() 函数,简化重复的值:grid-template-columns: repeat(3, 100px);
repeat() 接受两个参数,第一个参数是重复的次数,第二个参数是所要重复的值,也可以是某种模式 grid-template-columns: repeat(2, 100px 20px 80px);,定义了 6 列,第一列和第四列的宽度为 100px,第二列和第五列为 20px,第三列和第六列为 80px。
有时,单元格的大小是固定的,但是容器的大小不确定。如果希望每一行(或每一列)容纳尽可能多的单元格,这时可以使用 auto-fill 关键字表示自动填充:grid-template-columns: repeat(auto-fill, 100px);
除了 auto-fill,还有一个关键字 auto-fit,两者的行为基本是相同的。
详细
grid-template-columns: repeat(auto-fill|auto-fit, minmax(..., ...));repeat(auto-xxx, ...):让浏览器“能塞多少列就塞多少列”
minmax(min, max):每一列的宽度在 min~max 之间可变(max 如果是 1fr / auto 这类可伸缩值,就会参与分剩余空间)
auto-fill:就算最后那几列没有内容,也会把“列的坑位”保留下来(等于有“空列”存在),所以剩余空间会被这些空列也参与分配/占位,看起来像“用空格子填满”。auto-fit:会把“没有内容的列坑位”折叠成 0(当它们是空的时),于是剩余空间只能分给真正有内容的列,看起来像“把已有单元格撑大”。
注意:这里的“空列”指的是 没有任何 grid item 占用的列轨道,不是你肉眼看到的空白区域。
比如容器很宽,理论上可以塞下 6 列,而你只有 3 个 item,差别就来了:
auto-fill:会生成 6 列(后 3 列空着)auto-fit:也会“尝试”生成 6 列,但发现后 3 列没人用 → 折叠掉 → 最终等效只剩 3 列
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));,因为 1fr 会吃剩余空间:
auto-fill:空列也在 → 剩余空间会被更多列分掉 → 每个真实卡片不一定能撑很大auto-fit:空列折叠掉 → 剩余空间只给有内容的列 → 卡片就更容易被撑大铺满
在 90% 的实际开发里,auto-fill 和 auto-fit 基本不用纠结。,无脑用 auto-fit,它更符合“视觉直觉”,没东西就别留坑。
为了方便表示比例关系,网格布局提供了 fr 关键字(fraction 的缩写,意为 "片段"),如果两列的宽度分别为 1fr 和 2fr,就表示后者是前者的两倍。
grid-template-columns: 1fr 1fr; 表示两个相同宽度的列
fr 可以与绝对长度的单位结合使用,这时会非常方便。
grid-template-columns: 150px 1fr 2fr; 表示,第一列的宽度为 150 像素,第二列的宽度是第三列的一半。
minmax() 函数产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。
在 grid-template-columns: 1fr 1fr minmax(100px, 1fr); 中,minmax(100px, 1fr) 表示列宽不小于 100px,不大于 1fr。
auto 关键字表示由浏览器自己决定长度,grid-template-columns: 100px auto 100px;,第二列的宽度,基本上等于该列单元格的最大宽度,除非单元格内容设置了 min-width,且这个值大于最大宽度。
grid-template-columns 属性和 grid-template-rows 属性里面,还可以使用方括号,指定每一根网格线的名字,方便以后的引用。
.container {
display: grid;
grid-template-columns: [c1] 100px [c2] 100px [c3] auto [c4];
grid-template-rows: [r1] 100px [r2] 100px [r3] auto [r4];
}上面代码指定网格布局为 3 行 x 3 列,因此有 4 根垂直网格线和 4 根水平网格线。
方括号里面依次是这八根线的名字,网格布局允许同一根线有多个名字,比如 [fifth-line row-5]。
grid-template-columns 属性对于网页布局非常有用,两栏式布局只需要一行代码: grid-template-columns: 70% 30%;,表示将左边栏设为 70%,右边栏设为 30%。
传统的十二网格布局,写起来也很容易:grid-template-columns: repeat(12, 1fr);
grid-row-gap
grid-row-gap 属性设置行与行的间隔(行间距),grid-column-gap 属性设置列与列的间隔(列间距)
grid-gap 属性是 grid-column-gap 和 grid-row-gap 的合并简写形式:grid-gap: <grid-row-gap> <grid-column-gap>;
最新标准中,上面三个属性名的 grid- 前缀已经删除,grid-column-gap 和 grid-row-gap 写成 column-gap 和 row-gap,grid-gap 写成 gap。
grid-template-areas
网格布局允许指定 "区域"(area),一个区域由单个或多个单元格组成,grid-template-areas 属性用于定义区域。
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
grid-template-areas: 'a b c'
'd e f'
'g h i';
}上面代码先划分出 9 个单元格,然后将其定名为 a 到 i 的九个区域,分别对应这九个单元格。
多个单元格合并成一个区域的写法如下。
grid-template-areas: 'a a a'
'b b b'
'c c c';grid-template-areas: "header header header"
"main main sidebar"
"footer footer footer";上面代码中,顶部是页眉区域 header,底部是页脚区域 footer,中间部分则为 main 和 sidebar。
如果某些区域不需要利用,则使用 "点"(.)表示。
grid-template-areas: 'a . c'
'd . f'
'g . i';上面代码中,中间一列为点,表示没有用到该单元格,或者该单元格不属于任何区域。
注意,区域的命名会影响到网格线。每个区域的起始网格线,会自动命名为 区域名-start,终止网格线自动命名为 区域名-end。
比如,区域名为 header,则起始位置的水平网格线和垂直网格线叫做 header-start,终止位置的水平网格线和垂直网格线叫做 header-end。
grid-auto-flow
划分网格以后,容器的子元素会按照顺序,自动放置在每一个网格。默认的放置顺序是 "先行后列",即先填满第一行,再开始放入第二行,即下图数字的顺序。
这个顺序由 grid-auto-flow 属性决定,默认值是 row,即 "先行后列"。也可以将它设成 column,变成 "先列后行":grid-auto-flow: column;
grid-auto-flow 属性除了设置成 row 和 column,还可以设成 row dense 和 column dense,这两个值主要用于,某些项目指定位置以后,剩下的项目怎么自动放置,主要用于 尽可能紧密填满,尽量不出现空格。
dense 的核心目的: 尽量把后面出现的“更小的 item”塞进前面留下的空洞,减少空格。
justify/align-items
justify-items 属性设置单元格的水平位置(左中右),align-items 属性设置单元格的垂直位置(上中下)。
也就是说:justify-items / align-items 对齐的是 grid item 在它自己的 grid cell 里 的位置,而 grid item 里“内容怎么对齐”,那是 item 自己内部的事(比如 text-align、或者 item 里面再用 flex/grid)。
.container {
justify-items: start | end | center | stretch;
align-items: start | end | center | stretch;
}这两个属性的写法完全相同,都可以取下面这些值。
- start:对齐单元格的起始边缘。
- end:对齐单元格的结束边缘。
- center:单元格内部居中。
- stretch:拉伸,占满单元格的整个宽度(默认值)。
place-items 属性是 align-items 属性和 justify-items 属性的合并简写形式:place-items: <align-items> <justify-items>;,如果省略第二个值,则浏览器认为与第一个值相等。
justify/align-content
justify-content 属性是 整个内容区域 在容器里面的水平位置(左中右),align-content 属性是整个内容区域的垂直位置(上中下)。
justify-content:整个 grid 内容区域 在 容器里 怎么摆
justify-items:每一个 grid item 在 自己的格子里 怎么摆
.container {
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
align-content: start | end | center | stretch | space-around | space-between | space-evenly;
}start - 对齐容器的起始边框。
end - 对齐容器的结束边框。
center - 容器内部居中。
stretch - 项目大小没有指定时,拉伸占据整个网格容器。
space-around - 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍。
space-between - 项目与项目的间隔相等,项目与容器边框之间没有间隔。
space-evenly - 项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔。
place-content 属性是 align-content 属性和 justify-content 属性的合并简写形式:place-content: <align-content> <justify-content>,如果省略第二个值,浏览器就会认为第二个值等于第一个值。
grid-auto-rows/columns
隐式网格:
只声明了部分行/列(显式网格),但某个 item 被你放到了“网格外面”,浏览器就得 临时补行/补列 把它放进去;而 grid-auto-rows/columns 就是用来规定这些“临时补出来的行/列”尺寸的。
grid-template-columns: repeat(3, 100px);这表示:明确声明了 3 列,但没有声明 grid-template-rows,所以行数并没写死(行可能会根据需要自动长出来)。
隐式网格(浏览器补出来的),如果某个 item 你指定它去 “第 5 行” 或 “第 5 列”,那就超出你声明的范围了,浏览器就会自动补齐缺的行/列,让它有地方站。
.container{
display: grid;
grid-template-columns: repeat(3, 100px); /* 只声明了列 */
}
.item{
grid-row: 5; /* 强行放第5行 */
}没声明行,但 item 要去第 5 行,那浏览器只能补出第 1~5 行(至少补到 5 行),否则 item 没地方放,这些补出来的行就是 隐式行。
默认情况(不写 grid-auto-rows),隐式行的高度默认是 auto:由这一行里内容撑开,所以看到的现象可能是:有的隐式行很高,有的很矮,不一致。
grid-auto-rows: 80px; 意思是:以后浏览器 自动补出来的每一行 都固定 80px 高,grid-auto-columns: 120px; 同理,它们的“写法和 template 完全相同,可以写 repeat()、minmax()、fr 等。
写 repeat() 就是让“自动补出来的隐式行/列”按一个循环模式来取尺寸。
grid-auto-rows: 80px 120px;:隐式行会按 80、120、80、120… 循环。
用 repeat() 写就是:
grid-auto-rows: repeat(999, 80px 120px); /* 实际不用写999,只是表达循环模式 */grid-auto-rows: minmax(100px, auto); 至少 100px,高度不够就让内容撑大。
grid-template 属性是 grid-template-columns、grid-template-rows 和 grid-template-areas 这三个属性的合并简写形式。
grid 属性是 grid-template-rows、grid-template-columns、grid-template-areas、 grid-auto-rows、grid-auto-columns、grid-auto-flow 这六个属性的合并简写形式。
从易读易写的角度考虑,还是建议不要合并属性。
项目属性
grid-column/row-start/end
项目的位置是可以指定的,具体方法就是指定项目的四个边框,分别定位在哪根网格线。
grid-column-start属性:左边框所在的垂直网格线grid-column-end属性:右边框所在的垂直网格线grid-row-start属性:上边框所在的水平网格线grid-row-end属性:下边框所在的水平网格线
.item-1 {
grid-column-start: 2;
grid-column-end: 4;
}表示 1 号项目的左边框是第二根垂直网格线,右边框是第四根垂直网格线,没有指定上下边框,所以会采用默认位置
其他项目都没有指定位置,由浏览器自动布局,这时它们的位置由容器的 grid-auto-flow 属性决定,这个属性的默认值是 row,因此会 "先行后列" 进行排列。
指定四个边框位置的效果:
.item-1 {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 2;
grid-row-end: 4;
}这四个属性的值,除了指定为第几个网格线,还可以指定为网格线的名字。
.item-1 {
grid-column-start: header-start;
grid-column-end: header-end;
}这四个属性的值还可以使用 span 关键字,表示 "跨越",即左右边框(上下边框)之间跨越多少个网格。
.item-1 {
grid-column-start: span 2;
}
/* 等于 */
.item-1 {
grid-column-end: span 2;
}表示 1 号项目的左边框距离右边框跨越 2 个网格。
使用这四个属性,如果产生了项目的重叠,则使用 z-index 属性指定项目的重叠顺序。
grid-column 属性是 grid-column-start 和 grid-column-end 的合并简写形式,grid-row 属性是 grid-row-start 属性和 grid-row-end 的合并简写形式。
.item {
grid-column: <start-line> / <end-line>;
grid-row: <start-line> / <end-line>;
}.item-1 {
grid-column: 1 / 3;
grid-row: 1 / 2;
}
/* 等同于 */
.item-1 {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 2;
}这两个属性之中,也可以使用 span 关键字,表示跨越多少个网格。
.item-1 {
background: #b03532;
grid-column: 1 / 3;
grid-row: 1 / 3;
}
/* 等同于 */
.item-1 {
background: #b03532;
grid-column: 1 / span 2;
grid-row: 1 / span 2;
}斜杠以及后面的部分可以省略,默认跨越一个网格。
.item-1 {
grid-column: 1;
grid-row: 1;
}grid-area
grid-area 属性指定项目放在哪一个区域。
.item-1 {
grid-area: e;
}grid-area 属性还可用作 grid-row-start、grid-column-start、grid-row-end、grid-column-end 的合并简写形式,直接指定项目的位置。
.item {
grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
}.item-1 {
grid-area: 1 / 1 / 3 / 3;
}justify/align-self
justify-self 属性设置单元格内容的水平位置(左中右),跟 justify-items 属性的用法完全一致,但只作用于单个项目。
align-self 属性设置单元格内容的垂直位置(上中下),跟 align-items 属性的用法完全一致,也是只作用于单个项目。
.item {
justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;
}- start:对齐单元格的起始边缘。
- end:对齐单元格的结束边缘。
- center:单元格内部居中。
- stretch:拉伸,占满单元格的整个宽度(默认值)。
place-self 属性是 align-self 属性和 justify-self 属性的合并简写形式:place-self: <align-self> <justify-self>;,如果省略第二个值,place-self 属性会认为这两个值相等。
补充
justify-items:写在 grid container 上,控制所有 grid item在各自 cell 里的水平对齐方式(默认值)。justify-self:写在 某个 grid item 上,只控制这个 item 自己在 cell 里的水平对齐(覆盖默认值)。
align-items / align-self 同理,只是方向变成垂直。
拓展
grid-template-columns: repeat(3, max-content);意思就是:固定 3 列,每一列的宽度都取“这一列里内容最宽的那个元素所需要的宽度”。
max-content:内容“不换行、完整显示”时需要的宽度(最大理想宽度)
min-content:内容能压到多窄就多窄(会尽可能换行/断行)
auto:更像“由布局算法决定”,常见情况下会拉伸或结合剩余空间
1fr:按剩余空间均分(最常用的等分列)
文字不换行
white-space: nowrap;作用:
- 禁止文本自动换行
- 不管多长,都会在一行里撑开
不换行 + 超出省略号
.text {
white-space: nowrap; /* 不换行 */
overflow: hidden; /* 超出隐藏 */
text-overflow: ellipsis; /* ... */
}注意:必须有宽度!,不然省略号不会生效。
.text {
width: 200px;
}选择器
紧贴(没有空格)= 同一个元素叠条件
含义:选中“同一个元素”同时满足多个条件。
li.active选中:标签是li,并且 class 包含active的 同一个元素.options.expand选中:class 同时有options和expand的 同一个元素
典型用途:精准选中某个状态类(active / disabled / open)
空格 = 后代选择器(descendant)
含义:在 A 里面找 B(B 是 A 的后代,儿子/孙子都算)。
.options li .active读法:在.options里面找li,再在这个li里面找一个后代元素.active
注意:这里 .active 必须是 li 里面的某个子元素,而不是 li 自己。
子代选择器 > = 只找“亲儿子”
含义:B 必须是 A 的直接子元素,不能隔层。
.options > li选中:.options的直接子元素li
用途:结构稳定时更精准,避免“隔层误伤”。
兄弟选择器(同级之间)
相邻兄弟 +
含义:选中紧挨着的下一个兄弟。
.title + .options 选中:紧跟在 .title 后面的那个 .options
用途:常用于“标题 + 下拉面板”这种结构。
通用兄弟 ~
含义:选中后面所有同级兄弟(不要求紧挨)。
.title ~ .options 选中:.title 后面所有同级的 .options