CSS常见问题
CSS3 有哪些新特性?
并不存在一份名为「CSS3」的独立完整标准。
现代 CSS 以 CSS 2.1 作为基线,所有新增能力以独立模块形式持续演进;CSS1、CSS2 原有语法至今保持兼容可用。
日常俗称「CSS3」的特性:
- 变换、过渡、动画:
transform、transition、animation、@keyframes - 现代布局:Flex、Grid、columns
- 边框与阴影:
border-radius、box-shadow、border-image - 背景与渐变:
background-size、background-origin、background-clip、linear-gradient()、radial-gradient() - 文本排版:
text-shadow、writing-mode、word-break、overflow-wrap、font-size-adjust - 选择器扩展:属性选择器(
^=、$=、*=)、兄弟选择符E~F - 伪类
:root、:not()、:nth-child()、:target、:checked - 伪元素
::selection、::placeholder - 颜色体系:
rgba、hsla、currentColor、opacity - 盒模型:
box-sizing - 单位扩展:
rem、vw、vh、vmin、vmax、ch、q - 函数与变量:
calc()、var() - 混合模式:
mix-blend-mode、background-blend-mode - 规则:
@font-face、@supports
后续持续新增、目前广泛使用的现代 CSS 特性:aspect-ratio、clamp()、gap、dvh、:is()、:where()、:has()、@layer。
各阶段标准化模块参考:CSS Snapshot
reset.css 和 normalize.css 有什么区别?
两者目标都是抹平浏览器默认 UA 样式,但实现思路完全相反。
- reset.css:尽可能清除浏览器自带默认样式,消除语义标签外观差异;标题、段落、强调文本会失去原生字号、权重层级。
- normalize.css:保留合理原生默认样式(例如:
h1 ~ h6字号层级),仅修复跨浏览器不一致问题与已知Bug,适合 HTML5 项目,作为传统 reset 的替代方案。
备注:reset.css 仅作参考,不推荐直接作为新项目默认方案。
标准 CSS 盒模型和 IE 盒模型有什么区别?
元素盒模型由内容区、padding、border、margin 四部分组成,核心差异:width、height 是否包含内边距与边框。
content-box(标准默认):宽高仅代表内容区域;border-box(旧称IE盒模型):宽高包含内容区 + padding + border,不含 margin。
通过 box-sizing 切换模式,通用重置:* { box-sizing: border-box; }。
备注:IE6~8 缺失标准 DOCTYPE 时,默认使用 border-box;现代浏览器只要声明标准 DOCTYPE,默认均为 content-box。
CSS 选择符有哪些?
- 基础选择器:ID
#id、类.class、元素div、通配符* - 关系选择器:后代
h1 p、子代ul > li、相邻兄弟li + a、通用兄弟li ~ a - 属性选择器:
a[rel]、a[rel="external"]、[attr^=val]、[attr$=val]、[attr*=val] - 伪类:
:hover、:nth-child()、:is()、:where()、:has() - 伪元素:
::before、::after、::selection、::placeholder
备注::where() 选择器特异性为 0;伪类 :is()、:has() 自身不增加权重,权重取自内部参数中特异性最高者。
CSS 中哪些属性可以继承?
CSS 规范中每个属性都会标注是否默认继承(Inherited: Yes | No),决定元素未赋值时的取值逻辑。
- 继承属性:未显式赋值时,取用父元素对应属性的计算值(根元素除外)。
- 非继承属性:未显式赋值时,使用属性自身初始值。
常见默认可继承属性:
- 字体:
font、font-family、font-size、font-weight、font-style、font-variant - 文本:
color、line-height、text-indent、text-align、letter-spacing、word-spacing、text-transform、direction - 列表:
list-style及其子属性 - 表格:
caption-side、border-collapse、border-spacing、empty-cells - 其他:
visibility、cursor、quotes
典型默认不可继承属性:盒模型——width、height、margin、padding、border,display、float、position、background、vertical-align、text-decoration、opacity、content、outline。
重要提示:
a标签颜色、h1 ~ h6字号看似无法继承,是浏览器 UA 样式预先设置了独立值,并非属性不支持继承。- 任意属性均可使用
inherit,强制从父元素继承计算值,不受默认继承规则限制。
all: unset 和 all: revert 有什么区别?
all 属性一次性重置除 direction、unicode-bidi 之外所有 CSS 属性:
initial:使用规范定义的属性初始值。inherit:直接继承父元素计算值。unset:继承属性等价inherit;非继承属性等价initial。revert:回退到作者样式之前——继承属性等价inherit;非继承属性使用浏览器 UA 默认样式。如果 UA 没有定义这条属性,会继续落到initial。revert-layer:仅回退至当前@layer之前,用于层叠层场景。
核心概念:
- initial:CSS 规范给这个属性定义的全局初始值(和 HTML 标签无关)。
- 浏览器 UA 默认样式:浏览器针对
<div>、<h1>、<span>这类元素单独写的样式。
最直观例子:CSS 规范里,display 属性全局初始值固定为 inline,对所有元素都一样;<div>、<p>、<h1> 默认独占一行,不是规范初始值,是浏览器内置 UA 样式表提前声明:
/* 浏览器内置 UA 样式 */
div { display: block; }
p { display: block; }
h1 { display: block; }
div {
display: unset; /* initial → inline */
display: revert; /* 恢复浏览器 UA 样式 → block */
}
CSS 的简写属性有哪些?
简写属性可一次性批量设置多个长属性,未显式声明的子属性会重置为初始值,容易覆盖前置样式。
background: color image repeat attachment position / size origin clip;
font: style variant weight size/line-height family;
transition: prop duration timing delay;
animation: name duration timing delay count direction;
border: width style color;
margin: top right bottom left;
padding: top right bottom left;
outline: width style color;
flex: grow shrink basis;
flex-flow: direction wrap;
grid-template: rows columns;
list-style: type position image;
text-decoration: line style color;
CSS 优先级算法如何计算?
当多个选择器为同一元素的同一属性设置不同值时,浏览器依靠层叠(Cascade)规则选出最终生效声明。CSS 全称层叠样式表,层叠就是解决样式冲突的核心机制。
完整层叠判断顺序(优先级从高到低,前一级分出胜负,不再对比后续条件):
- 来源与重要性(!important)
- 选择器优先级(特异性 Specificity)
- 源码声明顺序
来源与重要性(最高层级)
样式来源分三类:浏览器 UA 样式、用户样式(用户在浏览器自定义的样式)、作者样式(开发者写的样式)。
样式来源优先级:
- 无
!important:作者样式 > 用户样式 > UA 样式。 - 有
!important(优先反转):UA!important> 用户!important> 作者!important。
@layer 特性:@layer层级优先级高于选择器权重,跨层对比时不再比较选择器特异性。
- 无
!important:后声明层优先级 > 先声明层;未归入任何层的样式,优先级高于所有具名层。 - 有
!important:层顺序反转,先声明层优先级 > 后声明层。
注意:@keyframes 动画样式优先级高于普通作者样式,但低于带 !important 的声明;transition 是过渡过程中的插值结果,进行中时压过普通声明与动画声明,与 !important 的相对关系以实现为准。
1. UA 普通样式
2. 用户普通样式
3. 作者普通样式
4. @keyframes 动画样式
5. 作者 !important
6. 用户 !important
7. UA !important
8. 正在执行过渡的插值值(进行中,居前列)
选择器优先级(特异性)
优先级使用四元组 (A, B, C, D):从左向右依次比较,各级之间不存在进制,不会进位。
- A:内联样式(元素
style属性),有则 A=1,无则 A=0; - B:ID 选择器,出现次数累加;
- C:类选择器、属性选择器、伪类选择器,出现次数累加;
- D:标签选择器、伪元素选择器,出现次数累加。
边界规则:
- 通配符
*、关系选择器(>、+、~)不计算优先级; :not()、:is():自身不增加权重,但括号内部选择器正常参与优先级计算;:where():自身不增加权重,括号内部选择器也不参与优先级计算;- 重复书写同类选择器可以叠加权重:
.c01.c01优先级(0,0,2,0)。
源码顺序规则
当来源重要性一致且优先级四元组完全相等,后声明的样式覆盖先声明样式。
要点说明
!important:不属于优先级四元组,是作用在【来源与重要性】层级。
规则:先对比重要性,重要性相同才对比选择器优先级。同来源内,
!important直接击败普通声明。想要覆盖一条带!important的作者样式,只能是同来源、同样带!important,优先级更高或者位置更靠后的声明。内联样式同样可以添加
!important,会改变它在重要性层级的排序。a标签颜色、h1~h6:不是不能继承,是浏览器 UA 样式预先设置了独立值,覆盖了继承值,属性本身支持继承。- 历史知识:256 个 class 超越 1 个 ID 属于老旧浏览器实现 bug,现代标准浏览器严格按「无进位」规则执行,不存在该现象。
什么是 CSS 包含块?
包含块(containing block)是元素计算百分比尺寸、偏移量的参考矩形。绝大多数场景为最近祖先块级盒内容区,元素 position 属性会改变包含块查找规则。
判定规则:
static、relative、sticky:最近块容器祖先(如block、inline-block、表格单元格等)的内容区。absolute:最近非static定位祖先的内边距盒。fixed:屏幕场景为视口;分页媒体为页面容器。- 祖先拥有
transform、filter、perspective、contain: paint、will-change: transform等属性时,会成为absolute、fixed元素的包含块。
百分比取值规则:
width、left、right、padding、margin:相对包含块宽度。height、top、bottom:相对包含块高度;若包含块高度由内容自适应,百分比失效,等价auto。
备注: position: sticky 的包含块规则同 static/relative,但 sticky 的吸附参照对象是最近具备滚动机制的祖先(滚动容器),而 sticky 效果有效范围受自身包含块约束,滚动超出包含块边界后,不再保持吸附。
<div style="height:500px; border:2px solid red;">
<!-- 滚动容器:scroll-wrap -->
<div class="scroll-wrap" style="overflow:auto; height:300px;">
<!-- 包含块:box -->
<div class="box">
<div class="sticky" style="position:sticky;top:0;">粘性元素</div>
<div style="height:600px;">滚动内容</div>
</div>
</div>
</div>
注意:根元素 <html> 的包含块称为初始包含块,屏幕环境等价视口。
CSS 如何隐藏元素?
常用的三种方案:
display: none:元素移出渲染树,不占据布局空间。无法响应鼠标事件,不支持过渡动画,触发重排,子元素无法单独恢复显示。visibility: hidden:保留布局空间。不响应鼠标事件,样式可继承,不触发重排,子元素可设置visibility:visible重新显示,支持transition。opacity: 0:保留布局空间。可响应鼠标事件,可过渡,不触发重排(部分引擎会为此做合成层优化)。
其他方案:
position:偏移至视口外部。clip-path:裁剪隐藏。transform: scale(0)height:0+overflow: hiddenz-index:负值。content-visibility: hidden:跳过渲染,保留原有布局占位。
display、position、float 之间有什么关系?
浏览器解析优先级顺序:display: none > position: absolute、fixed > float > 常规 display。
display: none:忽略position、float;absolute、fixed:float失效,元素自动块化(inline→block、inline-flex→flex);float: not none:元素自动块化;- 常规
display。
什么是可替换元素?
元素渲染内容不由当前文档 CSS 决定,由外部资源渲染,CSS 仅控制盒子尺寸与位置。
典型:img、video、iframe、embed、input[type="image"]、canvas。
关键特性:
- 无自定义尺寸时,部分替换元素默认尺寸
300×150,图片优先使用图像固有尺寸; vertical-align: baseline会出现底部留白,根源是替换元素基线对齐规则;- 尺寸优先级:CSS
width、height> HTMLwidth、height属性 > 固有尺寸(前两者均为auto时才用固有尺寸); object-fit、object-position专门控制内部资源裁切与对齐。
块容器内,为什么有不可见节点?
规范名称 strut。
行框内部存在一个不可见零宽行内盒,继承父元素字体、行高,参与基线对齐。
CSS2.1 规范原文(§10.8 Line height calculations)
On a block container element whose content is composed of inline-level elements, 'line-height' specifies the minimal height of line boxes within the element. The minimum height consists of a minimum height above the baseline and a minimum depth below it, exactly as if each line box starts with a zero-width inline box with the element’s font and line height properties. We call that imaginary box a "strut." (The name is inspired by TeX.)
对于内容由行内级元素构成的块容器元素,
line-height指定容器内行框的最小高度。该最小高度由基线之上最小高度与基线之下最小深度共同组成;其效果等价于:每个行框起始处都存在一个零宽度行内盒,继承该元素的字体与行高属性。这个假想盒子称为 strut(命名灵感源自 TeX 排版系统)。
最典型现象:img(默认 vertical-align:baseline)底部出现多余空白间隙,根源就是 strut 基线对齐。
解决方案:
- 图片设置
display:block; - 父容器设置
line-height: 0; - 图片修改
vertical-align: top/middle/bottom; - 父容器使用
flex布局。
什么是空白字符?
源码标签之间的空格、换行、Tab,浏览器合并为单个空格,占据水平空间,会撑开相邻行内元素间距。
解决方案:
- 标签紧贴书写,删除中间换行、空格等;
- 父容器
font-size:0,子元素重设字号; - 改用
flex、grid布局,子项之间空白字符不再渲染。
注意:不可见节点影响垂直间距;空白字符造成水平间距。
如何在实现小于 12px 的文字渲染?
部分浏览器、WebView 存在最小字号兜底策略,font-size < 12px 会被强制放大。
各平台兼容表现:
- 桌面端(Chrome、Edge,Chromium 内核):中文环境自带最小字号保护,小于 12px 会被强制拉升;
-webkit-text-size-adjust: none桌面端已失效,无法绕过该限制。 - iOS(Safari、iOS版Chrome):无强制 12px 字号下限,可直接渲染小字号。
- 原生 Android Chrome 内核:不存在 12px 强制下限。
- 国内安卓内嵌 WebView、套壳浏览器(微信、QQ内置浏览器、UC、夸克等):大量机型存在厂商自定义字号兜底,小于 12px 文字被强制抬高。属于厂商定制策略,
-webkit-text-size-adjust无法解决。
解决方案:
- transform: scale() 缩放容器,搭配
transform-origin修正位置偏移。缺陷:仅视觉缩小,元素原始占位尺寸不变,容易出现布局留白;低分屏文字可能模糊。 - SVG 文字:矢量渲染,不受网页字号规则限制,清晰度高;适合固定展示类文字,不适合大段动态文本。
滚动条隐藏后,为什么无法再次显示?
::-webkit-scrollbar 属于 WebKit 非标准伪元素,存在特殊渲染逻辑。
滚动条伪元素层级结构:
::-webkit-scrollbar (整个滚动条容器)
├── ::-webkit-scrollbar-track (滚动条轨道)
├── ::-webkit-scrollbar-thumb (滚动条滑块)
├── ::-webkit-scrollbar-button (上下、左右按钮)
└── ::-webkit-scrollbar-corner (横竖滚动条交汇处角落)
核心原理:::-webkit-scrollbar 设置 display: none,浏览器会直接从渲染树移除整套滚动条伪元素,不再创建该伪元素及其所有子伪元素。 后续通过样式修改 display(block、initial、revert)无法恢复显示,因为样式无法作用于一个不存在的渲染对象,属于 WebKit 内核特有渲染行为。
若仅给 ::-webkit-scrollbar-thumb、::-webkit-scrollbar-track 单独定义样式,即便父级 ::-webkit-scrollbar 设置 display: none,浏览器检测到子伪元素存在自定义样式,会重建滚动条相关伪元素,最终滚动条依旧显示。
.box::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.2);
border-radius: 4px;
}
.box::-webkit-scrollbar-track {
background-color: transparent;
}
.box.hide-scroll::-webkit-scrollbar {
width: 0;
height: 0;
}
.box.show-scroll::-webkit-scrollbar {
width: 6px;
height: 6px;
}
如何实现宽高比?
宽高比指元素宽度与高度的比值,常见写法 x:y。
在 Web 领域最早应用于响应式图片、视频,现在业务中普通容器(卡片、封面、占位框)也经常需要维持固定长宽比。
利用可替换元素
可替换元素:<img>、<video>、<iframe>,自身携带固有的像素尺寸与固有长宽比。
对于原生图片、视频,只需要固定其中一个方向尺寸,另一个方向设置为 auto,浏览器会按照素材本身固有比例自动计算。
img { width: 100%; height: auto; }
video { width: 100%; height: auto; }
利用透明占位图撑开容器:
普通 div 容器借助可替换元素维持比例,可以引入一张对应比例的透明占位图片做撑开,业务内容使用绝对定位浮在图片上层。
<div style="position: relative; width: 100%;">
<img src="transparent‑4‑3.png" style="width: 100%; height: auto;">
<div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0;">
卡片业务内容
</div>
</div>
padding‑top(经典)
CSS 规则:padding‑top、padding‑bottom 百分比值,参照的是父容器的宽度,而不是高度。
实现:把元素高度置为 0,通过垂直方向 padding 撑开盒子的高度,内容必须绝对定位,否则会被 padding 推到盒子外面。
限制:只能实现高度跟随宽度变化,无法做到宽度跟随高度变化。
<style>
.ratio‑wrap {
position: relative;
width: 100%;
height: 0;
/* 16 : 9 → 9 / 16 * 100% = 56.25% */
padding‑bottom: 56.25%;
}
.ratio‑inner {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
<div class="ratio‑wrap">
<div class="ratio‑inner">内容区域</div>
</div>
可以配合 calc() 动态计算百分比,适配任意自定义比例:
/* 比例 = 高 / 宽 * 100% */
padding‑bottom: calc(9 / 16 * 100%);
aspect‑ratio
aspect‑ratio 是 CSS Box Sizing Module Level4 新增属性,专门用来声明盒子的首选纵横比,不需要嵌套盒子、不需要 Hack。
- 初始值:
auto - 不继承;不作用于行内盒子、表格内部盒子。
取值:
auto:可替换元素沿用自身固有长宽比;普通盒子没有预设长宽比。<width‑value> / <height‑value>:16/9、4/3、1/1。
.box‑16‑9 { width: 100%; aspect‑ratio: 16 / 9; background‑color: #0aa; }
.box‑square { width: 300px; aspect‑ratio: 1 / 1; }
属性特性:
- 既可以高度跟随宽度变化;也可以固定高度,让宽度跟随高度变化。
- 当内部内容高度超过盒子计算高度,盒子会被内容自然撑开,不会强制死守比例。
- 兼容性:IE 完全不支持;Chrome 88+、Firefox 89+、Safari 15.4+ 支持;如果要兼容旧设备,需要降级到
padding‑bottom方案。
注意:aspect‑ratio 是首选比例,不是强制;当元素同时设置明确的 width、height,width / height 的优先级高于 aspect‑ratio。
JavaScript 动态计算
在需要兼容非常老旧浏览器,或是长宽比是运行时动态获取的场景,可以用 JS 获取容器宽度,按比例计算并设置元素高度。
function setRatio(box, ratio) {
const w = box.clientWidth;
box.style.height = `${w / ratio}px`;
}
setRatio();
window.addEventListener('resize', setRatio);
letter-spacing、word-spacing、white-space 有什么不同?
letter-spacing:字符间距,汉字、字母都生效,不支持百分比。word-spacing:仅作用于单词之间的空格,中文场景基本无效。white-space:控制空白合并、自动换行规则。
min-width、max-width、width 的覆盖规则?
不受 CSS 特异性影响,由浏览器计算值规则决定:
max-width:上限优先级高于width;- 当
min-width > max-width,min-width生效; height、min-height、max-height遵循完全一致规则。