CSS常见问题

CSS3 有哪些新特性?

并不存在一份名为「CSS3」的独立完整标准。

现代 CSS 以 CSS 2.1 作为基线,所有新增能力以独立模块形式持续演进;CSS1、CSS2 原有语法至今保持兼容可用。

日常俗称「CSS3」的特性:

  • 变换、过渡、动画:transformtransitionanimation@keyframes
  • 现代布局:Flex、Grid、columns
  • 边框与阴影:border-radiusbox-shadowborder-image
  • 背景与渐变:background-sizebackground-originbackground-cliplinear-gradient()radial-gradient()
  • 文本排版:text-shadowwriting-modeword-breakoverflow-wrapfont-size-adjust
  • 选择器扩展:属性选择器(^=$=*=)、兄弟选择符 E~F
  • 伪类 :root:not():nth-child():target:checked
  • 伪元素 ::selection::placeholder
  • 颜色体系:rgbahslacurrentColoropacity
  • 盒模型:box-sizing
  • 单位扩展:remvwvhvminvmaxchq
  • 函数与变量:calc()var()
  • 混合模式:mix-blend-modebackground-blend-mode
  • 规则:@font-face@supports

后续持续新增、目前广泛使用的现代 CSS 特性:aspect-ratioclamp()gapdvh: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 四部分组成,核心差异:widthheight 是否包含内边距与边框。

  • 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),决定元素未赋值时的取值逻辑。

  • 继承属性:未显式赋值时,取用父元素对应属性的计算值(根元素除外)。
  • 非继承属性:未显式赋值时,使用属性自身初始值

常见默认可继承属性

  • 字体:fontfont-familyfont-sizefont-weightfont-stylefont-variant
  • 文本:colorline-heighttext-indenttext-alignletter-spacingword-spacingtext-transformdirection
  • 列表:list-style 及其子属性
  • 表格:caption-sideborder-collapseborder-spacingempty-cells
  • 其他:visibilitycursorquotes

典型默认不可继承属性:盒模型——widthheightmarginpaddingborderdisplayfloatpositionbackgroundvertical-aligntext-decorationopacitycontentoutline

重要提示

  • a 标签颜色、h1 ~ h6 字号看似无法继承,是浏览器 UA 样式预先设置了独立值,并非属性不支持继承
  • 任意属性均可使用 inherit,强制从父元素继承计算值,不受默认继承规则限制。

all: unset 和 all: revert 有什么区别?

all 属性一次性重置除 directionunicode-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 属性会改变包含块查找规则

判定规则

  • staticrelativesticky:最近块容器祖先(如 blockinline-block、表格单元格等)的内容区
  • absolute:最近非 static 定位祖先的内边距盒
  • fixed:屏幕场景为视口;分页媒体为页面容器。
  • 祖先拥有 transformfilterperspectivecontain: paintwill-change: transform 等属性时,会成为 absolutefixed 元素的包含块。

百分比取值规则

  • widthleftrightpaddingmargin:相对包含块宽度。
  • heighttopbottom:相对包含块高度;若包含块高度由内容自适应,百分比失效,等价 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: hidden
  • z-index:负值。
  • content-visibility: hidden:跳过渲染,保留原有布局占位。

display、position、float 之间有什么关系?

浏览器解析优先级顺序:display: none > position: absolute、fixed > float > 常规 display

  • display: none:忽略 positionfloat
  • absolutefixedfloat 失效,元素自动块化(inlineblockinline-flexflex);
  • float: not none:元素自动块化;
  • 常规 display

什么是可替换元素?

元素渲染内容不由当前文档 CSS 决定,由外部资源渲染,CSS 仅控制盒子尺寸与位置。

典型imgvideoiframeembedinput[type="image"]canvas

关键特性

  • 无自定义尺寸时,部分替换元素默认尺寸 300×150,图片优先使用图像固有尺寸;
  • vertical-align: baseline 会出现底部留白,根源是替换元素基线对齐规则;
  • 尺寸优先级:CSS widthheight > HTML widthheight 属性 > 固有尺寸(前两者均为 auto 时才用固有尺寸);
  • object-fitobject-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,子元素重设字号;
  • 改用 flexgrid 布局,子项之间空白字符不再渲染。

注意:不可见节点影响垂直间距;空白字符造成水平间距。

如何在实现小于 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,浏览器会直接从渲染树移除整套滚动条伪元素,不再创建该伪元素及其所有子伪元素。 后续通过样式修改 displayblockinitialrevert)无法恢复显示,因为样式无法作用于一个不存在的渲染对象,属于 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‑toppadding‑bottom 百分比值,参照的是父容器的宽度,而不是高度

实现:把元素高度置为 0,通过垂直方向 padding 撑开盒子的高度,内容必须绝对定位,否则会被 padding 推到盒子外面。

限制:只能实现高度跟随宽度变化,无法做到宽度跟随高度变化。

<style>
  .ratio‑wrap {
    position: relative;
    width: 100%;
    height: 0;
    /* 16 : 9 → 9 / 16 * 100% = 56.25% */
    paddingbottom: 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% */
paddingbottom: calc(9 / 16 * 100%);

aspect‑ratio

aspect‑ratio 是 CSS Box Sizing Module Level4 新增属性,专门用来声明盒子的首选纵横比,不需要嵌套盒子、不需要 Hack。

  • 初始值:auto
  • 不继承;不作用于行内盒子、表格内部盒子。

取值:

  • auto:可替换元素沿用自身固有长宽比;普通盒子没有预设长宽比。
  • <width‑value> / <height‑value>16/94/31/1
.box169   { width: 100%; aspect‑ratio: 16 / 9; backgroundcolor: #0aa; }
.box‑square { width: 300px; aspect‑ratio: 1 / 1; }

属性特性:

  • 既可以高度跟随宽度变化;也可以固定高度,让宽度跟随高度变化。
  • 当内部内容高度超过盒子计算高度,盒子会被内容自然撑开,不会强制死守比例。
  • 兼容性:IE 完全不支持;Chrome 88+、Firefox 89+、Safari 15.4+ 支持;如果要兼容旧设备,需要降级到 padding‑bottom 方案。

注意aspect‑ratio首选比例,不是强制;当元素同时设置明确的 widthheightwidth / 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-widthmin-width 生效
  • heightmin-heightmax-height 遵循完全一致规则。

参考资料

MDN:继承

MDN:简写属性

MDN:特异性

MDN:层叠

MDN:包含块

MDN:可替换元素

MDN - aspect-ratio

© lizhao all right reserved,powered by Gitbook文件修订时间: 2026-08-20 21:20:08

results matching ""

    No results matching ""