var(--x) 的值不是合法颜色,color 最终会是什么?
var() 替换后若得到不合法的属性值,声明可能直到计算值阶段才失效,浏览器不会回头采用级联里上一条同属性声明。它会回到继承值或初始值;var() 自带的回退参数只处理变量缺失或变量本身无效,不是任意值校验。
程序员面试题库第 24 页,收录第 1151–1200 题,共 5000 道完整解析,覆盖前端、JavaScript、React、Vue、Node.js、AI Agent、网络、数据库与系统设计。
按稳定语义路径排序
var() 替换后若得到不合法的属性值,声明可能直到计算值阶段才失效,浏览器不会回头采用级联里上一条同属性声明。它会回到继承值或初始值;var() 自带的回退参数只处理变量缺失或变量本身无效,不是任意值校验。
自定义属性声明在组件根节点上会沿后代继承,局部覆盖可改变整个子树的主题值,无须都写在 :root。var() 回退值只在变量不存在或无效时参与;Shadow DOM 继承边界和 @scope 的选择器范围也会影响最终值。
:hover 随指针悬停变化,:focus 跟随真实焦点,:focus-visible 更适合显示键盘操作所需的焦点提示。触屏设备可能保留悬停状态,链接伪类也会相互覆盖;交互样式应保证鼠标与键盘都能看清当前目标。
::first-line 选择块容器实际排版后的第一行文字,容器宽度变化、字体加载或内容改动都可能改变被选中的字符。它只支持部分文本相关属性,不适用于普通行内盒或 Flex、Grid 容器;不能把它当作固定的首句选择器。
:has() 能按后代或相邻元素的状态选择当前元素,例如表单里有无无效输入、卡片里是否存在图片。它的优先级取决于参数选择器,复杂匹配也可能增加样式计算成本;用它选择父级时还要考虑支持范围和备选样式。
!important 影响声明在 CSS 级联中的优先级,但不能只和选择器权重相比。来源与层叠层先决定重要声明的竞争顺序,重要层的排序还会反转;内联样式、动画与过渡各有位置,排查覆盖失败时需逐层比较。
inherit 强制采用父元素的计算值,initial 使用规范定义的初始值,unset 则按属性是否可继承在两者间选择。revert 会退回更低级的样式来源;重置按钮或表单控件时,这些关键字会产生不同于“恢复浏览器默认”的结果。
表单控件常带浏览器默认字体和颜色,因此不一定跟随父元素;显式设置 inherit 可以让它取父级计算值。链接颜色、非继承属性也能这样处理,但子元素已有自己的声明时,默认继承不会覆盖它,inherit 作为声明则会参与级联。
继承值只在子元素没有该属性的直接声明时才使用,通配符 * 命中的低权重声明也能覆盖继承。inherit 和 unset 作为显式声明仍要参与正常级联;开发者工具里分清“本元素声明”与“从父元素继承”,才容易定位颜色或字体来源。
:is() 和 :where() 都能合并多组选择器,但 :is() 采用参数中最高的优先级,:where() 始终为零。组件选择器简化时,两者可能匹配完全相同元素却产生不同覆盖结果;需要易于覆盖的基础样式更适合 :where()。
未分层样式的优先级高于所有命名层,不管选择器权重。理解这条规则才能正确利用 @layer 管理第三方库样式,也能避免迁移过程中的优先级意外。会用普通声明和 important 声明分别比较,避免把两种顺序混为一谈。
@layer 把样式分组成层,层的优先级由声明顺序决定,越靠后优先级越高。掌握层叠层的声明方式和排序规则,解决第三方样式覆盖和大型项目样式冲突问题。还会说明层名首次出现的位置为何决定后续重复声明的排序。
普通样式里后声明的层赢,加 !important 后变成先声明的层赢。理解这个反转规则,才能正确使用层叠层管理第三方库的 !important 样式。并说明未分层的 important 声明在层叠顺序中处于什么位置。
同一个 @layer 出现多次时,层的优先级以第一次出现为准,后续只追加规则不改变顺序。掌握预声明、多次打开、嵌套层的排序规则,避免样式优先级混乱。通过多文件重复打开同一命名层的例子,说明它不是新建一层。
不同层的规则冲突时,层的声明顺序优先于选择器权重和源码顺序。弄清层间比较的规则,理解为什么高权重选择器会输给低权重选择器。通过跨层冲突说明何时才轮到选择器权重和源码顺序比较。
:nth-child(an+b) 把非负整数 n 依次代入公式,命中的正整数就是元素在同辈中的序号。2n、2n+1 和 -n+3 分别适合偶数行、奇数行和前几项;表格斑马纹或列表强调效果要按所有元素兄弟的位置计算。
:only-child 要求目标元素没有任何元素兄弟,:only-of-type 只要求同标签兄弟不存在。混合标签排列时,两者可能给同一个节点不同结果;卡片容器只有一个子元素和段落中只有一个同类标题,适用的选择器也不同。
浏览器不认识选择器中的伪类或伪元素时,整条普通选择器规则可能被丢弃,回退样式不应与新选择器绑在同一组中。@supports selector() 可检测支持情况,再逐步增强;私有前缀伪元素尤其需要单独规则。
:indeterminate 可匹配半选复选框、没有选中项的某些单选组和不确定进度条。复选框的半选状态通常由 JavaScript 设置,视觉状态不等于 checked 的提交值;全选控件显示半选时,还要单独处理实际选中逻辑。
:focus-within 在元素本身或任意后代拥有焦点时匹配,适合高亮整个表单字段组或展开包含输入框的面板。它不会把焦点移到父元素;与 :focus 相比,触发范围更大,组件嵌套时需要注意样式向上联动。
:required 匹配带 required 属性的表单控件,:optional 匹配不要求必填的控件,两者描述属性状态而不是用户当前输入是否有效。禁用控件也可能匹配必填规则;表单错误样式要把必填状态与 :invalid 等校验状态分开处理。
:target 匹配当前 URL 片段所指向的元素,例如 #intro 对应 id="intro" 的区块。目录跳转可据此高亮目标,纯 CSS 选项卡也能利用它;片段改变会即时切换匹配状态,目标不存在时则没有元素被选中。
::before 和 ::after 生成的内容由 content 指定,可以是文字、计数器、属性值或空字符串;没有有效的 content 通常不会产生伪元素盒子。它们适合装饰标记、编号等视觉内容,关键信息和交互内容仍应放在真实 DOM 中。
::selection 只能设置少数与选中文本相关的样式,例如文字颜色与背景色,不能像普通元素那样随意改布局。高对比度主题下还要保证选中文字可读;不同浏览器对可用属性与继承细节可能有差异。
:in-range 和 :out-of-range 只对支持范围约束的输入类型有意义,按 min、max 与当前值决定匹配结果。它们描述是否越界,不等于整个控件的 :valid 或 :invalid 状态;必填、格式错误等其他约束仍要另行判断。
:hover、:focus 等伪类匹配现有元素的状态,::before、::selection 等伪元素则选中元素的一部分或生成内容。单冒号的旧版伪元素写法为兼容保留,新增代码通常用双冒号;状态选择与生成内容可以组合,但语义不能互相替代。
revert 会把属性回退到上一个来源的值。对可继承属性来说,作者样式被撤销后,浏览器默认样式通常没有设置该属性,于是走正常继承、拿到父元素的值。但如果浏览器默认样式里显式设了值,结果会不一样。
revert 回退当前样式来源,在作者样式中会改用用户样式或浏览器默认值;revert-layer 回退当前层叠层,让较低优先级的层重新参与竞争。结合分层组件样式说明两者的适用场景,以及没有其他层可回退时的结果。
@scope 限制选择器的匹配范围,但外部样式仍然能穿透进来。Shadow DOM 建立真正的样式边界,内外互不影响。两者解决不同层次的问题,不能互相替代,但可以在 Shadow DOM 内部配合使用。
@scope 让样式只在指定的 DOM 子树内生效,还能用 to() 设下界排除嵌套区域。它不改变选择器优先级,但在优先级相同时,离作用域根更近的规则胜出。适合组件级样式命名空间,不需要编译工具。
@scope 的 to() 设置下界,排除指定子树不受作用域样式影响,适合防止嵌套组件被穿透。:scope 伪类指代作用域根元素本身,用于给根元素加样式或在选择器里引用根。两者功能完全不同。
选择器 ul#nav li.active a:hover 的优先级按 ID、类或伪类、元素三列计数,而不是把所有命中项简单加总。遇到 :is()、:where() 或内联样式时还有特殊规则;比较冲突声明前也要确认它们处于同一来源与层。
两条选择器规则只有在来源、重要性、层和优先级都相同时,书写顺序才决定谁胜出。引入 @layer 后,层的先后可压过层内较高的选择器优先级;覆盖第三方库样式时,应先看规则所在层,再排查构建后的实际顺序。
CSS 优先级按 ID、类、元素三列从左到右比较,ID 列有值就直接赢过类列,不看数量。讲解三列计算规则、为什么多个类拼不过一个 ID,以及实际项目中避免 ID 优先级过高的常用手段。
HTML 的 style 属性通常比普通选择器声明更靠前,但 !important 会改变级联比较的层级。内联重要声明、用户样式与层叠层仍有明确顺序;组件样式覆盖失败时,要先确认声明来源与重要性,再比较选择器权重。
:not() 自身不增加优先级,参数中最高优先级的选择器会计入结果;:is()、:has() 也按类似方式处理,:where() 则始终为零。多个参数或嵌套伪类时,需要按实际选择器结构计算,不能只数冒号个数。
:enabled 和 :disabled 只能选中可禁用的表单控件,对链接无效。这里说明哪些元素能被禁用、fieldset 禁用后对后代控件的影响,以及为什么仅写 disabled 属性未必能代表实际状态。
:first-child 看目标是不是父元素的第一个元素子节点,:first-of-type 则只在同标签兄弟里排位。前面插入一个不同标签时,后者仍可能匹配,前者会失效;给选择器加上标签名也不会改变这些伪类各自的计数范围。
CSS 变量的 var() 函数只接受一个可选备用值,多个逗号分隔的值不会逐个回退而是合并成整体。搞清回退触发条件、嵌套写法和无效值陷阱,主题系统的变量就不会踩坑。
暂停动画后改动同名关键帧,不会自动重启动画,但当前进度处的计算结果可能立即变化。区分冻结时间与冻结画面、修改关键帧与更换动画名,并给出用浏览器开发工具观察位置跳变的方法。
animation-direction 控制关键帧的播放方向。reverse 每轮倒着播,alternate 奇偶轮交替方向。搞清四种取值和缓动曲线反转的关系,动画方向就不会搞反。
animationstart、animationiteration 与 animationend 分别对应动画开始、新一轮循环和正常结束。正延迟会推迟开始事件,循环动画每轮未必都触发结束事件;动画被取消时还要考虑 animationcancel,监听逻辑不能只等最后一帧。
animation-fill-mode: backwards 会让元素在正延迟期间采用起始关键帧样式,动画结束后回到原样;both 同时具备 backwards 与 forwards 的效果。负延迟、动画方向和实际第一帧会改变视觉结果,不能简单把它理解成“永远显示 0% 帧”。
animation-delay 只发生在第一轮开始前,循环之间不会自动空出间隔。需要周期性停顿时,可把动作集中在关键帧前半段,让后半段保持同一状态;若停顿时长需动态变化,则适合用脚本控制播放状态。
关键帧中的 from 与 to 分别对应 0% 和 100%,中间可用任意百分比指定状态;端点缺失时,浏览器会依据元素的基础样式补齐。多个同名 @keyframes 规则的覆盖与同规则里重复百分比的合并不同,动画结果要分开判断。
paused 把动画冻结在当前帧,随时可以恢复继续播。负 delay 让动画跳过开头一段直接从中间开始,跳过的部分不会再播。两者对动画的影响完全不同,一个是暂停,一个是快进。
用 animation-timeline 把动画和滚动位置绑在一起,滚到哪动画就播到哪。讲解 scroll() 和 view() 两种时间线的区别、写法,以及浏览器兼容和常见坑。
filter 模糊元素自身,backdrop-filter 模糊元素背后的内容。讲解毛玻璃效果的写法、背景为何要留出透明度、模糊范围与性能开销,以及旧浏览器不支持时的降级方案。
卡片翻转 180 度后背面会透出正面的镜像内容,backface-visibility: hidden 就是把背面藏起来。讲解 3D 卡片翻转的完整结构、父容器的 perspective 设置,以及常踩的坑。
3D 变换、will-change、固定定位等都会触发合成层提升。讲解合成层的原理、will-change 的正确用法和常见的滥用问题,以及怎么在 DevTools 里检查层数。