1. 字体与文本:日常写样式的第一道关卡
1.1 字体家族的坑:font-family的正确打开方式
CSS 里font-family是我见过新手最容易忽略、老手也容易翻车的属性。很多人上来就写font-family: Arial,结果在 Windows 上打开,页面字体直接变成了宋体,因为 Arial 这字体在中文环境里压根不包含中文字形。字体栈(font stack)的意义就在于:浏览器会从头到尾找第一个可用的字体,找不到就继续往下走。
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif; }这套写法基本覆盖了 macOS、iOS、Windows 和 Android 的主流字体环境。-apple-system 是苹果系统专用字体,BlinkMacSystemFont 是 Chrome 在 Mac 上的渲染字体,Segoe UI 对应 Windows 现代字体,PingFang SC 是苹方,Microsoft YaHei 是微软雅黑。字体栈的顺序不是乱排的,它遵循"系统优先、中文兜底、sans-serif 收尾"的逻辑。
另一个容易忽略的是font-family对引号的处理。中文字体名和包含空格的字体名必须加引号,否则解析会出错。比如font-family: Microsoft YaHei这种不带引号的写法,在某些浏览器里是无效的。写"Microsoft YaHei"或者"微软雅黑"才稳妥。
实测下来还有个小细节:font-family在小程序、WebView 等环境里表现各不相同。如果你在做一个跨端项目,字体栈最好统一封装成 CSS 变量,方便一处修改、全局生效。
:root { --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; --font-mono: "JetBrains Mono", "Fira Code", Consolas, "Courier New", monospace; }1.2 文本装饰与段落处理:删除线、分割线、超长省略
热搜词里出现了"css 删除线"和"css实现段落分割线",这俩都是非常典型的文本装饰需求。删除线用text-decoration: line-through就可以实现,但很多人不知道它还有三个配套属性。
.del { text-decoration-line: line-through; text-decoration-style: wavy; /* 波浪线删除线 */ text-decoration-color: #e74c3c; text-decoration-thickness: 2px; /* 删除线的粗细 */ }text-decoration是复合属性,可以拆成四段来控制。搞电商和后台系统的同学经常用删除线表示原价,这时候用text-decoration-color把删除线调成比文字浅的颜色,视觉上会舒服很多。
段落分割线有几种实现思路,我自己比较常用的是伪元素方案:
.divider { display: flex; align-items: center; gap: 12px; color: #666; font-size: 14px; } .divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: #e5e5e5; }这样能得到一条文字两侧贯穿的分割线,而且长度自动适应容器宽度。比起直接写<hr>,这种方案的扩展性更好——可以随意调整间距、颜色和粗细,还能适配不同屏幕宽度。
真正让不少人头疼的是超长文本的省略。单行省略号大家都会写:
.ellipsis { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }但"css 两行超出..."这个热搜词说明大家都在找两行省略的写法,这个必须是-webkit-line-clamp,加上配套的三个属性:
.multiline-ellipsis { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }这段代码的作用是:把元素设置为弹性盒模型,主轴方向垂直(column),限制显示 2 行,超出部分隐藏。注意-webkit-line-clamp只对display: -webkit-box的元素生效,而且-webkit-box-orient一定不能省。这个写法虽然带-webkit-前缀,但在现代 Chrome、Safari、Firefox、Edge 里都能正常工作,可以放心用。
1.3 文本对齐的常规操作:line-height、text-align 与那个永远的"居中"问题
text-align: center是让文字水平居中,但它有个隐含条件:text-align 作用于块级元素,影响的是元素内部的内联内容。所以如果你对一个<span>直接设置text-align: center,是完全没用的,必须设置在其父级块元素上。
"css中怎么把input居中"这个热搜词,本质上就是文本对齐和表单控件尺寸的交互问题。input 属于行内块元素(inline-block),它默认的宽度不是撑满父容器,而是由size属性决定。要让 input 在容器中水平居中,方法很简单:
.form-item { text-align: center; } .form-item input { width: 280px; height: 40px; padding: 0 12px; font-size: 14px; box-sizing: border-box; }把 input 的 width 固定之后,给父级加text-align: center就能让它水平居中。这里有个新手常踩的坑:input 的高度和文字垂直居中问题。给 input 设置了height后,文字默认是靠上排布的,要让它垂直居中,不能用line-height去配(在部分浏览器里会失效),最可靠的做法是控制padding上下值:
input { height: 40px; padding: 8px 12px; box-sizing: border-box; }文字垂直居中还有一个经典场景:单行文字在容器里垂直居中,直接把line-height设置成容器高度即可。如果容器高度 48px,就写line-height: 48px。但这段代码有个前提——文字内容不能换行,一旦换行,整个排版就会崩掉。多行文本的垂直居中,交给后面要讲的 flex 方案更靠谱。
"怎么调整css容器里的文本位置"这个热搜词,实际上涵盖了水平对齐(text-align)、垂直对齐(vertical-align或 flex)、缩进(text-indent)、字间距(letter-spacing)等多个维度。其中letter-spacing经常被用来做标题的"高级感"处理:
.title { letter-spacing: 4px; /* 字间距拉大 */ } .subtitle { letter-spacing: -0.5px; /* 正文微调,显得紧凑 */ }2. 盒模型与尺寸:大部分布局问题的根源都在这
2.1 content-box 与 border-box:width 到底算到哪里
盒模型是 CSS 里最基础、也最容易被低估的概念。"css从入门到精通——盒模型"能成为热搜词,说明有大量初学者在这里卡住了。
每个元素在页面里本质上都是一个矩形盒子,从内到外依次是 content(内容)、padding(内边距)、border(边框)、margin(外边距)。问题出在width属性到底包含哪些部分上。
默认状态下,浏览器使用content-box模式:width只指内容区宽度,padding 和 border 都另外计算。这意味着:
.box { width: 200px; padding: 20px; border: 2px solid #000; }这个盒子实际占据的宽度是 200 + 20×2 + 2×2 = 244px。你需要心算这个结果,才能确保布局不超出容器。写多了真的会疯掉,尤其是修改 padding 或 border 数值的时候,整个布局都可能跟着变。
解决方案是全局切换成border-box:
*, *::before, *::after { box-sizing: border-box; }在border-box模式下,width直接包含 content、padding、border 三部分,设置 200px 就是实实在在的 200px,padding 和 border 只是从内容区里"挤"出来的。
我个人建议在所有新项目里都加上这段 reset,它几乎不会带来负面影响,却能让布局计算大幅简化。
2.2 margin 的合并与塌陷:为什么子元素把父元素"顶"下去了
margin 有两个反直觉的行为,排查很久都找不到原因的情况很常见。
第一个是margin 合并(collapsing):垂直方向上,两个相邻兄弟元素的 margin-bottom 和 margin-top 不会相加,而是取两者的最大值。上面元素设margin-bottom: 30px,下面元素设margin-top: 20px,最终间距是 30px 而不是 50px。水平方向不会发生合并。
第二个是margin 塌陷(overflow) 的经典问题:给子元素设置margin-top: 20px,结果子元素没动,父元素整体往下移了 20px。这是因为父元素没有建立独立的 BFC(块级格式化上下文),子元素的 margin 穿透到了父元素上。
解决办法有几种:
- 给父元素加
overflow: hidden - 给父元素加
padding-top代替子元素的margin-top - 给父元素加
border-top: 1px solid transparent - 给父元素设置
display: flex或display: grid
比较推荐的是直接给父元素设置display: flex,既解决了 margin 塌陷,也为后续的子元素布局提供了弹性能力。如果不想改变父元素的显示类型,overflow: hidden是最轻量的兜底方案。
2.3 尺寸控制的实战经验:min-width、max-width 与百分比高度
响应式布局里,min-width和max-width的出场率非常高。比方说你希望一个卡片在手机上全屏显示,在桌面上最多 1200px:
.card { width: 100%; max-width: 1200px; margin-inline: auto; /* 水平居中,等价于 margin-left/right: auto */ }这段代码是响应式布局的经典范式:移动端优先,宽度撑满;大屏受到 max-width 限制,再用 margin auto 居中。
height 的百分比设置有个著名坑点:height: 100%并不是"填满父元素高度",而是"等于父元素的高度",而父元素的 height 如果也是 auto,子元素的height: 100%就会失效。所以想用百分比高度,链条上的每一级父元素都必须有明确的 height 值。
现代 CSS 提供了更好的方案:min-height: 100vh(视口高度的 100%),加上 flex 布局,可以让页面底部固定而内容自由伸展:
.page { display: flex; flex-direction: column; min-height: 100vh; } .main { flex: 1; }这样main区域会自动填满剩余空间,内容多的时候页面也能正常撑开,算是height: 100%链式依赖的完美替代品。
3. 布局与定位:从"不小心居中"到"想居中就居中"
3.1 情景化居中方案:不同元素类型对应不同写法
"文本垂直水平居中css代码""让table水平居中css""css中怎么把input居中"这几个热搜词本质上问的是同一件事:不同元素类型下,居中的写法差异很大。
margin: 0 auto能实现块级元素的水平居中,但要求这个元素必须有明确的 width。如果不写 width,block 元素默认占满整行,居中就没有意义。
table 元素的居中稍有不同。table 默认宽度由内容决定(shrink-to-fit),如果想让它水平居中:
table { margin-left: auto; margin-right: auto; }或者对 table 的父级使用text-align: center(同样因为 table 是 inline 级别在文档流中的表现之一,这里用 margin auto 更稳)。
真正想做完整的水平垂直居中,现阶段最推荐的方案是 flex:
.parent { display: flex; justify-content: center; /* 水平居中 */ align-items: center; /* 垂直居中 */ }只要 parent 是块级元素且有明确尺寸,这个组合就是万金油。它同时适用于 div、input、table、图片、多行文本等所有子元素,不需要关心子元素的类型和具体宽度。
还有一种使用绝对定位的居中方式,用于"父容器 position 不是 static"的情况:
.center { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }top: 50% left: 50%把元素的左上角定位到父容器中心,transform: translate(-50%, -50%)再把它向左上移动自身宽度和高度的一半,实现真正居中。这个方法的好处是不需要知道元素的具体宽高,缺点是和 transform 共用后,后续如果要加动画缩放会互相冲突。
3.2 浮动与清除浮动:旧时代的遗产,仍然需要了解
flex 和 grid 全面普及之后,用 float 做整页布局已经不太主流了,但你仍然需要理解它——因为很多老项目、打印样式、图文混排场景还在大量使用 float。
float 的设计初衷是"文字环绕图片",而不是做布局。当元素被设置float: left/right后,它会脱离正常文档流,但文字和行内元素会环绕它排列。问题是:父容器的高度不会被子元素的浮动撑开,导致背景塌陷、边框包不住内容。
清除浮动的标准手法有几种,其中最经典的是万能 clearfix:
.clearfix::after { content: ""; display: block; clear: both; }原理是给父容器的末尾插入一个伪元素,用clear: both把这个伪元素推到浮动元素的下方,父容器的高度就会被这个伪元素撑开。实测下来,这个方案在所有浏览器里都稳定有效。
如果父容器本身就是一个 BFC(比如overflow: hidden或display: flow-root),浮动也可以被包含在内部。现代写法推荐:
.parent { display: flow-root; }flow-root专门用来创建 BFC,副作用比overflow: hidden小——overflow: hidden会把子元素溢出的部分裁掉,比如下拉菜单如果超出父容器范围就会被剪掉,而flow-root不会。
3.3 定位三兄弟:relative、absolute、fixed 的实际应用
定位(position)是"css从入门到精通——定位与布局"热搜词的核心。三者关系可以简化成一句话:absolute 元素会相对于最近的、非 static 定位的祖先元素进行定位;如果找不到这样的祖先,就相对于初始containing block(通常是根元素 html)。
也就是说,要控制 absolute 子元素的定位基准,必须在父元素上先加position: relative。这个相对定位的父元素本身并不需要移动,它只是一个坐标锚点。比如给容器右上角加一个关闭按钮:
<div class="modal"> <span class="close-btn">×</span> </div>.modal { position: relative; } .close-btn { position: absolute; top: 12px; right: 12px; width: 32px; height: 32px; line-height: 30px; text-align: center; cursor: pointer; }fixed 定位则是相对于视口,常用来做吸底按钮、回到顶部、悬浮导航。但这里也有个坑:如果 fixed 元素的祖先里有 transform、perspective 或 filter 属性,它会相对于那个祖先定位,而不是视口。这在做弹窗组件时经常导致浮层出现在错误的位置。
z-index 的常见误解是"值越大越靠上"。实际上 z-index 只在同一层叠上下文内起作用。父元素设置了opacity、transform、filter等属性时,会形成一个新的层叠上下文,子元素的 z-index 就只能在这个上下文内部比较,无法和外部元素比较。
4. 视觉装饰:渐变、描边、阴影与形状
4.1 文字渐变与文字描边:让标题跳出平面
"css 字体渐变"和"css 字体 外描边"这两个热搜词,对应的都是很实用的纯 CSS 文字效果。
文字渐变的核心是将背景渐变裁切到文字上:
.gradient-text { background: linear-gradient(90deg, #f5576c, #f093fb); -webkit-background-clip: text; background-clip: text; color: transparent; }原理很简单:给元素设置一个渐变色背景,用background-clip: text让背景只在文字的形状范围内显示,最后把文字本身颜色改成透明。注意-webkit-background-clip: text必须要写,标准语法background-clip: text的浏览器支持还不够全面。
文字外描边用-webkit-text-stroke:
.outline-text { -webkit-text-stroke: 2px #333; color: transparent; }-webkit-text-stroke能同时设置描边宽度和颜色。文字设置为透明后,就变成只剩轮廓的空心字。这种效果非常适合做标题、Banner 上的视觉强调。但要注意:-webkit-text-stroke的描边是沿着文字边缘向两边扩展的,所以 2px 的描边实际视觉效果会比 2px 粗,而且是向内侧入侵的,字越细越容易糊。
如果要实现"文字有描边但内部仍然是填充色"的效果,可以叠加 text-shadow 模拟,不过太麻烦,不如直接用两层文字做叠加,一层描边一层填充。
4.2 涟漪光圈扩散:纯 CSS 动画实现的水波效果
"css涟漪光圈扩散"属于比较炫酷的视觉需求,通常在没有 JavaScript 的情况下,用 CSS 动画加box-shadow或transform: scale()实现。
一个从中心向外扩散、逐渐消失的光圈效果:
@keyframes ripple { 0% { transform: scale(0.8); opacity: 0.8; } 100% { transform: scale(2.2); opacity: 0; } } .ripple { position: relative; width: 120px; height: 120px; border-radius: 50%; background: #3498db; } .ripple::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: rgba(52, 152, 219, 0.4); animation: ripple 2s ease-out infinite; }inset: 0是top/right/bottom/left都设为 0 的简写,让伪元素铺满父容器。动画核心是不断从 0.8 倍缩放到 2.2 倍,同时透明度从 0.8 降到 0。如果要做出多层扩散效果,可以再加一个伪元素,把动画延迟半拍:
.ripple::before { content: ""; position: absolute; inset: 0; border-radius: 50%; background: rgba(52, 152, 219, 0.2); animation: ripple 2s ease-out 0.5s infinite; }animation-delay: 0.5s让第二个光圈比第一个晚启动,视觉上就有连续波动的感觉。
4.3 圆角、阴影与边框:细节决定质感
border-radius的写法比大多数人以为的更灵活:
.box { border-radius: 16px 8px 4px 2px; /* 顺时针:左上 右上 右下 左下 */ }两种常见的特殊场景:胶囊按钮是border-radius: 999px或 50%(当高度确定时用border-radius: 50%会直接变成椭圆,而用大数值 999px 则是"高度的一半"的圆角,效果更可控)。圆形元素是border-radius: 50%加上宽高相等。
box-shadow 的完整语法是box-shadow: offset-x offset-y blur spread color inset。很多人只用前三个参数,忽略了spread(扩散半径):
.card { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); /* 常规阴影 */ } .card-hover { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); /* 悬停时阴影变深变大 */ }想让阴影更柔和,可以增大 blur;想让阴影"贴地",可以减小 y 轴偏移。用两层阴影叠加,能做出比单层更细腻的效果:
.card { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 8px 24px rgba(0, 0, 0, 0.08); }第一层负责近距离的轮廓感,第二层负责远距离的悬浮感,这套组合在实际业务里观感非常好。
border 和 outline 的区别也值得说:border 占据布局空间,会影响盒模型尺寸;outline 不占空间,绘制在元素外部,常用于焦点提示(:focus-visible)。
5. 交互与动效:hover、过渡与关键帧
5.1 鼠标移入事件:hover 的玩法与边界
"css 鼠标移入事件"这个热搜词,实际上说的就是:hover伪类。它可以根据鼠标是否悬停在元素上来切换样式:
.btn { background: #3498db; transition: background 0.3s ease; } .btn:hover { background: #2980b9; }:hover可以作用于任何元素,不只是按钮和链接。父元素 hover 时联动子元素变化,也是常见的技巧:
.card .action-btn { opacity: 0; transform: translateY(8px); transition: all 0.3s ease; } .card:hover .action-btn { opacity: 1; transform: translateY(0); }这个"悬停卡片时滑出按钮"的效果,完全不需要 JavaScript。但:hover有个边界:在触屏设备上没有悬停状态,所以不能把关键交互做成只通过 hover 触发。移动端一定要保证默认状态可操作,hover 效果只能是锦上添花。
另一个注意点是:hover配合transition的时候,进入和退出动画的速度差异。默认情况下,鼠标移入移出都会应用transition。如果你希望移入快、移出慢(或者相反),可以分别写在默认状态和 hover 状态里。
5.2 transition 与 animation:上手容易,细节不小
transition是用来做状态过渡的,它需要触发条件(比如 hover、class 变化);animation是主动播放的,从页面加载开始或指定时间自动执行。两者互补,覆盖了大多数 CSS 动效需求。
transition 的四个子属性分别是:
transition-property:要过渡的属性名(写 all 省事,但性能不如指定属性)transition-duration:过渡时长transition-timing-function:缓动函数transition-delay:延迟启动时间
写在一起时要注意顺序:第一个时间是 duration,第二个时间才是 delay。
.box { transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) 0.1s; }缓动函数cubic-bezier是新手最陌生的部分。默认的 ease 其实还可以,但想要更好的动效质感,推荐记住几个常用的曲线:
ease-in-out:缓慢开始,缓慢结束,最通用cubic-bezier(0.4, 0, 0.2, 1):Material Design 的标准曲线cubic-bezier(0.34, 1.56, 0.64, 1):带有一点回弹效果的曲线
回弹效果那行代码的意思是:动画中途会轻微超过目标值再弹回来,视觉上很活泼,适合做按钮点击、弹窗出现的动效,但用在进度条这类严肃场景就不合适了。
关键帧动画@keyframes的基本结构:
@keyframes fadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .animate-in { animation: fadeInUp 0.5s ease-out both; }animation缩写中最后那个both是animation-fill-mode,它决定动画结束前后元素的样式状态。both意味着:动画开始前应用from的样式,动画结束后保持to的样式。如果省略这个参数,动画播放完毕后元素会回到初始状态,很容易出现"一闪而没"的效果。
"css从入门到精通——动画"这个热搜词下面,最常见的需求其实是 loading 动画。用animation实现一个无限旋转的加载图标:
.spinner { width: 32px; height: 32px; border: 3px solid rgba(0, 0, 0, 0.1); border-top-color: #3498db; border-radius: 50%; animation: spin 0.8s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } }只给边框的顶部上色,其余边框透明浅色,就能得到一个经典 loading 圈。animation: spin 0.8s linear infinite中的linear是旋转类动画的标配,因为如果用 ease,旋转速度就会忽快忽慢。
6. 选择器与样式组织:写 CSS 的底层思维
6.1 基础选择器与优先级:为什么我写的样式不生效
"css id选择器""css选择器""样式表中使用*的优缺点"都在问选择器的问题。选择器的本质是"如何精确命中要改样式的元素",而样式不生效往往不是没命中,而是优先级不够。
CSS 的优先级计算可以简化为三档:id 选择器 > class 选择器 > 标签选择器。同档位比较数量,多的胜出。内联样式优先于所有选择器,!important又凌驾于内联样式之上(除非有另一个!important加更大优先级的组合)。
具体计算时,推荐用 (a, b, c) 三元组:
- a = id 选择器个数
- b = class、属性选择器、伪类个数
- c = 标签选择器、伪元素个数
比较时先比 a,再比 b,最后比 c。这个计算方式能解释很多"灵异事件":
/* 优先级 (0, 2, 1) */ .nav .item:hover a { color: red; } /* 优先级 (1, 0, 0) */ #nav-link { color: blue; }即使前者写了一大串,id 选择器的一个 a 得分就压过所有 class+标签组合。所以想覆盖 id 样式,除非用!important,否则只能靠另一个 id 选择器。这也是很多人建议少用 id 做样式钩子的原因——复用性太差,改起来太痛苦。
"css 样式表中使用*的优缺点"说的是通配选择器*。优点是一句就能重置所有元素:* { margin: 0; padding: 0; },在老旧项目里快速清掉浏览器默认间距。缺点是匹配了所有元素,性能上有微小损耗,而且会误伤很多需要保留默认样式的场景。更现代的 reset 方案是针对特定元素设置:
blockquote, dl, dd, h1, h2, h3, h4, h5, h6, figure, p, pre { margin: 0; }现在项目里通常用 CSS Reset 库(如现代-normalize)配合* { box-sizing: border-box }使用,既保留了必要的默认样式,又解决了盒模型的心算问题。
6.2 样式引入的三种方式:内联、嵌入、外部与@import
"css样式引入方式"是另一个高频热搜,它问的是 CSS 以什么形式进入 HTML 页面。
- 外部样式表:
<link rel="stylesheet" href="style.css">,最推荐的方式,样式与结构分离,便于缓存复用。 - 嵌入样式表:
<style>放在<head>里,适合单页小项目或首屏关键样式。 - 内联样式:
style=""写在标签上,优先级很高,但不可复用,适合动态修改或个别紧急覆盖。
@import url("style.css")也经常被人提起,但我不推荐它在业务项目里使用。@import会阻塞渲染,因为它必须在 CSS 文件加载后、再发起一次网络请求加载被导入的文件;而且它只能出现在样式表的最前面,嵌套过多还会拖慢页面的解析速度。用<link>标签让浏览器并行加载,是更稳妥的选择。
CSP(Content Security Policy)安全策略里有时候会限制内联样式,导致style=""无法生效。如果遇到这类情况,优先检查页面的 CSP 配置。
6.3 原子化 CSS 的讨论与实际体验
"原子性css"这个热搜词涉及的是一个更工程化的话题:把一条条 CSS 规则拆成单一用途的原子类。比如flex、center、mt-4,一个类名只做一件事,在 HTML 里组合使用。
它的优势很明显:类名复用率高,样式几乎不会重复定义;改样式不用动 CSS 文件,直接在 HTML 里换个类;配合 Tailwind CSS 这类工具,开发速度确实快。缺点是 HTML 类名会变得很长,可读性有所下降,而且完全依赖工具的约定,团队里每个人都得学习这套类名体系。
我的实际体验是:原子化 CSS 适合组件化程度高、设计规范清晰的中后台项目;如果是大量自定义视觉的 C 端营销页,传统语义化类名配合 CSS Modules 或 BEM 仍然更合适。工具没有优劣,只有匹配的业务场景。
"css定义与引用"和"css基础知识点总结"这两个热搜词,其实指向的是同一个问题:CSS 怎么从"会写"变成"写得有体系"。我个人的建议是,把文字样式、盒模型、布局、动效、选择器这五大块当作主线,每个知识点先在 CodePen 或本地 HTML 里跑一个最小实例,理解它为什么这样工作,再开始堆页面。比起记一堆现成代码片段,理解属性的计算和作用机制,迁移到新场景时才不会卡壳。
最后分享一个我处理样式问题的习惯:遇到怪异表现时,先在浏览器 DevTools 里检查元素的计算后样式(Computed 面板),它会告诉你最终生效的 margin、width、display 到底是什么值——大多数布局问题,看一眼 Computed 就真相大白了。CSS 属性的每个细节,说到底都是在回答"这个元素在页面上应该占据什么位置、以什么形态呈现"这一个问题。