1. 这篇"第六讲"想解决什么:从高频热搜里筛出来的真问题
CSS 语法学习文档写到第六篇,说实话有点"越写越不知道该写什么基础"的意思。前五篇多半在过盒模型、定位、浮动、Flex 的入门用法、动画的基础属性,到这一篇如果还停留在"display 有哪些取值""position 有几种定位"这种层面,那读者大概率已经不需要看了。
所以这次我换了个思路。我把自己平时在社区答疑、代码评审、以及各种前端群里看到的、大家反复问的高频问题拉了一遍,从 Flex 子元素宽度为什么"不听话"、兄弟元素怎么选、伪元素能不能用变量控制,到小程序底部安全区兼容、涟漪光圈扩散特效、字体渐变、单行省略这种看似简单却天天有人踩坑的点,都收进了这一篇。
这套内容没有严格的递进关系,每一节都能单独看。你如果正卡在某个问题上,直接跳到对应小节就行;如果你是想系统查漏补缺,顺着读下来会发现很多"哦,原来还能这样"的细节。整体定位是:Flex 布局的隐性规则、选择器与样式作用域的进阶用法、纯 CSS 特效的拆解思路、移动端适配里的兼容细节,以及文本处理和打包报错的收尾技巧。适合已经能独立写页面、但希望把 CSS 从"能写"提升到"写得稳"的同学。
另外说明一下,这是一篇实践笔记,不是规范文档。文中所有结论我都尽量标注了"为什么",但更重要的还是你自己动手改一遍参数、看一下效果差异,这个习惯比背任何属性都值钱。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Flex 布局里那些"看似自适应、实则不听话"的宽度问题
2.1 flex: 1 到底让子元素做了什么
热搜里"css flex 布局子元素宽度自适应"这条,几乎每周都能看到。很多人给子元素写 flex: 1 之后发现,宽度确实撑开了,但两个子元素放一起,一个被内容撑得很宽、一个被压缩得很窄,怎么看都不像是"自适应"。
先说结论:flex: 1 是 flex-grow: 1; flex-shrink: 1; flex-basis: 0% 的缩写。它解决的是"剩余空间怎么分"的问题,不是"宽度怎么变成一样"的问题。
css复制.parent {
display: flex;
width: 600px;
}
.child {
flex: 1;
border: 1px solid #ccc;
}
父容器 600px,两个子元素各分到 300px,这时候看着是"等宽自适应"。但如果其中一个子元素里放了一长串不换行的英文或者一张很宽的图片,这个平衡立刻就被打破了。原因是 Flex 布局里有个默认行为:子元素的 min-width 是 auto,意思是"我的内容多宽,我就至少要多宽"。所以不管你怎么分剩余空间,内容本身的宽度会反过来撑住这个元素,把它顶得比理论上更宽。
这就是"不听话"的根源。要让它听话,给子元素加一行:
css复制.child {
flex: 1;
min-width: 0;
}
把 min-width 改成 0,等于告诉浏览器:不用照顾我的内容,剩余空间怎么分我就怎么接。这个技巧在"左侧固定头像、右侧自适应文本"这种布局里几乎是必用的,不然右侧文字一长,整个布局就崩了。
2.2 固定 + 自适应两栏布局的可靠写法
实战里最常见的结构是:左边一个固定宽度的按钮或图标,右边文本区域自动占满剩余宽度。教科书上给的方案是 flex: 1,但真正稳的写法要配合 min-width: 0 和 overflow 一起用:
css复制.card {
display: flex;
align-items: center;
padding: 16px;
}
.card__icon {
flex: 0 0 40px;
height: 40px;
margin-right: 12px;
border-radius: 50%;
background: #409eff;
}
.card__content {
flex: 1;
min-width: 0;
}
.card__content p {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
这里 flex: 0 0 40px 表示不放大、不缩小、基准宽度 40px,右边的 flex: 1 负责吸收所有剩余空间。再加上 min-width: 0 和文本省略,整个结构无论左边图标怎么换、右边文字多长,都不会把布局撑破。
提示:
flex: 1和flex: auto是两回事。前者flex-basis是 0%,后者是auto,也就是"以内容宽度为基准"。两者在内容很短时看着差不多,内容一长差异就出来了。拿不准的时候统一用flex: 1加min-width: 0,行为最可预期。
2.3 间距别再一个个加 margin 了:gap 的兼容与降级
Flex 容器里的间距,老写法是给每个子元素加 margin-right,再给最后一个子元素去掉。这种写法不是不行,而是当子元素由前端动态渲染出来时,last-child 的判断很容易出问题。CSS 社区等了很多年的 gap 属性终于在 Flex 布局里普及了:
css复制.parent {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
gap 会同时处理行间距和列间距,而且不会在容器边缘多加一份间距。这个属性在 Chrome 84+、Safari 14.1+、Firefox 63+ 都已经支持,2024 年之后的项目基本可以放心用。如果你的用户群还有大量旧版移动端 WebView,稳妥做法是用 @supports 做降级:
css复制.parent {
display: flex;
flex-wrap: wrap;
margin: -8px;
}
.parent > * {
margin: 8px;
}
@supports (gap: 16px) {
.parent {
gap: 16px;
margin: 0;
}
.parent > * {
margin
