css面试题2
伪类和伪元素
伪类(Pseudo-classes)和伪元素(Pseudo-elements)是 CSS 中两个容易混淆但本质不同的概念。它们都以冒号开头,但用途、语义和行为完全不同。
一、核心区别一句话总结
- 伪类(Pseudo-class):描述元素的某种状态或位置(如
:hover、:first-child)- 伪元素(Pseudo-element):创建一个不存在于 HTML 中的虚拟元素(如
::before、::first-line)
二、伪类(Pseudo-classes)
✅ 是什么?
- 用于选中处于特定状态或特定位置的元素
- 不创建新元素,只是对现有元素的“状态”或“关系”进行样式控制
🔹 常见类型与示例:
| 类别 | 伪类 | 说明 |
|---|---|---|
| 用户交互 | :hover、:focus、:active | 鼠标悬停、获得焦点、激活 |
| 表单状态 | :valid、:invalid、:checked | 表单验证状态 |
| 结构位置 | :first-child、:nth-of-type(2)、:last-child | 元素在父级中的位置 |
| 语言/方向 | :lang(zh)、:dir(rtl) | 语言或文本方向匹配 |
| 否定 | :not(.disabled) | 排除某些元素 |
📝 示例:
/* 鼠标悬停时变色 */
button:hover { color: red; }/* 第一个 li 元素加粗 */
li:first-child { font-weight: bold; }/* 未被选中的复选框 */
input[type="checkbox"]:not(:checked) { opacity: 0.5; }
✅ 关键:伪类不会增加 DOM 节点,只是“条件选择器”。
三、伪元素(Pseudo-elements)
✅ 是什么?
- 用于在现有元素的前后或内部插入虚拟内容或样式
- 创建一个“假”的 DOM 节点(虽然不在 HTML 中,但可被 CSS 和 JS 操作)
🔹 常见伪元素:
| 伪元素 | 说明 | 必须设置 content? |
|---|---|---|
::before | 在元素内容前插入 | ✅ 是(即使为空 "") |
::after | 在元素内容后插入 | ✅ 是 |
::first-line | 选中块级元素的第一行文本 | ❌ 否 |
::first-letter | 选中块级元素的首字母 | ❌ 否 |
::selection | 选中用户高亮的文本 | ❌ 否 |
::placeholder | 表单占位符文本 | ❌ 否 |
📝 示例:
/* 在链接前加图标 */
a::before {content: "🔗 ";
}/* 清除浮动(经典 clearfix) */
.clearfix::after {content: "";display: table;clear: both;
}/* 首字母大写并放大 */
p::first-letter {font-size: 2em;font-weight: bold;
}/* 自定义选中文本样式 */
::selection {background: gold;color: black;
}
✅ 关键:
::before/::after必须有content属性(哪怕为空)才能显示- 伪元素可以设置宽高、定位、动画等,就像真实元素一样
四、语法规范:单冒号 vs 双冒号
| 类型 | CSS2 写法 | CSS3+ 写法 | 推荐 |
|---|---|---|---|
| 伪类 | :hover | :hover | 单冒号 |
| 伪元素 | :before | ::before | 双冒号 |
💡 CSS3 引入双冒号是为了明确区分伪类和伪元素,避免混淆。
五、如何记忆?
| 特征 | 伪类 | 伪元素 |
|---|---|---|
| 是否创建新内容 | ❌ 否 | ✅ 是(虚拟元素) |
是否需要 content | ❌ 否 | ✅ ::before/::after 需要 |
| 冒号数量 | 单 : | 双 ::(现代规范) |
| 类比 | “元素的状态” | “元素的附属部分” |
六、常见误区
-
::before不是“在元素前面插入兄弟元素”
→ 它是在该元素的子内容最前面插入,属于该元素内部。 -
伪类可以叠加使用
a:hover:focus { color: blue; } /* 同时满足 hover 和 focus */ -
伪元素不能被 JavaScript 直接选中
→ 但可通过getComputedStyle读取其样式。
单行文本的溢出隐藏
在CSS中,实现文本溢出隐藏(无论是单行还是多行)通常使用text-overflow属性。这个属性必须配合其他一些CSS属性来共同完成效果,下面是具体的实现方法:
单行文本溢出隐藏
对于单行文本溢出隐藏,你可以使用以下CSS代码:
.single-line {white-space: nowrap; /* 防止文本换行 */overflow: hidden; /* 溢出内容隐藏 */text-overflow: ellipsis; /* 当文本溢出时显示省略号 */
}
这里的关键点在于:
white-space: nowrap;确保文本不会换行。overflow: hidden;隐藏超出容器宽度的内容。text-overflow: ellipsis;用省略号代替被隐藏的文本。
媒体查询@media
媒体查询(Media Queries)是 CSS 中用于实现响应式设计(Responsive Design)的核心机制。它的本质是:根据设备或视口的特定条件(如宽度、高度、分辨率、方向等),有条件地应用一组 CSS 样式。
一、核心作用一句话总结:
“在不同设备/屏幕尺寸下,展示最适合的样式。”
二、基本语法
@media [媒体类型] and (媒体特性) {/* 当条件满足时,应用这些样式 */
}
1. 媒体类型(Media Type,可省略)
all(默认):所有设备screen:彩色屏幕设备(最常用)print:打印预览或打印页面speech:语音合成器
✅ 现代开发中通常省略类型,直接写特性。
2. 媒体特性(Media Features)
最常用的是视口尺寸:
min-width:视口最小宽度max-width:视口最大宽度min-height/max-heightorientation:portrait(竖屏) /landscape(横屏)resolution:设备分辨率(如@media (min-resolution: 2dppx)用于 Retina 屏)
三、经典用法示例
移动优先(Mobile First)—— 推荐写法
/* 默认:手机样式 */
.card { padding: 10px; }/* 平板及以上 */
@media (min-width: 768px) {.card { padding: 16px; }
}/* 桌面及以上 */
@media (min-width: 1024px) {.card { padding: 24px; }
}
✨ 优势:代码简洁,性能更好(移动端无需下载大屏样式)
桌面优先(Desktop First)
/* 默认:桌面样式 */
.container { width: 1200px; }/* 平板及以下 */
@media (max-width: 1023px) {.container { width: 100%; }
}/* 手机 */
@media (max-width: 767px) {.container { padding: 0 16px; }
}
四、关键注意事项
1. 断点(Breakpoints)设计原则
-
不要盲目套用 Bootstrap 断点
-
根据内容需求而非设备尺寸设断点:
/* 当卡片布局开始拥挤时调整 */ @media (min-width: 650px) { ... }
2. 避免过度嵌套
// ❌ 反例:每个组件都写媒体查询 → 难维护
.card {@media (max-width: 768px) { ... }
}
.button {@media (max-width: 768px) { ... }
}// ✅ 推荐:集中管理断点(用 CSS 自定义属性或预处理器)
:root {--breakpoint-tablet: 768px;
}
@media (min-width: var(--breakpoint-tablet)) { ... }
五、现代增强:容器查询(Container Queries)
💡 未来趋势:媒体查询是“全局响应”,而容器查询(
@container)是“局部响应”。
/* 当父容器宽度 > 400px 时生效 */
.card {container-type: inline-size;
}
@container (min-width: 400px) {.card-title { font-size: 1.5em; }
}
✅ 解决“组件在不同位置需要不同样式”的痛点(媒体查询做不到)
六、性能提示
-
媒体查询不会阻塞渲染
-
但过多断点会增加 CSS 文件体积 → 按需使用
-
使用
prefers-reduced-motion尊重用户偏好:
@media (prefers-reduced-motion: reduce) {* { animation-duration: 0.01ms !important; } }
CSS工程化
CSS 工程化(CSS Engineering)是指将工程化思想和工具链引入 CSS 开发流程,解决传统 CSS 在大型项目中面临的可维护性差、复用性低、协作困难、性能瓶颈等问题。其核心目标是:让 CSS 像 JavaScript 一样可模块化、可测试、可构建、可协作。
一、为什么需要 CSS 工程化?
传统 CSS 的痛点:
- 全局作用域 → 样式冲突(“改一处,崩全局”)
- 无逻辑能力 → 重复代码多(颜色、间距硬编码)
- 无模块化 → 难以复用和拆分
- 无依赖管理 → 文件引入顺序敏感
- 无构建优化 → 无法压缩、兼容、拆分
💡 CSS 工程化就是为了解决这些问题而生的。
二、CSS 工程化的核心实践
1. 模块化与作用域隔离
-
CSS Modules(推荐)
通过构建工具(Webpack/Vite)将 CSS 类名哈希化,实现局部作用域:/* button.module.css */ .primary { background: blue; }import styles from './button.module.css'; <button className={styles.primary}>Click</button>→ 编译后:
<button class="primary_a1b2c3">Click</button> -
CSS-in-JS(如 styled-components, Emotion)
将 CSS 写在 JS 中,天然具备作用域隔离和动态能力:const Button = styled.button`background: ${props => props.primary ? 'blue' : 'gray'}; `; -
Scoped CSS(Vue SFC)
Vue 单文件组件自动为样式添加data-v-xxx属性选择器。
✅ 效果:彻底解决样式冲突,组件真正独立。
2. 预处理器 + 后处理器增强能力
-
预处理器(Sass/Less):变量、嵌套、Mixin、函数 → 提升开发效率
-
后处理器
(PostCSS):
- Autoprefixer:自动加浏览器前缀
- cssnano:压缩 CSS
- postcss-preset-env:使用未来 CSS 语法
✅ 效果:写得更快、兼容更好、体积更小。
3. 设计系统与原子化思想
-
设计 Token:用 CSS 变量统一管理设计语义
:root {--color-primary: #007bff;--space-md: 16px;--radius-sm: 4px; } .button { padding: var(--space-md); border-radius: var(--radius-sm); } -
原子化 CSS(如 Tailwind CSS)
通过工具类组合样式,避免手写 CSS:<button class="px-4 py-2 bg-blue-500 rounded hover:bg-blue-600">Click </button>→ 优势:极致复用、无命名烦恼、体积可控(配合 PurgeCSS)
✅ 效果:团队设计语言统一,开发速度飙升。
4. 构建与性能优化
- 代码分割:按路由/组件拆分 CSS(Webpack
splitChunks) - 关键 CSS 内联:首屏样式直出,避免 FOUC
- Tree Shaking:移除未使用样式(PurgeCSS / UnCSS)
- 资源内联/外链策略:小图标转 Data URI,大资源走 CDN
✅ 效果:加载更快、首屏渲染更早。
5. 质量保障
- Linting:Stylelint 统一代码风格,禁止低效选择器
- 类型检查:TypeScript + CSS Modules 提供类名智能提示
- 视觉回归测试:用 Percy / Chromatic 检测 UI 意外变更
✅ 效果:减少低级错误,保障 UI 一致性。
三、现代 CSS 工程化架构示例
src/
├── styles/
│ ├── tokens/ # 设计 Token(CSS 变量)
│ ├── base/ # 重置样式、全局基础
│ └── components/ # 组件样式(CSS Modules)
├── components/
│ └── Button/
│ ├── Button.tsx
│ └── Button.module.css # 局部作用域
public/
└── critical.css # 构建生成的关键 CSS
构建流程:
Sass → PostCSS(Autoprefixer + cssnano)→ CSS Modules → 代码分割 + PurgeCSS → 输出优化 CSS
四、CSS 工程化的演进趋势
| 阶段 | 特点 | 工具 |
|---|---|---|
| 原始 CSS | 全局污染、无逻辑 | 原生 CSS |
| 预处理时代 | 变量/嵌套提升效率 | Sass, Less |
| 模块化时代 | 作用域隔离 | CSS Modules, Scoped CSS |
| 原子化时代 | 工具类 + 设计系统 | Tailwind CSS |
| 未来 | 容器查询 + CSS Houdini | @container, @property |
💡 没有银弹:
- 中后台项目 → CSS Modules + 设计 Token
- 快速原型/营销页 → Tailwind CSS
- 复杂动态主题 → CSS-in-JS
Z-index属性在什么情况下会失效
z-index 是 CSS 中控制元素层叠顺序(stacking order)的重要属性,但它并不是在所有情况下都生效。以下是 z-index 失效或不按预期工作的常见原因和场景,附带原理说明和解决方案:
✅ 前提:z-index 生效的基本条件
z-index 只对定位元素(positioned elements):
position: relativeposition: absoluteposition: fixedposition: sticky
❌ 如果元素是
position: static(默认值),设置z-index完全无效!
一、常见失效场景及原因
1️⃣ 父级元素创建了新的层叠上下文(Stacking Context)
这是最常见也最容易被忽视的原因!
📌 问题现象:
- 子元素 A 的
z-index: 9999 - 子元素 B 的
z-index: 1 - 但 A 仍然被 B 的父容器盖住
🔍 原因:
当父元素满足以下任一条件时,会创建新的层叠上下文,其内部所有子元素的 z-index 只在该上下文内有效,无法突破父级的层级限制:
| 触发新层叠上下文的 CSS 属性 |
|---|
opacity < 1(如 opacity: 0.9) |
transform(如 translate, scale) |
filter(如 blur, grayscale) |
will-change(值包含 transform/opacity 等) |
position: fixed / sticky(本身就会创建) |
isolation: isolate(显式创建) |
z-index 值不是 auto(且元素已定位) |
💡 示例:
<div class="parent" style="transform: translateX(0); z-index: 1"><div class="child" style="position: relative; z-index: 9999">我应该在最上层?</div>
</div><div class="other" style="position: relative; z-index: 2">我盖住你了!</div>
→ 尽管 .child 的 z-index 很高,但因为 .parent 有 transform,创建了新层叠上下文,整个 .parent 的层级只有 1,所以被 z-index: 2 的 .other 盖住。
✅ 解决方案:
- 避免不必要的层叠上下文:检查父级是否有
transform/opacity等 - 提升父级的
z-index:让整个容器层级变高 - 重构 DOM 结构:将需要高
z-index的元素移到更高层级的容器中
2️⃣ 元素未脱离文档流(未设置定位)
.box {z-index: 999; /* ❌ 无效!因为 position 是 static */
}
✅ 修复:
.box {position: relative; /* 或 absolute/fixed */z-index: 999;
}
3️⃣ z-index 值为负数,但父容器裁剪了内容
.parent {overflow: hidden; /* 裁剪子元素 */
}
.child {position: relative;z-index: -1; /* 跑到父容器后面,但被裁剪看不见 */
}
✅ 注意:负 z-index 会让元素位于父容器背景之下,如果父容器有背景色或 overflow: hidden,可能完全看不到。
4️⃣ Flex / Grid 容器中的子项
在 Flex 或 Grid 容器中,即使子元素未定位,z-index 也可能生效(这是规范行为),但容易和层叠上下文混淆。
⚠️ 但如果你期望它“突破”父容器层级,同样会受层叠上下文限制。
5️⃣ 浏览器渲染 bug 或极端值
- 某些旧版浏览器对超大
z-index(如999999999999)处理异常 - 不同浏览器对层叠顺序的实现略有差异(罕见)
✅ 建议:使用合理数值(如 1~1000),避免滥用 999999
二、如何调试 z-index 问题?
Chrome DevTools
- 打开 Elements 面板
- 选中元素 → 右侧面板 “Computed”
- 查看 “Rendered Styles” 中的
z-index - 注意是否有 “Creates a new stacking context”
三、最佳实践建议
| 建议 | 说明 |
|---|---|
避免滥用高 z-index | 用合理的层级规划(如 header: 10, modal: 100, tooltip: 1000) |
慎用 transform/opacity 在需要高 z-index 的父级上 | 它们会意外创建层叠上下文 |
使用 isolation: isolate 显式控制上下文 | 避免隐式创建导致混乱 |
| 优先用 DOM 顺序控制层级 | 同一层级下,后写的元素默认在上层(z-index: auto 时) |
✅ 总结:z-index 失效的核心原因
“
z-index只在同一个层叠上下文内比较;一旦父级创建了新的上下文,子元素就无法突破父级的层级限制。”
记住这个原则,90% 的 z-index 问题都能迎刃而解!
css3中transform拥有的属性
在CSS3中,transform 属性允许你对元素进行旋转、缩放、移动或倾斜等变换。以下是一些常用的 transform 函数:
- translate(x, y):移动元素。x 和 y 分别代表水平和垂直方向上的位移量。可以使用 translateX() 或 translateY() 单独指定方向。
- rotate(angle):旋转元素。angle 参数表示旋转的角度,正数表示顺时针方向,负数表示逆时针方向。
- scale(x, y):缩放元素。x 和 y 分别代表宽度和高度的缩放比例。如果只提供一个参数,则宽度和高度都将按该比例缩放。也可以单独使用 scaleX() 或 scaleY() 来分别指定宽高的缩放比例。
- skew(x-angle, y-angle):倾斜元素。x-angle 和 y-angle 分别代表水平和垂直方向上的倾斜角度。同样地,可以使用 skewX() 或 skewY() 单独指定方向。
- matrix(a, b, c, d, e, f):以一个六参数的矩阵形式定义二维转换,提供了所有上述函数的功能。这是一种较为底层的方式,通常不需要直接使用,除非你需要精确控制转换效果。
px em rem的区别及使用场景
一、核心区别速览表
| 单位 | 全称 | 相对于谁? | 是否继承? | 是否可缩放? | 典型用途 |
|---|---|---|---|---|---|
px | pixels(像素) | 屏幕物理像素(CSS 像素) | 否 | ❌ 用户缩放时固定 | 边框、图标、固定间距 |
em | — | 当前元素的 font-size | ✅ 会继承并复合 | ✅ | 组件内间距、弹性缩放 |
rem | root em | 根元素(<html>) | 否(始终基于根) | ✅ | 布局尺寸、全局间距 |
二、详细解析 + 示例
1. px —— 绝对单位(但其实是相对 CSS 像素)
- 1px = 1 个 CSS 像素(不是物理像素!由浏览器根据设备 DPR 换算)
- 固定不变:用户放大浏览器时,
px尺寸不会变大(可能影响无障碍访问)
.border { border: 1px solid #ccc; } /* 边框必须固定 */
.icon { width: 24px; height: 24px; } /* 图标尺寸固定 */
.gap { margin: 8px 0; } /* 微小固定间距 */
⚠️ 注意:
- 不要用
px定义字体大小(不利于用户调整阅读体验)- 现代浏览器对
px的缩放支持已改善,但rem/em仍是更优选择
2. em —— 相对于当前元素字体大小
1em = 当前元素的 font-size 值- 会继承并复合:嵌套时容易“放大再放大”
🌰 示例:
<div class="parent">Parent<div class="child">Child</div>
</div>
html { font-size: 16px; }
.parent {font-size: 2em; /* = 32px (16 * 2) */padding: 1em; /* = 32px (相对于自身 font-size) */
}
.child {margin: 1em; /* = 32px (继承 parent 的 font-size) */
}
✅ 使用场景:
-
组件内部比例(如按钮 padding 相对于文字大小):
.btn {font-size: 1.2rem;padding: 0.5em 1em; /* 文字越大,padding 自动变大 */ } -
图标与文字对齐:
.icon { width: 1em; height: 1em; } /* 和当前文字同高 */
❌ 避坑:
- 避免深层嵌套使用
em(尺寸会失控) - 不要用
em定义容器宽高(容易受字体影响)
3. rem —— 相对于根元素字体大小
1rem = <html> 元素的 font-size- 不会复合:无论嵌套多深,始终基于根字体
html { font-size: 16px; }
.box {width: 20rem; /* = 320px (16 * 20) */margin: 2rem; /* = 32px */
}
.nested {font-size: 1.5rem; /* = 24px,不受父级影响 */
}
✅ 使用场景(强烈推荐!):
-
全局布局尺寸:
.container { max-width: 75rem; } /* = 1200px */ .section { padding: 3rem 1.5rem; } -
响应式缩放:通过修改根字体实现全局缩放
/* 移动端缩小整体尺寸 */ @media (max-width: 768px) {html { font-size: 14px; } /* 所有 rem 元素自动缩小 */ } -
无障碍友好:用户在浏览器设置更大默认字体时,
rem会自动适配
三、黄金组合:rem + em + px
/* 全局基准 */
html { font-size: 16px; }/* 布局用 rem */
.container { padding: 2rem; max-width: 60rem;
}/* 组件内部用 em */
.btn {font-size: 1.125rem; /* = 18px */padding: 0.75em 1.5em; /* = 13.5px 27px */border: 1px solid; /* 固定边框用 px */
}/* 图标用 em 或 px */
.icon {width: 1em; /* 与文字同高 */height: 1em;margin-right: 0.5em; /* 与文字比例协调 */
}
四、常见误区
| 误区 | 正确理解 |
|---|---|
“em 是相对于父元素字体” | ❌ 是当前元素的字体(但会继承父级的字体值) |
“rem 在所有浏览器表现一致” | ⚠️ IE8 不支持(但现代项目可忽略) |
“px 完全不能缩放” | ⚠️ 现代浏览器会整体缩放页面(包括 px),但用户设置的字体偏好不会影响 px |
✅ 终极口诀:
“布局用 rem,组件用 em,边框图标用 px。”
“字体大小优先 rem,内部间距交给 em。”
说说响应式设计的概念及其理论
响应式设计(Responsive Web Design,简称 RWD)是一种让网页在不同设备、不同屏幕尺寸上都能良好显示和交互的前端开发方法论。其核心目标是:“一次开发,多端适配”,无需为手机、平板、桌面等设备分别开发独立版本。
一、响应式设计的三大核心概念(由 Ethan Marcotte 于 2010 年提出)
-
使用相对单位(如
%、rem、vw)代替固定单位(如px)定义布局。 -
容器宽度随视口缩放,列数/间距自动调整。
.container {width: 90%; /* 而不是 width: 1200px */max-width: 1200px; } -
图片/视频等媒体元素不超出容器,自动缩放。
img, video {max-width: 100%;height: auto; /* 保持宽高比 */ } -
根据设备特性(如屏幕宽度)有条件地应用 CSS。
/* 手机默认样式 */ .card { padding: 10px; }/* 平板及以上 */ @media (min-width: 768px) {.card { padding: 20px; } }
✅ 这三者结合,构成了响应式设计的“铁三角”。
二、响应式设计的基本原理
1. 视口(Viewport)
-
移动端浏览器默认会将页面渲染在一个虚拟视口(通常 980px 宽)上,导致页面缩小显示。
-
解决方案:通过
<meta>标签控制视口:<meta name="viewport" content="width=device-width, initial-scale=1">width=device-width:视口宽度 = 设备屏幕宽度initial-scale=1:初始缩放比例为 1
2. 断点(Breakpoints)
-
在特定屏幕宽度“断点”处改变布局(如 768px、1024px)。
-
最佳实践:基于内容设断点,而非设备尺寸:
/* 当卡片开始拥挤时调整 */ @media (min-width: 650px) { ... }
3. 移动优先(Mobile-First)
-
先写手机样式,再用
min-width逐步增强大屏体验:/* 默认:手机 */ .nav { display: none; }/* 平板+ */ @media (min-width: 768px) {.nav { display: block; } }- 优势:代码更简洁、性能更好(移动端无需加载大屏样式)
三、响应式设计的关键技术
| 技术 | 作用 | 示例 |
|---|---|---|
| CSS Grid / Flexbox | 创建弹性布局 | display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); |
| 媒体查询 | 条件化样式 | @media (max-width: 767px) { ... } |
| 相对单位 | 尺寸自适应 | font-size: 1.2rem; width: 80vw; |
| 图片响应式 | 媒体适配 | <img src="image.jpg" srcset="image-480w.jpg 480w, image-800w.jpg 800w"> |
| 容器查询(新) | 组件级响应 | @container (min-width: 400px) { ... } |
四、响应式 vs 自适应 vs 移动端独立站
| 类型 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 响应式(RWD) | 同一套代码,动态适配 | 开发维护成本低 | 复杂布局可能性能差 |
| 自适应(Adaptive) | 多套固定布局,服务端判断设备返回对应版本 | 精准控制体验 | 开发成本高 |
| 独立移动站(m.) | 完全独立的移动端网站(如 m.example.com) | 极致轻量化 | 需维护两套系统 |
✅ 现代主流选择:响应式设计(配合 PWA 可接近原生体验)
五、响应式设计的挑战与解决方案
| 挑战 | 解决方案 |
|---|---|
| 图片加载慢 | 使用 srcset + picture 按需加载 |
| 触摸 vs 鼠标交互 | 用 @media (hover: hover) 区分设备 |
| 字体可读性 | 用 clamp() 实现流体排版: font-size: clamp(1rem, 2.5vw, 1.5rem); |
| 复杂组件适配 | 用 容器查询(Container Queries)实现组件级响应 |
✅ 总结:响应式设计的本质
“不是适配设备,而是适配内容。”
它通过 流体布局 + 弹性媒体 + 媒体查询 的组合,让网页像水一样自然填充任何容器,最终实现:
- 用户体验一致(无论设备)
- 开发维护高效(一套代码)
- 未来兼容性强(新设备自动适配)
说说网页的层叠顺序
网页元素的层叠顺序(stacking order)是指当多个 HTML 元素在页面上发生重叠时,浏览器决定哪个元素显示在上层、哪个在下层的规则。这个顺序由 层叠上下文(stacking context)和 z-index 属性共同决定。
一、基本层叠顺序(默认规则)
在没有创建新的层叠上下文、也没有设置 z-index 的情况下,浏览器按照以下顺序(从底到顶)渲染元素:
- 根元素的背景和边框(即
<html>元素) - 普通流中的块级元素(按 HTML 代码出现顺序)
- 浮动元素(float)
- 普通流中的内联元素
- 定位元素(position 为
relative、absolute、fixed或sticky),且 z-index 为 auto 或 0,按 HTML 顺序
注意:此时即使设置了
position,只要z-index是auto或0,它们仍然按文档流顺序堆叠。
二、z-index 与层叠上下文
1. z-index 的作用前提
- 只对定位元素(即
position不是static的元素)生效。 z-index值越大,越靠上;可为负数(负值会低于普通流内容)。
2. 层叠上下文(Stacking Context)
层叠上下文是一个包含一组元素的“容器”,其内部的层叠顺序不会影响外部,外部也无法插入到其内部。
创建层叠上下文的常见方式:
- 根元素(
<html>) position为relative/absolute/fixed/sticky且z-index值不为autoopacity< 1transform不为nonefilter不为nonewill-change指定了相关属性isolation: isolate- Flex 或 Grid 容器的子项(如果
z-index不为auto)
一旦创建了新的层叠上下文,其内部所有元素的
z-index只在该上下文内有效。
三、完整层叠顺序(在一个层叠上下文中)
在一个层叠上下文中,元素从底到顶的渲染顺序为:
- 背景和边框(该上下文的根元素)
- z-index < 0 的定位子元素(按 z-index 从小到大)
- 非定位的普通流块级元素
- 非定位的浮动元素
- 非定位的内联元素
- z-index: auto 或 0 的定位元素(按 HTML 顺序)
- z-index > 0 的定位元素(按 z-index 从小到大)
四、常见误区
- ❌ “
z-index越大就一定在最上层”
→ 错!必须在同一个层叠上下文中比较才有意义。 - ❌ “父元素
z-index: 1,子元素z-index: 999就能盖住其他z-index: 2的元素”
→ 错!如果父元素本身处于一个较低的层叠上下文,子元素再高也出不去。
五、调试建议
- 使用浏览器开发者工具(如 Chrome DevTools)的 3D View 或 Layers 面板查看层叠上下文。
- 检查元素是否创建了新的层叠上下文(可通过 computed 样式判断)。
- 确保比较
z-index时,元素处于同一层叠上下文中。
