CSS面试题汇总
2026年最新版 - 涵盖盒模型、布局、现代CSS新特性、响应式设计、动画与性能优化
📋 目录
基础概念
1. 什么是CSS盒模型?
每个HTML元素都是一个矩形盒子,由四部分组成:content(内容)、padding(内边距)、border(边框)、margin(外边距)。
两种盒模型:
| 模型 | box-sizing 值 | 宽度计算 |
|---|---|---|
| 标准盒模型 | content-box(默认) | width = 内容宽度 |
| IE盒模型 | border-box | width = 内容 + padding + border |
/* 推荐全局使用 border-box */
*, *::before, *::after {
box-sizing: border-box;
}
/* 标准盒模型:实际宽度 = 200 + 20*2 + 1*2 = 242px */
.content-box {
box-sizing: content-box;
width: 200px;
padding: 20px;
border: 1px solid #ccc;
}
/* IE盒模型:实际宽度 = 200px(内容自动缩小) */
.border-box {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 1px solid #ccc;
}2. 什么是BFC?如何触发?
BFC(Block Formatting Context,块级格式化上下文) 是一个独立的渲染区域,内部元素的布局不会影响外部元素。
触发BFC的条件:
overflow值不为visible(如hidden、auto、scroll)display值为flow-root、flex、grid、inline-blockposition值为absolute或fixedfloat值不为none
BFC的应用场景:
/* 1. 清除浮动 —— 推荐使用 display: flow-root */
.clearfix {
display: flow-root;
}
/* 2. 阻止外边距合并 */
.parent {
display: flow-root;
}
.child {
margin-top: 20px; /* 不会与父元素的margin合并 */
}
/* 3. 阻止元素被浮动元素覆盖 */
.float-left {
float: left;
width: 200px;
}
.content {
overflow: hidden; /* 创建BFC,不会环绕浮动元素 */
}3. margin合并和margin塌陷是什么?
margin合并:相邻块级元素的上下外边距会合并为较大的那个值。
margin塌陷:父元素和第一个/最后一个子元素的外边距会合并。
/* margin合并:两个p之间的间距是30px,不是50px */
.p1 { margin-bottom: 20px; }
.p2 { margin-top: 30px; }
/* 解决margin塌陷 */
.parent {
/* 方案1: 触发BFC */
display: flow-root;
/* 方案2: 添加border或padding */
/* border-top: 1px solid transparent; */
/* padding-top: 1px; */
}4. 元素隐藏的方式有哪些?区别是什么?
| 方式 | 占据空间 | 可交互 | 触发重排 | 子元素可见 |
|---|---|---|---|---|
display: none | ❌ | ❌ | ✅ | ❌ |
visibility: hidden | ✅ | ❌ | ❌ | ✅(设置visible) |
opacity: 0 | ✅ | ✅ | ❌ | ❌ |
position: absolute + 移出视口 | ❌ | ❌ | ✅ | ❌ |
clip-path: inset(50%) | ✅ | ❌ | ❌ | ❌ |
/* 屏幕阅读器可见的隐藏方式(无障碍推荐) */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}选择器与优先级
5. CSS选择器优先级如何计算?
优先级从高到低:
| 优先级 | 类型 | 示例 |
|---|---|---|
| ∞ | !important | color: red !important |
| 1000 | 内联样式 | style="color: red" |
| 100 | ID选择器 | #header |
| 10 | 类/伪类/属性选择器 | .nav, :hover, [type="text"] |
| 1 | 元素/伪元素选择器 | div, ::before |
| 0 | 通配符/关系选择器 | *, >, +, ~ |
/* 优先级: 0-1-0 (一个类) */
.title { color: blue; }
/* 优先级: 1-0-0 (一个ID) */
#title { color: red; }
/* 优先级: 1-1-1 (一个ID + 一个类 + 一个元素) */
#header .nav a { color: green; }
/* :where() 优先级为0,:is() 取参数中最高优先级 */
:where(.card, #main) { color: gray; } /* 优先级: 0-0-0 */
:is(.card, #main) { color: gray; } /* 优先级: 1-0-0 */6. :has() 选择器是什么?(2026重点)
:has() 被称为CSS的**"父选择器"**,可以根据子元素或后续兄弟元素的状态来选择父元素。
/* 选择包含图片的卡片 */
.card:has(img) {
grid-template-rows: auto 1fr;
}
/* 选择没有图片的卡片 */
.card:not(:has(img)) {
padding: 2rem;
}
/* 表单验证:输入框无效时,改变label样式 */
label:has(+ input:invalid) {
color: red;
}
/* 标题后面紧跟段落时,减少下边距 */
h1:has(+ p) {
margin-bottom: 0.25em;
}
/* 列表包含子列表时,添加左边框 */
ul:has(> li > ul) {
border-left: 2px solid #667eea;
}
/* 页面级状态控制:body包含dialog[open]时调暗背景 */
body:has(dialog[open]) {
overflow: hidden;
}7. 伪类和伪元素的区别?
- 伪类(
:):选择处于特定状态的元素,如:hover、:focus、:first-child - 伪元素(
::):创建DOM中不存在的虚拟元素,如::before、::after、::placeholder
/* 伪类 - 选中特定状态 */
a:hover { color: #667eea; }
li:nth-child(odd) { background: #f5f5f5; }
input:focus-visible { outline: 2px solid #667eea; }
/* 伪元素 - 创建虚拟元素 */
.quote::before {
content: '"';
font-size: 2rem;
color: #667eea;
}
/* 2026新伪元素 */
select::picker(select) {
appearance: base-select;
border-radius: 12px;
}布局
8. Flexbox布局详解
Flexbox 是一维布局模型,适合处理行或列方向的元素排列。
.container {
display: flex;
/* 主轴方向 */
flex-direction: row; /* row | row-reverse | column | column-reverse */
/* 换行 */
flex-wrap: wrap; /* nowrap | wrap | wrap-reverse */
/* 主轴对齐 */
justify-content: center; /* flex-start | flex-end | center | space-between | space-around | space-evenly */
/* 交叉轴对齐 */
align-items: center; /* flex-start | flex-end | center | stretch | baseline */
/* 多行对齐 */
align-content: space-between;
/* 间距(推荐替代margin方案) */
gap: 16px;
}
.item {
/* 放大比例 */
flex-grow: 1;
/* 缩小比例 */
flex-shrink: 0;
/* 基础尺寸 */
flex-basis: 200px;
/* 简写: flex: grow shrink basis */
flex: 1 0 200px;
/* 单独对齐 */
align-self: flex-end;
}经典面试题:实现水平垂直居中
/* 方案1: Flexbox(最常用) */
.center-flex {
display: flex;
justify-content: center;
align-items: center;
}
/* 方案2: Grid(最简洁) */
.center-grid {
display: grid;
place-items: center;
}
/* 方案3: 绝对定位 + transform */
.center-absolute {
position: relative;
}
.center-absolute > .child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}9. Grid布局详解
Grid 是二维布局模型,同时处理行和列。
.grid-container {
display: grid;
/* 定义列 */
grid-template-columns: repeat(3, 1fr);
/* 定义行 */
grid-template-rows: auto 1fr auto;
/* 间距 */
gap: 20px;
/* 区域模板 */
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
/* 自适应列数 */
.auto-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}10. Subgrid是什么?(2026重点)
Subgrid 允许子网格继承父网格的轨道定义,解决嵌套网格对齐问题。
.grid {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
gap: 1rem;
}
/* 子元素继承父网格的列轨道 */
.card {
display: grid;
grid-column: 1 / -1; /* 跨越所有父列 */
grid-template-columns: subgrid; /* 继承父网格列定义 */
}
/* 实际应用:卡片列表对齐 */
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
.card {
display: grid;
grid-row: span 3; /* 每个卡片占3行 */
grid-template-rows: subgrid; /* 继承父网格行定义 */
}
/* 卡片内部元素(标题、内容、按钮)自动跨卡片对齐 */
.card h3 { /* 第1行 */ }
.card p { /* 第2行 */ }
.card .btn { /* 第3行 */ align-self: end; }11. Flex和Grid如何选择?
| 场景 | 推荐 | 原因 |
|---|---|---|
| 导航栏 | Flex | 单行水平排列 |
| 表单字段 | Flex | 简单的标签-输入对齐 |
| 卡片列表 | Grid | 二维自适应网格 |
| 整体页面布局 | Grid | 复杂的行列结构 |
| 垂直居中 | 都可以 | Grid 更简洁 (place-items: center) |
/* 导航栏 - 用Flex */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
}
/* 仪表盘 - 用Grid */
.dashboard {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: 60px 1fr;
min-height: 100dvh;
}现代CSS新特性
12. CSS原生嵌套(2026重点)
不再需要Sass/Less等预处理器来实现嵌套,CSS原生支持嵌套语法。
/* CSS 原生嵌套 */
.card {
padding: 1rem;
border: 1px solid var(--border);
border-radius: 8px;
/* 嵌套子元素 */
& h3 {
margin: 0 0 0.5rem;
font-size: 1.25rem;
}
& p {
color: #666;
line-height: 1.6;
}
/* 嵌套伪类 */
&:hover {
border-color: #667eea;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 嵌套媒体查询 */
@media (max-width: 768px) {
padding: 0.75rem;
}
}
/* 对比 Sass 写法 —— 现在CSS原生即可 */13. 容器查询(Container Queries)是什么?(2026重点)
容器查询让组件根据父容器尺寸(而非视口)响应式调整,实现真正的组件级响应式设计。
/* 1. 声明容器 */
.card-wrapper {
container-type: inline-size; /* 开启容器宽度查询 */
container-name: card; /* 可选命名 */
}
/* 2. 根据容器宽度调整布局 */
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
gap: 1rem;
}
}
@container card (min-width: 600px) {
.card {
grid-template-columns: 250px 1fr auto;
}
.card .actions {
display: flex;
flex-direction: column;
}
}
/* 3. 容器查询单位 */
.card-title {
font-size: clamp(1rem, 3cqw, 1.5rem); /* cqw = 容器宽度的1% */
padding: 2cqi; /* cqi = 容器内联尺寸的1% */
}容器查询 vs 媒体查询:
| 特性 | 媒体查询 @media | 容器查询 @container |
|---|---|---|
| 基于 | 视口尺寸 | 父容器尺寸 |
| 组件复用 | 不同上下文需调整 | 自动适配 |
| 粒度 | 页面级 | 组件级 |
| 使用场景 | 整体布局 | 组件内部布局 |
14. @starting-style 和离散属性动画(2026重点)
@starting-style 让元素在首次渲染时也能有过渡动画,解决了 display: none 到 display: block 无法动画的历史难题。
/* 弹窗淡入淡出 */
dialog {
opacity: 1;
transform: translateY(0);
transition: opacity 0.3s, transform 0.3s,
display 0.3s allow-discrete,
overlay 0.3s allow-discrete;
}
/* 初始状态 —— 元素首次出现时的样式 */
@starting-style {
dialog[open] {
opacity: 0;
transform: translateY(-20px);
}
}
/* 关闭状态 */
dialog:not([open]) {
opacity: 0;
transform: translateY(-20px);
}
/* Popover 进出动画 */
[popover] {
opacity: 1;
scale: 1;
transition: opacity 0.25s, scale 0.25s,
display 0.25s allow-discrete,
overlay 0.25s allow-discrete;
}
@starting-style {
[popover]:popover-open {
opacity: 0;
scale: 0.9;
}
}15. 滚动驱动动画(Scroll-Driven Animations)是什么?(2026重点)
纯CSS实现基于滚动位置的动画,无需JavaScript或第三方库。
/* 1. 页面滚动进度条 */
.progress-bar {
position: fixed;
top: 0;
left: 0;
height: 3px;
background: #667eea;
transform-origin: left;
animation: grow-progress linear;
animation-timeline: scroll(); /* 绑定到页面滚动 */
}
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* 2. 元素滚动进入视口时的淡入效果 */
.section {
view-timeline: --reveal block;
}
.fade-in {
animation: slide-up 1s ease both;
animation-timeline: --reveal;
animation-range: entry 0% cover 40%;
}
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 3. 横向滚动图片视差效果 */
.parallax-image {
animation: parallax linear;
animation-timeline: scroll(root);
}
@keyframes parallax {
from { transform: translateY(-50px); }
to { transform: translateY(50px); }
}16. Anchor Positioning(锚点定位)是什么?(2026重点)
CSS原生锚点定位,让Tooltip、下拉菜单等元素相对于触发器精准定位,无需JavaScript计算。
/* 触发器声明锚点 */
.trigger {
anchor-name: --btn;
}
/* tooltip定位到触发器下方 */
.tooltip {
position: absolute;
position-anchor: --btn;
inset-area: bottom;
margin-top: 0.5rem;
}
/* 带自动翻转的下拉菜单 */
.dropdown-menu {
position: absolute;
position-anchor: --btn;
inset-area: bottom span-right;
/* 如果下方空间不足,自动翻转到上方 */
position-try-fallbacks: flip-block;
}17. 自定义Select样式(appearance: base-select)(2026重点)
终于可以用纯CSS自定义原生 <select> 的样式,同时保留原生可访问性和键盘交互。
/* 开启可自定义模式 */
select,
select::picker(select) {
appearance: base-select;
}
/* 自定义下拉面板样式 */
select::picker(select) {
border-radius: 12px;
border: 1px solid #e0e0e0;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
padding: 0.5rem;
}
/* 选项样式 */
option {
padding: 0.75rem 1rem;
border-radius: 8px;
transition: background 0.2s;
}
option:hover {
background: #f0f0ff;
}
/* 配合 sibling-index() 实现交错动画 */
option {
transition: opacity 0.25s ease, translate 0.3s ease;
transition-delay: calc(0.05s * (sibling-index() - 1));
}
@starting-style {
option {
opacity: 0;
translate: 20px 0;
}
}响应式设计
18. 媒体查询的用法和最佳实践?
/* 移动优先:从小屏开始,逐步增强 */
.container {
padding: 1rem;
}
/* 平板 */
@media (min-width: 768px) {
.container {
padding: 2rem;
max-width: 720px;
margin: 0 auto;
}
}
/* 桌面 */
@media (min-width: 1024px) {
.container {
max-width: 960px;
}
}
/* 大屏 */
@media (min-width: 1280px) {
.container {
max-width: 1200px;
}
}
/* 偏好查询 */
@media (prefers-color-scheme: dark) {
:root { --bg: #1a1a2e; --text: #eee; }
}
@media (prefers-reduced-motion: reduce) {
* { animation-duration: 0.01ms !important; }
}
/* 高分辨率屏幕 */
@media (min-resolution: 2dppx) {
.logo { background-image: url('logo@2x.png'); }
}19. 新视口单位 dvh、svh、lvh 是什么?(2026重点)
解决移动端 100vh 被浏览器地址栏遮挡的经典问题。
/*
svh (Small Viewport Height) - 浏览器UI完全展开时的视口高度
lvh (Large Viewport Height) - 浏览器UI完全收起时的视口高度
dvh (Dynamic Viewport Height) - 动态跟随浏览器UI变化
*/
/* Hero区域 - 使用dvh */
.hero {
min-height: 100dvh; /* 动态适应地址栏显隐 */
display: grid;
place-items: center;
}
/* 固定底部按钮 - 使用svh确保始终可见 */
.bottom-bar {
position: fixed;
bottom: 0;
height: calc(100svh - 100dvh + 60px);
/* ... */
}
/* 兼容写法 */
.full-height {
min-height: 100vh; /* 回退 */
min-height: 100dvh; /* 现代浏览器 */
}20. 响应式字体和间距的最佳方案?
/* clamp() 实现流式响应 */
.title {
/* clamp(最小值, 首选值, 最大值) */
font-size: clamp(1.5rem, 4vw, 3rem);
}
.container {
padding: clamp(1rem, 3vw, 3rem);
gap: clamp(0.5rem, 2vw, 2rem);
}
/* 结合容器查询单位 */
.card-title {
font-size: clamp(1rem, 3cqw, 1.5rem);
}
/* 现代流式排版系统 */
:root {
--step-0: clamp(1rem, 0.5rem + 1vw, 1.25rem);
--step-1: clamp(1.25rem, 0.75rem + 1.5vw, 1.75rem);
--step-2: clamp(1.5rem, 1rem + 2vw, 2.5rem);
--step-3: clamp(2rem, 1.25rem + 3vw, 3.5rem);
--space-s: clamp(0.5rem, 0.25rem + 1vw, 1rem);
--space-m: clamp(1rem, 0.5rem + 2vw, 2rem);
--space-l: clamp(2rem, 1rem + 4vw, 4rem);
}
h1 { font-size: var(--step-3); }
h2 { font-size: var(--step-2); }
p { font-size: var(--step-0); }颜色与主题
21. 现代CSS颜色函数有哪些?(2026重点)
:root {
/* oklch - 感知均匀的颜色空间,2026推荐 */
--brand: oklch(0.72 0.18 250);
--brand-light: oklch(0.85 0.12 250);
--brand-dark: oklch(0.55 0.20 250);
}
/* color-mix() - 颜色混合 */
.card {
/* 将品牌色与白色按60%:40%混合 */
border-color: color-mix(in oklab, var(--brand) 60%, white);
}
.card:hover {
/* 相对颜色语法 - 降低亮度10% */
background: oklch(from var(--brand) calc(l - 0.1) c h / 0.12);
}
/* light-dark() - 根据color-scheme自动切换 */
:root {
color-scheme: light dark;
}
.button {
background: light-dark(#fff, #1a1a2e);
color: light-dark(#333, #eee);
border-color: light-dark(#ddd, #444);
}
/* 传统暗色模式对比 */
/* 旧写法:需要两套媒体查询 */
@media (prefers-color-scheme: dark) {
.button { background: #1a1a2e; color: #eee; }
}
/* 新写法:light-dark() 一行搞定 */22. CSS自定义属性(变量)的高级用法?
:root {
--color-primary: #667eea;
--color-secondary: #764ba2;
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 16px;
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* 组件级变量 + 回退值 */
.button {
--btn-bg: var(--color-primary);
--btn-radius: var(--radius-md);
background: var(--btn-bg);
border-radius: var(--btn-radius);
padding: var(--btn-padding, 0.5rem 1rem); /* 带回退 */
}
/* 变体通过覆盖变量实现 */
.button--danger {
--btn-bg: #e53e3e;
}
.button--rounded {
--btn-radius: 999px;
}
/* 在JavaScript中操作CSS变量 */// 读取
getComputedStyle(document.documentElement)
.getPropertyValue('--color-primary');
// 设置
document.documentElement.style
.setProperty('--color-primary', '#ff6b6b');动画与过渡
23. transition和animation的区别?
| 特性 | transition | animation |
|---|---|---|
| 触发方式 | 需状态变化触发 | 自动/自定义触发 |
| 关键帧 | 仅起始和结束 | 可定义多个 |
| 循环 | 不支持 | infinite |
| 方向 | 单方向(可回弹) | alternate 等 |
| 控制 | 简单 | 丰富 |
/* transition 示例 */
.btn {
background: #667eea;
transition: background 0.3s ease, transform 0.2s ease;
}
.btn:hover {
background: #5a67d8;
transform: translateY(-2px);
}
/* animation 示例 */
.loading-dot {
animation: bounce 1.4s ease-in-out infinite both;
}
.loading-dot:nth-child(1) { animation-delay: 0s; }
.loading-dot:nth-child(2) { animation-delay: 0.16s; }
.loading-dot:nth-child(3) { animation-delay: 0.32s; }
@keyframes bounce {
0%, 80%, 100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}24. View Transitions(视图过渡)API是什么?(2026重点)
实现页面/状态切换的平滑过渡动画,支持SPA和MPA。
/* 1. 基础视图过渡 */
::view-transition-old(root) {
animation: fade-out 0.3s ease;
}
::view-transition-new(root) {
animation: fade-in 0.3s ease;
}
@keyframes fade-out {
to { opacity: 0; }
}
@keyframes fade-in {
from { opacity: 0; }
}
/* 2. 命名视图过渡 - 特定元素过渡 */
.hero-image {
view-transition-name: hero;
}
::view-transition-group(hero) {
animation-duration: 0.5s;
}
/* 3. MPA跨页面过渡 */
@view-transition {
navigation: auto;
}// SPA中使用
document.startViewTransition(() => {
// 更新DOM
updateContent();
});25. sibling-index() 和 sibling-count() 是什么?(2026重点)
CSS树计数函数,获取元素在兄弟中的索引和总数,实现动态交错动画。
/* 交错动画 - 无需手动设置每个元素的延迟 */
.list-item {
opacity: 0;
animation: slide-in 0.3s ease forwards;
/* sibling-index() 返回元素在兄弟中的位置(1-based) */
animation-delay: calc(0.08s * (sibling-index() - 1));
}
@keyframes slide-in {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* 基于总数的自适应布局 */
.grid-item {
/* sibling-count() 返回兄弟元素总数 */
flex-basis: calc(100% / sibling-count());
}
/* 彩虹色列表 */
.color-item {
background: oklch(0.75 0.15 calc(360 / sibling-count() * sibling-index()));
}CSS工程化
26. Cascade Layers(级联层)@layer 是什么?(2026重点)
@layer 让开发者显式控制CSS的级联顺序,解决大型项目中的优先级冲突。
/* 1. 定义层级顺序(后面的层优先级更高) */
@layer reset, base, components, utilities;
/* 2. 在各层中编写样式 */
@layer reset {
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
}
@layer base {
body {
font-family: system-ui, sans-serif;
line-height: 1.6;
color: var(--text);
}
a { color: var(--link); }
}
@layer components {
.btn {
padding: 0.5rem 1rem;
border-radius: 8px;
background: var(--color-primary);
color: white;
}
.card {
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.5rem;
}
}
@layer utilities {
.sr-only { /* 屏幕阅读器专用 */ }
.text-center { text-align: center; }
.hidden { display: none; }
}
/* 无层级的样式优先级最高 */
.override { color: red; }27. @scope 是什么?
@scope 限制样式的作用范围,避免全局污染。
/* 样式只在 .card 内部生效 */
@scope (.card) {
h3 {
margin: 0 0 0.5rem;
font-size: 1.25rem;
}
p {
color: #666;
}
a {
color: #667eea;
}
}
/* 指定上下界 - 样式在 .card 内生效,但不影响 .card-footer 内的元素 */
@scope (.card) to (.card-footer) {
p {
font-size: 1rem;
line-height: 1.8;
}
}28. CSS变量 vs Sass变量 vs CSS-in-JS?
| 特性 | CSS变量 | Sass变量 | CSS-in-JS |
|---|---|---|---|
| 运行时 | ✅ 动态 | ❌ 编译时 | ✅ 动态 |
| 继承 | ✅ 级联继承 | ❌ | 取决于实现 |
| JS访问 | ✅ | ❌ | ✅ |
| 作用域 | 选择器作用域 | 块作用域 | 组件作用域 |
| 性能 | 高 | 高 | 中等 |
| 主题切换 | ✅ 原生支持 | 需多文件 | ✅ |
/* 2026推荐:CSS变量 + @layer 的组合 */
@layer tokens {
:root {
--color-primary: oklch(0.65 0.2 260);
--space-unit: 0.25rem;
--space-xs: calc(var(--space-unit) * 2);
--space-sm: calc(var(--space-unit) * 4);
--space-md: calc(var(--space-unit) * 8);
--space-lg: calc(var(--space-unit) * 16);
}
[data-theme="dark"] {
--color-primary: oklch(0.75 0.18 260);
}
}性能优化
29. 哪些CSS属性会触发重排(reflow)和重绘(repaint)?
重排(Reflow)→ 重绘(Repaint)→ 合成(Composite)
成本: 高 中 低| 操作 | 触发 | 示例属性 |
|---|---|---|
| 改变几何属性 | 重排+重绘 | width, height, margin, padding, top, left |
| 改变外观属性 | 重绘 | color, background, box-shadow, visibility |
| 合成层属性 | 仅合成 | transform, opacity, filter, will-change |
/* ❌ 差 - 触发重排 */
.animate-bad {
transition: left 0.3s, top 0.3s;
}
.animate-bad:hover {
left: 100px;
top: 50px;
}
/* ✅ 好 - 仅触发合成 */
.animate-good {
transition: transform 0.3s;
}
.animate-good:hover {
transform: translate(100px, 50px);
}
/* will-change 提示浏览器提前优化 */
.will-animate {
will-change: transform, opacity;
}
/* content-visibility 跳过屏幕外元素的渲染 */
.long-list-item {
content-visibility: auto;
contain-intrinsic-size: 0 80px; /* 预估高度 */
}30. contain 和 content-visibility 属性的作用?
/* contain - 限制元素的渲染影响范围 */
.widget {
contain: layout; /* 内部布局变化不影响外部 */
contain: paint; /* 内部绘制不溢出 */
contain: size; /* 不依赖子元素确定尺寸 */
contain: strict; /* 同时启用 layout + paint + size */
contain: content; /* 同时启用 layout + paint */
}
/* content-visibility - 跳过屏幕外内容的渲染 */
.below-fold {
content-visibility: auto; /* 不在视口中时跳过渲染 */
contain-intrinsic-size: auto 500px; /* 预估尺寸防止滚动条跳动 */
}
/* 实际应用:长列表优化 */
.list-section {
content-visibility: auto;
contain-intrinsic-size: auto 200px;
}31. 如何优化CSS加载性能?
<!-- 1. 关键CSS内联 -->
<style>
/* 首屏必要样式 */
.hero { display: grid; place-items: center; min-height: 100dvh; }
</style>
<!-- 2. 非关键CSS异步加载 -->
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="non-critical.css"></noscript>
<!-- 3. 预加载关键CSS -->
<link rel="preload" href="critical.css" as="style">/* 4. 避免使用 @import(阻塞渲染) */
/* ❌ */ @import url('other.css');
/* ✅ 使用 <link> 标签替代 */
/* 5. 使用 CSS @layer 组织代码,减少优先级冲突 */
@layer base, components, utilities;
/* 6. 合理使用 font-display */
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2');
font-display: swap; /* 先显示系统字体,加载后切换 */
}
/* 7. 使用 CSS containment 减少渲染开销 */
.card {
contain: content;
}进阶深入
32. @property 注册自定义属性是什么?
@property 让CSS变量拥有类型检查、默认值和继承控制,是 CSS Houdini 的一部分。
/* 注册一个有类型的自定义属性 */
@property --progress {
syntax: '<percentage>';
inherits: false;
initial-value: 0%;
}
/* 核心用途:让自定义属性可以被动画! */
.progress-bar {
--progress: 0%;
background: linear-gradient(to right, #4caf50 var(--progress), #eee var(--progress));
transition: --progress 0.5s ease;
}
.progress-bar:hover {
--progress: 80%;
/* ✅ 渐变现在可以平滑过渡了! */
/* 没有 @property 注册,transition 对自定义属性无效 */
}
/* 实现颜色循环动画 */
@property --hue {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
.rainbow {
--hue: 0deg;
background: hsl(var(--hue), 80%, 60%);
animation: hue-cycle 3s linear infinite;
}
@keyframes hue-cycle {
to { --hue: 360deg; }
}
/* 实现数字计数器动画 */
@property --num {
syntax: '<integer>';
inherits: false;
initial-value: 0;
}
.counter {
--num: 0;
animation: count-up 2s ease forwards;
counter-reset: num var(--num);
}
.counter::after {
content: counter(num);
}
@keyframes count-up {
to { --num: 100; }
}@property syntax 支持的类型:
<length>,<percentage>,<number>,<integer><color>,<angle>,<time><image>,<url>,<transform-function><custom-ident>,*(任意值)
33. CSS逻辑属性是什么?为什么重要?
逻辑属性用书写方向无关的方式替代物理方向属性(top/right/bottom/left),对国际化(i18n) 至关重要。
/* 物理属性 → 逻辑属性 */
/* 水平方向(inline轴) */
margin-left → margin-inline-start
margin-right → margin-inline-end
padding-left → padding-inline-start
padding-right → padding-inline-end
width → inline-size
/* 垂直方向(block轴) */
margin-top → margin-block-start
margin-bottom → margin-block-end
height → block-size
/* 简写 */
margin-inline: 0 auto; /* 等价于 margin-left: 0; margin-right: auto; */
padding-block: 16px 24px; /* 等价于 padding-top: 16px; padding-bottom: 24px; */
inset-inline: 0; /* 等价于 left: 0; right: 0; */
/* 边框和圆角 */
border-inline-start: 2px solid red; /* 在LTR中是左边框,RTL中是右边框 */
border-start-start-radius: 8px; /* LTR中是左上角 */
/* 实际应用:RTL自适应布局 */
.sidebar {
inline-size: 280px; /* 宽度 */
padding-inline: 16px; /* 左右内边距 */
border-inline-end: 1px solid #ddd; /* 分隔线 */
margin-inline-start: auto; /* 自动靠一边 */
}
/* 在 dir="rtl" 下,所有方向自动镜像,无需额外CSS */34. CSS架构方法论有哪些?怎么选?
/* 1. BEM(Block Element Modifier) */
/* 命名规范:block__element--modifier */
.card { }
.card__title { }
.card__image { }
.card__button--primary { }
.card__button--disabled { }
/* 优点:清晰、无嵌套冲突、可维护性好 */
/* 缺点:类名较长 */
/* 2. Utility-First(Tailwind CSS 风格) */
/* <div class="flex items-center gap-4 p-6 bg-white rounded-lg shadow-md"> */
/* 3. CSS Modules */
/* 自动生成唯一类名,天然隔离 */
/* .title → .Title_title__3xk2a */
/* 4. CSS-in-JS(styled-components / Emotion) */
/* 与组件绑定,动态样式,自动作用域 */
/* 5. 2026推荐:@layer + CSS变量 + 原生嵌套 */
@layer base, components, utilities;
@layer base {
:root {
--color-primary: oklch(65% 0.25 260);
--radius: 8px;
--spacing: 16px;
}
}
@layer components {
.card {
border-radius: var(--radius);
padding: var(--spacing);
& .title {
font-size: 1.25rem;
font-weight: 600;
}
&:hover {
box-shadow: 0 4px 12px oklch(0% 0 0 / 10%);
}
}
}| 方案 | 适用场景 | 隔离性 | 工具依赖 |
|---|---|---|---|
| BEM | 传统项目、多人协作 | 约定式 | 无 |
| CSS Modules | React/Vue组件化项目 | 编译隔离 | 构建工具 |
| Tailwind | 快速开发、设计系统 | 原子类 | PostCSS |
| CSS-in-JS | React动态样式 | 运行时隔离 | JS库 |
| @layer + Nesting | 2026现代项目 | 原生级联控制 | 无 |
35. text-wrap: balance 和 pretty 是什么?
/* text-wrap: balance - 让标题文本行宽更均匀 */
h1, h2, h3 {
text-wrap: balance;
/* 之前: "这是一个非常长的标题"
第一行:这是一个非常长的标
第二行:题
之后 balance:
第一行:这是一个非常
第二行:长的标题 ← 行宽更均匀 */
}
/* text-wrap: pretty - 避免段落末尾出现孤字(orphans) */
p {
text-wrap: pretty;
/* 浏览器会调整换行位置,避免最后一行只有一个字 */
}
/* white-space-collapse: 控制空白处理 */
pre {
white-space-collapse: preserve; /* 保留空白 */
}
.normalize {
white-space-collapse: collapse; /* 折叠连续空白 */
}36. 如何实现瀑布流布局?(Masonry Layout)
/* 方法1: CSS Grid Masonry(实验性,2026+ Firefox已支持) */
.masonry-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: masonry; /* ✨ 原生瀑布流 */
gap: 16px;
}
/* 方法2: CSS columns(现已广泛支持) */
.masonry-columns {
columns: 3 240px;
column-gap: 16px;
}
.masonry-columns .item {
break-inside: avoid;
margin-bottom: 16px;
}
/* 方法3: Flexbox 模拟(竖向排列) */
.masonry-flex {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 800px; /* 需要固定高度 */
gap: 16px;
}37. CSS自定义高亮(Custom Highlight API)是什么?
// 创建自定义高亮 - 替代传统的包裹<span>方案
const text = document.querySelector('p').firstChild;
// 创建Range
const range = new Range();
range.setStart(text, 5);
range.setEnd(text, 10);
// 注册高亮
const highlight = new Highlight(range);
CSS.highlights.set('search-result', highlight);/* 用CSS设置高亮样式 */
::highlight(search-result) {
background-color: #ffeb3b;
color: #000;
}
/* 多种高亮可共存 */
::highlight(spell-error) {
text-decoration: wavy underline red;
}
::highlight(grammar-error) {
text-decoration: wavy underline blue;
}优势: 不修改DOM结构、性能好、支持大量高亮、不破坏事件绑定。
38. CSS field-sizing 属性是什么?(2026新特性)
/* 让表单元素自动根据内容调整尺寸 */
textarea, input, select {
field-sizing: content;
/* textarea 会随输入内容自动增长高度
input 会随文本宽度自动扩展
select 会适配最长选项的宽度 */
}
/* 配合 min/max 使用 */
textarea {
field-sizing: content;
min-block-size: 3lh; /* 最小3行高 */
max-block-size: 10lh; /* 最大10行高 */
}总结
2026年CSS面试重点:
- ✅ 盒模型与BFC - 经典必考,理解触发条件和应用场景
- ✅ Flexbox & Grid & Subgrid - 布局三件套,Subgrid是新热点
- ✅ :has() 选择器 - CSS最受欢迎的新特性,使用率最高
- ✅ 容器查询 - 组件级响应式设计,替代部分媒体查询场景
- ✅ CSS原生嵌套 - 告别Sass嵌套依赖
- ✅ 滚动驱动动画 - 纯CSS实现滚动动效
- ✅ @starting-style - 解决 display 动画难题
- ✅ @layer 级联层 - 大型项目CSS架构必备
- ✅ 现代颜色函数 - oklch、color-mix()、light-dark()
- ✅ 性能优化 - content-visibility、contain、合成层动画
学习建议:
- 经典布局(盒模型、BFC、Flex、Grid)仍是面试基础,必须扎实
- 重点掌握 :has()、容器查询、CSS嵌套等已全面支持的新特性
- 了解 @starting-style、滚动驱动动画、Anchor Positioning 等前沿特性
- 关注 CSS 工程化趋势:@layer + CSS变量 + 原生嵌套的组合