开头
CSS这东西,入门容易,写好难。平时写页面,很多同学能写出一堆能跑的样式,但一遇到“为什么这个flex子项被压扁了”“为什么覆盖不了Bootstrap的样式”“为什么动画一开就掉帧”这种问题就卡住,根源往往不是别的,就是基础概念没扎牢。这篇“CSS基础知识分享2”,我们继续沿着基础往深处走,把选择器、Flex布局宽度自适应、字体排版细节、动画动效、Bootstrap样式覆盖这几个点挨个拆一遍,每个点都配上实际场景和可复现的代码。
这篇内容适合两类人:一类是刚把CSS语法过了一遍、正在尝试写完整页面的前端入门者;另一类是写了两三年CSS但全靠“试出来”的开发者——相信我,看完选择器和Flex的原理部分,你至少能少走一半弯路。全文没有废话,每个知识点都会说清楚“为什么”,不是填鸭式的语法清单。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
1. 选择器不熟,写再多样式也是盲写
1.1 基础选择器和组合选择器,你真的用对了吗
选择器是CSS的入口,也是大多数样式问题的源头。我不止一次在code review里看到类似 .nav ul li a:hover 这种五六层嵌套的选择器,说实话这种写法既难读又难维护。CSS选择器不是越详细越好,它讲究的是“够用且不过度”。常用基础选择器就五类:标签选择器、类选择器、ID选择器、通配选择器、属性选择器。其中类选择器的复用性最强,ID选择器的权重最高但最不该乱用,属性选择器在表单样式和动态类名场景下非常能打。
组合选择器这块,很多人容易混淆的是后代选择器和子代选择器。.parent .child 选的是所有后代,哪怕中间隔了三层;.parent > .child 只选直接子元素。实际开发里,如果你写的是组件化页面,几乎只需要子代选择器;一旦用了后代选择器,就要做好心理准备:任何一层DOM结构变化都可能让样式失控。相邻兄弟选择器 .a + .b 和通用兄弟选择器 .a ~ .b 也常被忽略,但这两个在实现“当前项高亮时联动后面的元素”这种交互时非常省事。
组合选择器的权重计算也是个高频考点。内联样式1000,ID选择器100,类/属性/伪类10,标签/伪元素1。注意,通配选择器权重是0,但它的特殊性依然高于继承值。很多人以为 div .box 一定压过 .box.red,其实算一下:前者是1+10=11,后者是10+10=20,后者赢。这类问题在面试题里经常出现,但在实际调试里更能救命——因为你会遇上一个样式死活不生效,最后发现就是权重不够。
1.2 伪类和伪元素:形态和状态要分清
伪类和伪元素是CSS基础里最容易被混为一谈的部分。我见过不少新人用 ::after 做了个图标,然后困惑为什么设置 content: "" 才能显示出来——因为伪元素本质上是创建了一个不属于DOM树但真实渲染的子元素,而伪类是依附于既有元素的状态描述,比如 :hover、:focus、:nth-child()。
伪元素主要用于装饰和内容注入。::before 和 ::after 必须配合 content 属性使用,哪怕是空的 content: "" 也必须写,否则整个伪元素不会渲染。想画一个气泡尾巴、做一道分割线、给文字加渐变色蒙层,优先考虑这两个伪元素。::first-line 和 ::first-letter 在做排版细节时非常好用,比如首字下沉、首行缩进,不需要额外包一层span。
伪类这边,除了最常见的 :hover、:active、:focus,我建议你把结构性伪类吃透。:nth-child(2n+1) 做奇偶行变色;:not(.disabled) 配合表单状态;:empty 处理空状态占位提示。还有一个很实用但容易被忽略的 :focus-within——只要子元素里有任意一个获得焦点,父元素就匹配该伪类,做卡片聚焦高亮效果非常舒服,不用写JS监听focus事件了。
伪元素上还有个容易被忽略的小技巧:可以用伪元素配合CSS变量做“类选择器参数化”。比如你写一个按钮,不同颜色场景下不想重复写一堆类名,可以定义 .btn { --btn-bg: #4a90d9; },然后 .btn::before { background: var(--btn-bg); },调用时只需要在HTML里用内联style把 --btn-bg 改成对应颜色就行。这个思路在组件化开发里非常实用,具体写法下面会再展开。
1.3 用CSS变量,让同一个类根据不同参数变化
“CSS类根据参数不同使用不同的类”这个需求,看起来像是在问“我该不该动态切换类名”,其实更优雅的解法是CSS自定义属性,也就是常说的CSS变量。CSS变量的好处是:它在运行时生效,它的“参数”可以从父元素继承,也可以直接通过内联样式传进去。
举个例子。你有一个消息提示组件,分为成功、警告、错误三种状态。常规写法是写三个类 .msg-success、.msg-warning、.msg-error,每个类把背景色、边框色、图标色都写一遍。用CSS变量的写法是:
css复制.msg {
--msg-color: #333;
--msg-bg: #f5f5f5;
color: var(--msg-color);
background: var(--msg-bg);
border-left: 4px solid var(--msg-color);
}
然后在使用时通过内联变量指定:
html复制<div class="msg" style="--msg-color: #2e7d32; --msg-bg: #e8f5e9;">保存成功</div>
<div class="msg" style="--msg-color: #c62828; --msg-bg: #ffebee;">保存失败</div>
这样写的好处是明显的:主题色、状态色集中管理,后续要加个“信息”状态,不需要动CSS文件里一坨类,只需要在HTML侧换个变量值。这个思路在维护大型项目时尤其有用,避免了一旦状态变多,类名也跟着无限膨胀的问题。
2. Flex布局,解决“宽度自适应”这一件事
2.1 理解 flex-grow、flex-shrink、flex-basis 这条大腿
Flex布局最让人头疼的其实是它的三大属性:flex-grow、flex-shrink、flex-basis。很多人都是直接写 flex: 1,然后发现子元素宽度有时按预期增长,有时又被压缩得不成样子。要搞明白这个,先记住一条核心规则:flex-basis 决定主轴上的初始大小,flex-grow 决定剩余空间怎么分配,flex-shrink 决定空间不够时怎么收缩。
flex-basis 默认值是 auto,意思是取元素的 width 属性;如果写 flex-basis: 0,那所有子元素都忽略width,完全根据 flex-grow 按比例分。这就是为什么 flex: 1 能让多个子元素等分宽度——它等价于 flex: 1 1 0%,初始大小从零开始,剩余空间全部按比例分给每个子项。
flex-shrink 这条很多人栽过。默认值是1,也就是所有子项都可以收缩。如果你不想让某个子项被压缩,必须显式设置 flex-shrink: 0。典型场景是侧边栏固定宽度、中间内容自适应:侧边栏写 width: 240px; flex-shrink: 0,这样容器再窄也不会把侧边栏挤扁。不加的话,容器宽度不足时,240px 会被自动压缩,布局直接变形。
flex-grow 的分配规则也要说细一点:假设容器还有200px剩余空间,三个子项的 flex-grow 分别是1、2、3,那它们分到的额外空间就是 200×(1/6)、200×(2/6)、200×(3/6)。新手容易把它理解成“按比例设置最终宽度”,其实不是,它只是分配剩余空间,最终宽度还要加上自身的基础宽度,两者要区分开。
2.2 子元素宽度自适应的三种经典场景
“flex布局子元素宽度自适应”是特别常见的需求,我拆成三个经典场景来说,你们对号入座就能直接用。
场景一:等分布局。 三个卡片,宽度均分。每个子项写 flex: 1 即可,不需要算百分比。它比 width: 33.33% 强的地方在于:如果有一项内容特别多,不会因为固定百分比导致换行或者溢出,flex会自动调整。当然,如果你需要严格等分且每个卡片内容长度差异很大,配合 min-width: 0 或者 overflow: hidden 来防止内容把布局撑破,这个细节下面单独说。
场景二:固定侧栏 + 自适应主体。 这是后台管理系统的标配布局:左边菜单宽度固定,右边内容区自适应剩余宽度。结构上只需要让父容器 display: flex,左侧 width: 240px; flex-shrink: 0,右侧 flex: 1; min-width: 0。这里的 min-width: 0 很关键,因为flex子项的 min-width 默认值是 auto,意思是子项的最小宽度不能小于内容宽度,如果内容里有一张很大的图片或者一长串不换行的英文,它会把右区域撑出横向滚动条,加了 min-width: 0 就允许子项收缩到容器宽度以内。
场景三:标签栏平均分配。 类似tab标签,需求是数量不固定,但始终平分整行宽度。这个和场景一一样,用 flex: 1 就能解决。但要注意:如果标签文字很长,为了让文字在较窄空间里显示省略号,需要在标签元素上同时加 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;。然后整个标签栏就不需要JS去动态计算宽度了,纯flex搞定。
2.3 Flex布局里的隐藏陷阱
第一个坑:flex容器默认不换行。flex-wrap 默认是 nowrap,意味着所有子项挤在一行里,空间不足时优先收缩而不是换行。如果你需要子项在窄屏下自动换行,必须显式写 flex-wrap: wrap,并且配合子项上的 flex-basis 来限定每行放几个。比如你想做个两列自适应卡片,子项写 flex: 0 1 calc(50% - 20px),这样每行最多两个,中间留20px间距。
第二个坑:flex子项的 margin: auto 是不同玩法。margin: auto 在flex布局里不只是居中,它会吃掉所有剩余空间。比如顶部栏里有个按钮,想让按钮靠右,不需要 justify-content: space-between,直接把按钮的 margin-left: auto 就能把它推到右侧。这个技巧在处理导航栏、列表项右侧操作按钮时特别简单粗暴。
第三个坑:flex和百分比宽度混用时的比例问题。如果你在flex容器里给子项写 width: 50%,但这个容器不够宽的时候,子项会先按 flex-shrink 缩放,而不是保持50%。很多人因此产生困惑:我明明写了50%,为什么变成45%了?这其实不是bug,而是flex的收缩机制在生效。当你希望子项严格按百分比占位时,需要显式写 flex-shrink: 0。
3. 字体、文本和排版细节,页面质感的分水岭
3.1 字体栈,别只写一个 font-family
字体这块,很多初学者在 font-family 里只写一个字体名,比如 font-family: "Microsoft YaHei"。这在Windows上没问题,换成macOS或者手机端就直接退回到浏览器默认字体,排版瞬间崩掉。正确的做法是写一组字体栈,按优先级从前往后排列。中文字体栈的常见写法:
css复制body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
"Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
}
这个字体栈的意思是:苹果系统用苹方,微软系统用雅黑,都没有就退回Arial。这里有一个容易被忽略的点:字体栈的优先级是“逐个尝试,找不到就用下一个”。字体名如果包含空格,必须加引号,否则会被解析成两个字体。还有,如果你字体栈里的某个字体只在部分系统里存在,比如 "Helvetica Neue" 在Windows上没有,就会跳到下一个,这没问题,但如果你把它放在前面,Windows用户会直接跳过它,并不会报错——这也是为什么标题和正文最好分开设置字体栈,标题追求设计感,正文追求可读性。
3.2 字体渐变和金光闪闪的效果,用伪元素 + 背景裁剪实现
“CSS字体渐变”“CSS如何做出来金光闪闪的效果”这两个热搜词,背后是同一个核心技术:background-clip: text。用背景色渐变填充文字,同时把背景裁剪到文字形状。
css复制.gradient-text {
background: linear-gradient(90deg, #f6d365, #fda085, #f6d365);
background-size: 200% 100%;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: shine 3s linear infinite;
}
@keyframes shine {
0% { background-position: 0% 0; }
100% { background-position: 200% 0; }
}
这个写法做了三件事:第一,用渐变背景色当文字颜色;第二,background-clip: text 把背景裁剪到文字轮廓内;第三,color: transparent 把原始文字颜色变成透明,这样露出来的就是背景色。最后加了个背景位置循环动画,文字里就出现了“金光扫过”的效果。注意,-webkit-background-clip 这个前缀目前仍然需要,因为Safari等一些浏览器对无前缀的 background-clip: text 支持不完整。
同样用 background-clip: text,你还可以做图片文字、动态流光字、渐变标题。做这类效果时有几个细节要留意:一是 color: transparent 必须设置,否则文字颜色会遮住背景;二是如果元素的背景是渐变的,它默认背景区域是整个元素盒子,所以给 background-size 放大到200%再动画,扫光效果才流畅;三是一些浏览器对 background-clip: text 有兼容性问题,正式项目里建议使用 @supports 做特性检测,不支持的环境退回纯色文字。
3.3 文字竖排、超出省略和控制文本位置
“CSS文字竖着排列”这个需求,以前都是靠 writing-mode 或者旋转来实现。writing-mode: vertical-rl 是正统方案,它能让中文文本像古书那样自上而下、从右往左排列,非常适用于竖排标题、印章、装饰文案。注意它和 transform: rotate(90deg) 有本质区别:旋转只是视觉上转了90度,排版逻辑没变,但 writing-mode 会重新参与文档流布局,文字宽度、行高、对齐方式都是竖排的专用规则,多行文本换行方式也完全不同。
“CSS超出显示省略号”同样是高频需求。单行省略号的写法是 white-space: nowrap; overflow: hidden; text-overflow: ellipsis;,三条缺一不可。多行省略号在WebKit内核浏览器里可以用 display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; 实现。这里有个容易栽的坑:如果父容器是flex布局且子项是flex项,单行省略号经常失效,因为flex子项默认 min-width: auto,内容会撑开它,导致 overflow: hidden 失效。解决办法是给该子项加 min-width: 0 或者 overflow: hidden 本身就能触发新的格式化上下文,但最稳妥的还是 min-width: 0。
关于“调整CSS容器里的文本位置”,这其实是个大杂烩问题。文本在容器里的位置一般由 text-align(水平方向)、line-height(垂直方向)、padding 三个属性共同决定。垂直居中文本的老办法是设置 line-height 等于容器高度,但容器高度变化或者有多行文字时就失灵;推荐用 flex 或 grid 布局让文本居中:display: flex; align-items: center; justify-content: center;,这才是一劳永逸的解法。另外,vertical-align 只对行内元素和表格单元格生效,用在块级元素上没用,这个误区很多人都有。
4. 动画与动效,把CSS写“活”
4.1 涟漪光圈扩散效果的实现思路
“CSS涟漪光圈扩散”是很多按钮、地图定位点、卡片提示上常见的动效。它的核心不复杂:用 ::before 或 ::after 做一个逐渐放大的圆圈,同时把透明度从1降到0,并且循环播放。难点在于“怎么做出一圈一圈连续扩散”的层次感。
基础版的做法:
css复制.ripple {
position: relative;
width: 120px;
height: 120px;
border-radius: 50%;
background: rgba(64, 158, 255, 0.3);
}
.ripple::after {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
background: inherit;
animation: ripple 2s ease-out infinite;
}
@keyframes ripple {
0% {
transform: scale(1);
opacity: 1;
}
100% {
transform: scale(2.4);
opacity: 0;
}
}
这里的关键点是 inset: 0 让伪元素和父元素完全重叠,然后再通过 transform: scale() 让它放大。如果想要多个光圈,可以用 ::before 和 ::after 各做一个,把动画延迟错开,形成连续波纹。另外很多实现里会出现一个bug:用了 transform: scale 之后,动画结束回到原始状态时会有一次“闪烁”,这是因为动画在循环之间重新执行,元素先缩回原尺寸再放大。要避免这种闪断感,可以在动画关键帧的0%里加 opacity: 0,让它在缩到最小且完全透明的时候重置。
4.2 hover延迟关闭,交互手感更舒服
“CSS hover延迟关闭”这个需求,经常出现在下拉菜单、悬浮卡片、tooltip上。默认情况下,鼠标移出元素,hover样式立即消失,这会产生“刚移动过去就关闭了”的尴尬体验。CSS里有两个延迟相关的属性:transition-delay 和 transition-duration。前者是延迟多久开始过渡,后者是过渡持续多久。
具体做法是:给元素本身设置一个较短的进入延迟,给它的隐藏状态设置一个较长的离开延迟。用下拉菜单举例:
css复制.menu {
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease, visibility 0.2s;
transition-delay: 0s, 0s;
}
.parent:hover .menu {
opacity: 1;
visibility: visible;
transition-delay: 0.1s, 0.1s;
}
这个写法让菜单在鼠标悬停父元素后100ms内淡入,而移出时则保持当前状态200ms后才开始消失,手感顺畅了很多。这里还涉及一个小细节:为什么用 visibility 而不是 display: none?因为 display 不是可过渡属性,从 none 到 block 是瞬时切换,无法实现淡入淡出。用 visibility + opacity 的组合才能在隐藏时既不占交互区域也能平滑过渡。想要彻底不占位,可以额外加 pointer-events: none,这在做浮层时非常有用。
4.3 动画性能,别忽略重排和重绘
CSS动画写起来容易,跑起来掉帧的比比皆是。这里有一个核心原则:尽量只动 transform 和 opacity,避免动画过程中修改 width、height、top、left、margin 这些触发重排的属性。width 变了会导致后续元素跟着移动,整个文档的布局都要重新计算;而 transform 只是做合成层的变换,不引发重排,渲染效率高出几个数量级。一个典型例子:做位移动效时,用 top/left 做和用 transform: translate() 做,性能差距在低端手机上一眼可见。
另一个需要重点提醒的细节是:一个页面不要放太多无限循环的动画。每个动画都会占据一个合成层,层多了以后,即使每个动画本身很轻量,合成层之间的合并也会消耗GPU资源。如果你做的是一个后台系统,就别给加载动画、背景漂浮光点、按钮涟漪同时上无限循环,否则老设备上会明显卡顿。用DevTools的Performance面板录制动画期间的表现,看有没有长任务(long task)和Layout抖动,这个排查方法比靠感觉调试高效得多。
5. Bootstrap样式覆盖,一套可复用的覆盖策略
5.1 为什么Bootstrap的样式覆盖不了
“Bootstrap 如何覆盖css样式”这个问题,每个用Bootstrap的人几乎都会遇到。你写了自定义样式想让按钮变个颜色,结果刷新页面发现Bootstrap的样式把你自己的覆盖了,原因就是CSS优先级的“三座大山”:选择器权重、加载顺序、!important。Bootstrap的默认样式在多数情况下权重并不高,它只是输在了加载顺序上——如果你把自定义样式写在Bootstrap之后,一般都能覆盖成功。但如果你用了Bootstrap的某些组件类,或者你的自定义样式写在更早的位置,那就可能失效。
假设你在 <head> 里先引入了bootstrap.css,再引入自己的style.css,理论上自己的样式权重相同且顺序靠后,就能覆盖。但实际开发里经常出现“还是覆盖不了”的情况,这时候要检查你的选择器权重。Bootstrap里很多组件是用类选择器定义的,比如 .btn-primary 权重是10,你如果写 #myBtn .custom 这样的Id+类组合,权重就是110,一定覆盖得了。但如果你写 .btn-primary-custom,权重也是10,顺序又靠前,那肯定被压。
5.2 三种覆盖方式,按场景选择
第一种,最直接的:在Bootstrap之后加载自定义样式表,并且用相同或者更高的选择器权重去覆盖。这是最干净的方式,不侵入Bootstrap源码,也不污染其他页面。
第二种,利用CSS变量。Bootstrap 5 内部大量使用CSS变量,比如 .btn-primary 的背景色是通过 --bs-btn-bg 定义的。你只需要覆盖这个变量,按钮整套配色就会联动变化,不需要重新写一大段样式。
css复制.btn-primary {
--bs-btn-bg: #7c4dff;
--bs-btn-border-color: #7c4dff;
--bs-btn-hover-bg: #6a3de8;
--bs-btn-hover-border-color: #6a3de8;
}
这种方式的优势是:不用重新定义按钮的内边距、圆角、字体大小等全部样式,只改关键的那几个变量,其余样式仍然复用Bootstrap的规则。如果只是微调颜色,强烈推荐这个方案,代码量极低,且不容易造成样式冲突。
第三种,深挖选择器优先级。如果实在绕不开,必须覆盖某个Bootstrap类且不想改加载顺序,那你只能提高自己选择器的权重。比如写 .navbar-nav .nav-link.active 去覆盖Bootstrap的 .nav-link。注意别滥用ID选择器或者 !important,尤其是 !important 一多,整个项目的样式层级全乱套。我的底线判断标准是:如果出现两处以上 !important 才能解的问题,说明结构设计有问题,该重构了。
5.3 覆盖时必须注意的三个坑
第一个坑:Bootstrap的样式文件可能被压缩过,你难以直接定位类名。这种情况建议直接去查Bootstrap官方文档的Sass变量表,或者用浏览器DevTools的Elements面板看计算后的样式,再用刚才说的CSS变量方案覆盖。
第二个坑:改了Bootstrap变量但没生效。Bootstrap的CSS变量有些定义在 :root 上,有些定义在具体组件类上。比如 .btn 的变量定义在 .btn 本身,.btn-primary 的变量定义在 .btn-primary 上,你要先确认覆盖的是哪一层。变量没有继承到子元素时也会失效,所以要检查目标组件类的确继承了该变量。
第三个坑:响应式断点破坏了你的覆盖。Bootstrap的媒体查询里会重复定义一些样式,这些样式在特定屏幕宽度下比你的覆盖优先级更高。如果你只做了通用覆盖,没有处理断点内的样式,就在窄屏下还会恢复原样。最简单的方法是用浏览器的响应式模式一挡一挡地测,把每个断点下出问题的地方记下来,挨个补覆盖。
6. 常见问题与排查技巧实录
6.1 样式没生效?按这三步排查
样式不生效是CSS实战里最常遇到的问题,其实有一套标准排查流程,按顺序走一遍基本都能找到原因。
第一步:看权重。 先确认你的选择器权重是不是被另一个更高权重的规则压过了。在DevTools的Elements面板选中目标元素,右侧Styles列表会显示所有匹配的规则,被覆盖的规则会带删除线,直接对比特殊性和顺序即可。实战里80%的“样式没生效”都能在这一步定位到。
第二步:看属性是否被继承或重置。 比如你给body设置了字体颜色,但某个元素的 color 可能在组件样式里被覆盖了。一个处理技巧是:给目标元素临时添加一个明显的样式,比如 outline: 3px solid red,如果立刻显示,说明是值被覆盖;连红框都不出现,说明选择器根本没匹配上元素。
第三步:看是否被 !important 或内联样式挡住。 内联样式优先级1000,正常选择器怎么都覆盖不了,需要 !important 才能打平并靠后加载获胜。现实里如果你写的是第三方组件库,组件内部很可能用了内联样式来控制状态,这部分只能看文档有没有提供覆盖入口,不建议硬扛。
6.2 汇总几个高频CSS报错现象
我把实际开发中踩过的坑列成一张表,方便大家速查:
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 子元素宽度超出flex容器 | 子项 min-width: auto 阻止收缩 |
给子项加 min-width: 0 或 overflow: hidden |
| 背景图不显示 | 路径错误或者容器没有固定宽高 | 检查路径、确认容器的宽高不是0 |
::after 不显示 |
忘记写 content 属性 |
加上 content: "" |
| 文字有下划线去不掉 | 继承了 text-decoration |
显式写 text-decoration: none |
position: fixed 失效 |
祖先元素创建了包含块 | 检查是否有 transform、filter、perspective 属性 |
| 点击hover无反应 | 元素被其他层遮挡 | 检查 z-index 和 pointer-events |
| 动画不循环 | animation-iteration-count 默认1 |
显式写 infinite |
| 字体渐变没有效果 | color 没有设成 transparent |
补上 color: transparent |
这张表里的每一条我都实际遇到过,尤其是 position: fixed 失效那条,是个非常隐蔽的坑。一旦某个祖先元素设置了 transform,它就变成了fixed的包含块,fixed元素不再相对于视口定位,而是相对于这个祖先定位,布局直接变形。排查时不妨检查一下最近的父级是否有这个属性。
6.3 用DevTools提升排查效率
调试CSS一定要形成“DevTools优先”的肌肉记忆。先在Elements面板里选中目标元素,然后用键盘的上下方向键在相邻元素间切换,比鼠标点选快多了。选中元素后,右侧Styles面板除了能看到生效规则,还有一个“Computed”标签页,里面直接列出所有最终计算后的属性值,排查继承和覆盖问题时非常高效。
还有一个冷门技巧:DevTools的Style面板可以按住Alt点击颜色值,让它在HEX、RGB、HSL之间切换;可以点击 + 号快速添加样式,方便临时验证某个属性是否生效。如果你在调试flex布局,多利用 display: flex 时DevTools自动出现的flex图标,点一下能可视化调整 justify-content 和 align-items,确认方向性的问题。
我在实际工作中排查样式问题的顺序基本是:先用Elements选中元素,再看Styles面板里加了删除线的规则,溯源是谁覆盖的,点击跳转到具体文件和行号,然后决定是提权还是改值。遇到疑似布局问题,直接在Computed里看 flex-shrink、min-width 这些不常想起的属性。这套流程下来,绝大多数问题五分钟之内能定位。
结尾
这些基础内容看起来零散,但基础稳了以后,花在调试上的时间会成倍下降。我自己的切身体会是:CSS不是“背属性”的语言,而是“理解规则”的语言。选择器权重、flex的三大属性、覆盖策略、动画性能,每一条规则背后都有它存在的原因,想通这些,写样式就不再是试错,而是推理。特别是做项目遇到疑难布局时,退回到基础原理去想,往往比到处搜代码片段更有效。这篇分享里的代码片段都不复杂,建议挨个动手跑一遍,在修改和试错中把感觉找回来。
