做前端这些年,CSS 是唯一一个让我又爱又恨的技术栈。爱的是它上手极快,写几个属性就能看到效果;恨的是它的知识体系太散,选择器、盒模型、布局、动画、响应式、工程化,哪一块都能单独写几本书。最近整理笔记时发现,自己这几年最常用的其实就集中在几个核心脉络里,顺着这条线捋下来,足以覆盖日常开发 90% 以上的场景。所以我把这份 CSS 样式表的概括总结写出来,既不堆砌文档,也不故作高深,完全是从实际项目里抽出来的经验:它会告诉你 CSS 到底在解什么问题、核心语法怎么落地、遇到样式不生效和布局崩掉时该怎么排查。内容适合刚入门的前端,也适合写过一阵子但总觉得知识零散的朋友查漏补缺。
我一直跟团队里的小朋友说,CSS 不是一个靠背属性就能学好的东西。很多属性你背得滚瓜烂熟,到了真实页面里照样抓瞎,因为浏览器不会按你的“我以为”渲染,它只认选择器匹配规则、层叠规则和盒模型规则。这篇文章就把这些底层规则拆开讲清楚,再配合我实际踩过的坑,希望你能少走弯路。
1. 从整体视角理解 CSS:它到底在解决什么问题
1.1 结构、表现、行为分离是前提
HTML 负责页面结构,CSS 负责外观表现,JavaScript 负责交互行为,这是前端开发最基础的的分工。我经常拿装修房子打比方:钢筋水泥是 HTML,墙面乳胶漆和地板瓷砖是 CSS,开关插座和智能家居是 JS。没有 CSS,网页就像毛坯房,信息能用但谈不上好看;没有 JS,网页就像精装房里所有开关都是摆设,能看不能用。
很多刚入门的同学会忽略这个边界,喜欢把交互状态全部塞到 JS 里改样式,结果页面逻辑乱成一团。正确做法是:能用 CSS 实现的状态切换(hover、focus、checked、media query),就不要用 JS 手动去改 class。CSS 本身就是一套声明式的“状态描述系统”,它天然适合处理视觉反馈。尤其在项目越来越复杂以后,把样式逻辑交给 CSS,代码可维护性会明显提升。
1.2 浏览器是怎么把你的样式“画”出来的
理解浏览器渲染流程,比背 100 个属性都管用。大致过程是:HTML 解析成 DOM 树,CSS 解析成 CSSOM 树,两者合并成渲染树,再经过布局计算、绘制合成,最终呈现在屏幕上。
这个过程里有两个点非常关键。
第一,选择器匹配效率。浏览器在生成渲染树时,会从右往左匹配 CSS 选择器。什么意思?比如你写 .box .title {},浏览器会先找到所有 .title 元素,再往祖先方向找 .box。所以选择器不是越复杂越好,写得太深会影响匹配速度,当然现代浏览器优化得很好了,但语义清晰依然是优先原则。
第二,层叠规则。CSS 的“C”指的就是 Cascading(层叠),同一元素的同一个属性可能有多个声明来源,最终按“重要性 > 来源 > 优先级 > 书写顺序”来决定谁生效。这部分是很多人样式覆盖不了的根源,后面我会单独展开。
1.3 CSS 不是“样式语言”,而是“渲染描述语言”
这个认知上的转变,是我工作三年后才想明白的。CSS 表面上在描述“元素长什么样”,但往深了看,它描述的是“元素在不同状态、不同屏幕尺寸、不同容器环境下应该长什么样”。
你能用它做响应式布局,因为媒体查询和容器查询可以描述不同宽度下的外观;你能用它做动画,因为关键帧可以描述元素从 A 状态到 B 状态的中间过程;你甚至能做复杂的光效、遮罩、滚动驱动动画,因为它本质上是一个“渲染控制层”。
所以别再小看 CSS 了。它的“简单”只是入门门槛低,真正想用好,需要带着“条件描述”的思维去组织代码。读到这里,你应该对 CSS 的整体位置有数了,下面我们开始扎进具体细节。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 选择器与优先级:写出可控样式的第一道门槛
2.1 常用选择器分类与使用场景
选择器是 CSS 的基本语言单位。我平时最常用的就几类:
- 基础选择器:元素选择器
p、类选择器.box、ID 选择器#app。 - 属性选择器:
[type="text"]、[class^="btn-"],适合批量匹配特征。 - 伪类选择器:
:hover、:focus、:nth-child(odd)、:not(.disabled)、:checked。 - 伪元素选择器:
::before、::after,用来插入装饰性内容,很常用。 - 关系选择器:后代
、子元素>、相邻兄弟+、通用兄弟~。
这里要单独提一下兄弟选择器,因为很多项目里会用它实现“上一个兄弟元素”的联动效果。比如热词里提到的“css div上一个兄弟元素”,本质是想让某个元素影响它前面的元素。CSS 语法层面没有“上一个兄弟”选择器,但可以通过 ~ 配合 flex 的 order 属性做视觉调换,或者用 :has() 选择器,例如 .item:has(+ .active),就是选中后面跟着 .active 的 .item。这个选择器兼容性已经不错了,值得用起来。
2.2 优先级计算背后的逻辑
样式不生效,十有八九是优先级没算明白。CSS 优先级按四位权重统计:内联样式占最高权重,然后是 ID 选择器数量、类/属性/伪类选择器数量、元素/伪元素选择器数量。比较时从左往右比,谁先出现更大值谁赢。
举个例子:
css复制/* 权重:类选择器 1 个 */
.title { color: red; }
/* 权重:ID 选择器 1 个 */
#main-title { color: blue; }
如果同一个元素同时命中了这两个规则,最终文字是蓝色,因为 ID 权重大。再比如 ul li 权重是两个元素选择器(0,0,0,2),而 li.active 是一个元素加一个类(0,0,1,1),后者权重更高。很多同学写 ul li 去覆盖 li.active,怎么都覆盖不了,就是这个原因。
真正让我觉得优先级麻烦的场景,是去覆盖第三方库的样式。比如用 Bootstrap 时,你想改一个按钮的 padding,发现改了半天不生效。原因通常是自己的样式写在 Bootstrap 之前,或者优先级没有库内部的选择器高。针对这种场景,优先用更具体的选择器,比如 .btn-group .btn-custom,实在不行再加 !important,但要控制使用频率。
2.3 CSS 变量的引入如何影响选择器与主题化
CSS 自定义属性(变量)是我现在写样式必用的工具。定义在 :root 里做全局主题,定义在组件类里做局部控制,还可以配合伪元素做动态样式。
比如这个例子:给 ::before 设置一个颜色变量,并允许外部通过新增 class 覆盖。
css复制.icon::before {
content: "";
background: var(--icon-bg, #888);
}
.icon.success {
--icon-bg: #52c41a;
}
这样 .icon.success 的伪元素背景就会自动变绿,完全不需要额外写伪元素样式。热词里提到“css 控制伪元素变量”和“css类根据参数不同使用不同的类”,本质就是利用 CSS 变量做“参数化类名”。我经常用它做主题切换,一个 data-theme="dark" 的类切换,整个页面的配色跟着变。
原子性 CSS 也是同一个思路。每个类只做一件事,比如 .text-center { text-align: center; }、.mt-10 { margin-top: 10px; },配合变量可以做到极致的复用。Tailwind 就是这类方案的代表,用起来很爽,但也需要你看清它的取舍:HTML 会变得很长,初学者读起来费劲,页面结构变化时维护成本也不低。
3. 盒模型与布局:从传统布局到 Flex 与 Grid
3.1 盒模型四件套与 box-sizing 的坑
每个 HTML 元素在浏览器眼里都是一个矩形盒子,从内到外分别是 content、padding、border、margin。默认情况下,你给元素设置 width: 300px,这个宽度只代表内容区,实际占位还要加上 padding 和 border,这就非常容易导致布局溢出。
我刚开始写页面时,经常遇到两个并排元素宽度各设 50%,结果第二行被挤下去。因为 50% + padding + border 已经超过父容器宽度的 100% 了。解决办法很简单:
css复制* {
box-sizing: border-box;
}
border-box 会把 padding 和 border 包含在 width 范围内,这样 width: 50% 就是实实在在的一半。现在我每次新建项目,第一件就是把这条全局规则加上,能省一大半布局问题。margin 是不占元素实际占位宽度的,但它会影响外面的布局间距,折叠等细节也需要了解。
3.2 Flex 布局:主轴交叉轴、子元素宽度自适应、常见布局套路
Flex 已经成了我日常布局的首选方案。它解决的是“一维排列”问题,核心思路是让容器控制子项的排列方式。
首先明确主轴和交叉轴:默认 flex-direction: row 时,主轴是水平方向,交叉轴是垂直方向;改成 column 后反过来。justify-content 控制主轴的分布方式,align-items 控制交叉轴的对齐方式。这两个属性加上 flex-wrap 就能撑起绝大部分布局。
真正需要花心思的是子项上的 flex 属性。热搜词里“css flex布局子元素宽度自适应”,我猜很多人是在做等分或自适应卡片时遇到的。flex 是三个子属性的简写:
flex-grow:空间多余时,子项按比例放大。flex-shrink:空间不足时,子项按比例缩小。flex-basis:子项在主轴上的初始尺寸。
常见的写法:
css复制.item {
flex: 1; /* 等价于 flex: 1 1 0% */
}
这样写,所有 .item 会平分父容器剩余空间,非常适合做导航栏、标签列表、卡片等分。如果你希望某几项固定宽度,其余项自适应,可以把固定项设 flex: 0 0 200px;,把自适应项设 flex: 1。
还有一个坑:flex 子项默认 min-width: auto,当里面的文字很长不换行时,子项会被内容撑大,导致等分失败。解决办法是给子项加 min-width: 0,或者 overflow: hidden。这是我做“flex 子元素宽度自适应”时踩得最多的地方。
3.3 Grid 布局:二维控制与网格模板的核心
Grid 和 Flex 不是二选一的关系,而是互补。Flex 适合线性排列,Grid 适合二维网格。页面整体骨架用 Grid,组件内部细节用 Flex,是比较合理的分工。
Grid 的核心是定义网格轨道:
css复制.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
1fr 是 Grid 里的自适应单位,相当于把剩余空间按比例分配。repeat(3, 1fr) 就是三列等分。更实用的是 repeat(auto-fill, minmax(200px, 1fr)),表示列数自动填充,每一列最小 200px、最大 1fr。这样写,不需要任何媒体查询,卡片列表就能在窄屏上自动变成两列,宽屏上变成四列,属于真正的“响应式网格”。
Grid 还支持区域命名,适合搭页面骨架:
css复制.layout {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
这种写法可读性很高,团队协作时看一眼就知道页面结构。热词里“css grid”相关搜索量一直很高,说明大家确实在从 Flex 往 Grid 迁移,但我觉得不必焦虑,两个都掌握,按场景选用就好。
3.4 文本与容器的细节:文本位置调整、文字竖排、超出省略号
调整容器内文本位置,是我几乎每天都要做的事。最简单的是 text-align 和 vertical-align,但这两个属性有局限性。真正好用的是 Flex 或 Grid:
css复制.box {
display: flex;
justify-content: center;
align-items: center;
}
只要三行,容器内所有内容水平垂直居中。这个方法在按钮、卡片、弹窗里都适用,比 position + transform 的手动居中方案更简洁。
文字竖排也很简单:
css复制.vertical-text {
writing-mode: vertical-rl;
}
这个属性在古籍排版、侧边标签、海报标题里挺常用。
文本溢出显示省略号,是我看到被搜最多的问题之一。单行省略:
css复制.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
多行省略可以直接套用 -webkit-line-clamp:
css复制.multi-ellipsis {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
这两段代码我直接存在代码片段里,每次遇到“css超出显示...”的诉求就拿出来改一下行数。需要注意,多行方案依赖 -webkit- 前缀,目前现代浏览器都支持,无需过度担心。
4. 样式细节与动效实现:从静态到动态
4.1 字体与文本效果:字体渐变、金光闪闪效果、文字竖排
字体渐变是一个比较炫但实现很简单的效果。核心思想是把背景渐变裁切到文字上,然后让文字颜色透明:
css复制.gradient-text {
background: linear-gradient(90deg, #f00, #00f);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
这个写法兼容性很好,我经常用它做标题、大促文案、品牌词。如果你想要“金光闪闪”的效果,本质就是让渐变的背景位置动起来,形成扫光动画:
css复制.shine-text {
background: linear-gradient(120deg, #b8860b 20%, #ffd700 40%, #fff8dc 50%, #ffd700 60%, #b8860b 80%);
background-size: 200% 100%;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: shine 2s linear infinite;
}
@keyframes shine {
to {
background-position: -200% 0;
}
}
这段代码的核心是 background-size 和 background-position。背景图放大到两倍宽,动画改变位置,高光部分就会来回扫过文字,看起来就像金属光泽在流动。实际项目里我建议把扫光速度调慢一点,不然容易闪到用户眼睛。
4.2 过渡与动画:hover 延迟关闭、涟漪光圈扩散
动画有两种实现路径:transition 适合简单的状态变化,@keyframes 适合复杂的连续动作。
热词里“css hover延迟关闭”是一个很常见的交互需求。默认情况下,鼠标移开时过渡会立刻开始往回走,但有时候我们希望延迟一下再关闭,比如悬浮菜单收起时不要太突兀。实现方式是在 transition 上写延迟时间:
css复制.menu {
opacity: 0;
transition: opacity 0.3s ease;
}
.card:hover .menu {
opacity: 1;
transition: opacity 0.3s ease 0.2s; /* 进入时延迟 0.2s */
}
这段代码的问题是进入和退出共用一个 transition,如果只给 .compact:hover .menu 写延迟,退出时仍会走默认的 0 延迟。如果你希望退出时也有延迟,就给菜单的默认状态加上延迟;如果希望进入延迟、退出立刻关闭,就只给 hover 状态加延迟。这个小细节很多人容易搞混,建议自己在 DevTools 里试一遍。
涟漪光圈扩散效果也是热门需求。核心是用 ::before 或 ::after 做一个圆圈,然后结合 scale 和 opacity 做放大淡出:
css复制.ripple-btn {
position: relative;
overflow: hidden;
}
.ripple-btn::after {
content: "";
position: absolute;
width: 100px;
height: 100px;
left: 50%;
top: 50%;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
transform: translate(-50%, -50%) scale(0);
opacity: 1;
}
.ripple-btn:active::after {
animation: ripple 0.6s ease-out;
}
@keyframes ripple {
to {
transform: translate(-50%, -50%) scale(4);
opacity: 0;
}
}
点击按钮时,圆圈从中心向外扩,模拟水波纹。这里的 overflow: hidden 很重要,否则扩散会超出按钮边界。
4.3 高级遮罩与动效:CSS mask、动效样式库、动画性能优化
CSS 里的 mask 属性可以让元素局部透明,常用于制作渐变遮罩、不规则裁剪、一些比较有设计感的图片过渡。基础用法:
css复制.image {
mask-image: linear-gradient(to bottom, transparent, #000 60%);
-webkit-mask-image: linear-gradient(to bottom, transparent, #000 60%);
}
这样图片底部会逐渐虚化融入背景,视觉上很柔和。现在不少网站首页的滚动淡入效果就是这么做的。
动效样式库方面,Animate.css、Hover.css 这类库确实能快速做出不错的效果,但我更建议你在短平快项目里用,需要长期维护的项目最好还是手写关键帧。原因很简单:库带来的冗余样式,可能和你自己的主题色、间距体系冲突,后期反而难调。
动画性能优化是移动端开发躲不开的话题。CSS 动画触发“重排”“重绘”“合成”三个阶段,其中“合成”开销最小。所以做位移动画时,尽量用 transform: translate(),而不是 left/top;做淡入淡出时用 opacity,而不是 display。这样浏览器能走硬件加速,动画更流畅。will-change: transform 也可以提前告诉浏览器优化,但别滥用,每个元素都用反而消耗内存。
5. 响应式与工程化:在真实项目中如何组织 CSS
5.1 响应式的核心:媒体查询、视口单位、容器查询
移动端适配是前端的日常,媒体查询是最基础的方案。我的习惯是 Mobile-first,先写手机样式,再用 @media (min-width: 768px) 和 @media (min-width: 1024px) 逐步加宽屏样式。这样写出来的代码相对精简,老设备也能先走基础样式。
视口单位 vw、vh 也很好用,比如全屏 banner 可以直接 height: 100vh。但单独用 vw 控制字体大小会有问题,因为它在窄屏上会缩得很小,建议配合 clamp():
css复制font-size: clamp(16px, 2vw, 24px);
这句话的意思是:字体在 16px 到 24px 之间,随视口宽度变化,但不超过边界。这是我做响应式文本的首选写法。
容器查询是近几年的新方向。媒体查询基于视口,容器查询基于父容器尺寸,更适合组件级复用。写法类似:
css复制.card {
container-type: inline-size;
}
@container (min-width: 300px) {
.card {
padding: 24px;
}
}
这意味着同一个卡片组件,放到窄容器里自动窄版样式,放到宽容器里自动宽版样式,完全不用管它在页面哪个位置。
5.2 覆盖样式与第三方库定制:以 Bootstrap 为例
很多项目用 Bootstrap 这类框架起步,但到了定制阶段,会遇到样式覆盖难题。我总结了一套自己的处理顺序:
第一,优先用 Bootstrap 的 CSS 变量去定制主题。新版 Bootstrap 大量使用 CSS 变量,比如 --bs-primary、--bs-border-radius,直接覆盖这些变量,比写出几十条覆盖规则干净得多。
第二,在组件根元素上增加自定义类,然后写更高优先级的选择器。比如:
css复制.btn-custom {
padding: 12px 28px;
border-radius: 8px;
}
在 HTML 里写成 class="btn btn-custom",因为 .btn-custom 和 .btn 优先级相同,但自己的样式表只要在 Bootstrap 之后加载,就能覆盖。这比在 .btn 上硬改安全,不会影响其他按钮。
第三,万不得已才用 !important。在验证过选择器优先级和加载顺序都没有问题之后,再局部使用。记住一点:!important 用多了,整个项目的样式会变得不可预测,后接手的人会骂人的。
5.3 原子性 CSS 与样式架构:实用性与代码维护的平衡
原子性 CSS 这阵子讨论度很高,本质是把样式拆成单一职责的类。比如 flex、mt-8、text-sm,每个类只做一件事。它的优点是复用性极高、命名成本低、打包体积可压缩;缺点是 HTML 里堆积大量类名,视觉上非常啰嗦,项目大了以后可读性下降。
如果你要在团队里用原子性 CSS,我的建议是:
- 项目早期统一好设计变量,比如间距、字号、颜色都用变量控制。
- 常用的小工具类可以自己封装,不一定要引全家桶。
- 复杂组件内部还是用传统语义化类名,避免所有样式都堆在 HTML 上。
个人感受是,原子性 CSS 和 BEM 并不冲突。页面级结构用 BEM 表达“是什么”,组件内部状态用工具类表达“长什么样”,这个组合用起来反而舒服。
5.4 手机端适配特殊问题:PC hover 到移动端、小程序 swiper 非当前项缩放
移动端没有鼠标,所以没有真正意义上的 hover 状态。PC 端悬浮显示菜单的交互,在手机上会变成点击后显示,而 CSS 的 :hover 在移动端有各种兼容性问题,比如第一次点击后元素一直保持 hover 样式,很难取消。更稳妥的写法是用 @media (hover: hover) 来区分设备:
css复制@media (hover: hover) {
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}
}
这样 PC 端正常有悬浮效果,手机端不会误触发。
微信小程序里,swiper-item 非当前元素缩小也是常见设计。通常做法是给当前项加一个类名,然后利用 CSS 控制非当前项的 scale 和 opacity。比如在 swiper 的 bindchange 事件里记录 current,再在 WXML 中给当前项绑定 class="active",样式这样写:
css复制.swiper-item {
transition: all 0.3s ease;
transform: scale(0.9);
opacity: 0.6;
}
.swiper-item.active {
transform: scale(1);
opacity: 1;
}
这个思路不限于小程序,普通网页里的轮播图也适用。关键是过渡动画要平滑,同时注意不要影响图片的清晰度。
6. 常见问题与排查技巧实录
6.1 样式不生效的常规排查顺序
很多同学一遇到样式不生效就慌,其实排查思路是固定的。我的顺序是:
- 检查 CSS 文件和 HTML 是否成功引入,路径有没有错,浏览器控制台有没有 404。
- 检查选择器名称是否拼写正确,尤其注意大小写和驼峰命名。
- 检查样式加载顺序,自己的样式是不是写在库样式前面了。
- 检查优先级,是不是被更高权重的规则覆盖了。
- 在 DevTools 的 Elements 面板看 Computed 样式,找到是哪条规则覆盖了你的声明。
- 检查父元素是否正常显示,比如父元素宽度为 0、
overflow: hidden、display: none,子元素再怎么写也没用。
这套流程走下来,90% 的问题都能定位到。真正复杂的情况是“样式时灵时不灵”,这种一般和状态类、动态渲染有关,需要重点检查类名是否在渲染后被 JS 移除。
6.2 选择器优先级陷阱
我见过团队里一个很典型的 bug:导航栏高亮失效。原因是有人写了 .nav .item.active,有人写了 .nav > .item.active,两个人以为自己改的是同一个东西,结果后者优先级更高,把前者的颜色覆盖了。开发时靠猜,最终只能靠 DevTools 一行行找。
如果怕优先级问题,就直接用变量和组件类来收敛。我在自己项目里一般会把状态类控制得比较严格:.nav__item--active 这种 BEM 修饰符,一眼就能看出来含义和层级。优先级反而没有那么容易出问题。
6.3 Flex 子元素宽度自适应失效
之前做个卡片列表,每张卡片用 flex: 1,但里面如果放了一长串没有空格的链接文字,卡片就会被撑大,导致整体布局参差不齐。排查后发现是 min-width: auto 在作祟。
解决方案很简单,给卡片加一行:
css复制.card {
min-width: 0;
}
这样它在 Flex 容器里就允许被压缩。记住这个属性,以后遇到 Flex 自适应失效,第一个就查它。
6.4 动画在移动端不流畅/不触发
移动端动画卡顿,最常见的原因是用 margin-left、top、width 这类属性做动画,触发大量重排。解决方法是改用 transform 和 opacity。另一个常见问题是动画不触发,多是因为元素初始状态和结束状态设置不对,比如 opacity 已经为 0,再过渡到 0 当然没变化。
还有一点容易被忽略:在低电量模式下,有些浏览器会自动禁用复杂动画。遇到“测试机好好的,用户手机上不动”的情况,可以往这个方向排查,并配合 prefers-reduced-motion 提供无动画版本,这也是提升无障碍体验的做法。
6.5 伪元素变量控制与动态样式
很多同学想用 CSS 控制 ::before 和 ::after 的样式,但发现伪元素不能直接写在 HTML 里。我的技巧是把变量定义在元素本体上:
css复制.icon {
--icon-color: #333;
}
.icon::after {
color: var(--icon-color);
}
.icon--danger {
--icon-color: #d33;
}
这样类名一换,伪元素颜色就变了。这个方法最常见的使用场景是字体图标、描边、装饰点等,能少写很多重复代码。
6.6 综合速查表:每日高频样式代码片段
我把这些年攒下来的一些高频代码整理成了一份速查表,基本能覆盖日常写页面的绝大多数需求。
| 需求 | 核心代码 | 说明 |
|---|---|---|
| 水平垂直居中 | display: flex; align-items: center; justify-content: center; |
Flex 方案,最稳定 |
| 文本单行省略 | white-space: nowrap; overflow: hidden; text-overflow: ellipsis; |
基础三件套 |
| 文本多行省略 | display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; |
改变数字即可控制行数 |
| Flex 子项等分 | flex: 1; min-width: 0; |
min-width 防止内容撑破 |
| Grid 自适应列数 | grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); |
经典响应式网格 |
| 字体渐变 | background: linear-gradient(...); background-clip: text; color: transparent; |
注意前缀 |
| 金色扫光 | 渐变背景 + background-position 动画 |
文字级金属感效果 |
| 涟漪光圈 | transform: scale() + opacity + @keyframes |
点击水波纹 |
| hover 延迟关闭 | transition: opacity 0.3s ease 0.2s; |
延迟写在默认状态 |
| 移动端禁用 hover | @media (hover: hover) { ... } |
区分设备 |
| 覆盖 Bootstrap | 自己的类加载在后面 + 更高优先级 | 配合 CSS 变量更佳 |
说实话,CSS 这门技术最磨人的地方不是“不会写”,而是“不知道为什么没生效”。我这些年逐渐养成一个习惯:每写一段样式,都先想清楚它的选择器命中谁、优先级够不够、容器的宽度和高度约束是什么。想通这三点,大部分问题都能在设计阶段避免。最后再分享一个小技巧:遇到诡异的布局问题,别急着加各种 hack,先把相关元素的 outline: 1px solid red 打开,看看真实的盒子边界在哪里。很多时候,肉眼看到的不一定是代码认为的边界,把边界画出来,问题就一目了然了。
