CSS 层叠上下文和堆叠顺序

介绍

CSS 层叠上下文和堆叠顺序是 CSS 中控制元素在视觉上如何堆叠的重要概念。当多个元素在页面上重叠时,理解这些概念对于预测和控制哪个元素会显示在前面至关重要。在本章中,我们将深入探讨层叠上下文的工作原理、创建方式以及如何有效地管理堆叠顺序,以避免常见的 z-index 陷阱。

核心知识点

层叠上下文基础

1. 什么是层叠上下文

  • 层叠上下文是一个三维概念,表示元素在 z 轴上的堆叠关系
  • 每个层叠上下文都有自己的层叠顺序
  • 层叠上下文内部的元素不会影响外部元素的堆叠顺序

2. 层叠顺序

  • 层叠顺序决定了在同一个层叠上下文中元素的堆叠顺序
  • 从后到前的默认堆叠顺序:背景和边框 → 负 z-index 值 → 块级元素 → 浮动元素 → 行内元素 → 正 z-index 值
  • 越晚在 HTML 中出现的元素,在层叠顺序中越靠前(在相同堆叠级别时)

3. z-index 属性

  • z-index:控制元素在层叠上下文中的堆叠顺序
  • 仅对定位元素(position 值不为 static)有效
  • 可以是 auto 或整数值(正、负或零)
  • 较高的 z-index 值通常会使元素显示在前面

创建层叠上下文的方法

1. 根层叠上下文

  • 由浏览器创建的最外层层叠上下文
  • 对应于 <html> 元素
  • 所有其他层叠上下文都是它的子级

2. 定位元素与 z-index

  • 任何 position 值不为 static 且 z-index 值不为 auto 的元素
  • 会创建一个新的层叠上下文
  • 其子元素的 z-index 相对于此上下文

3. CSS 属性创建的层叠上下文

  • opacity 值小于 1 的元素
  • transform 值不为 none 的元素
  • filter 值不为 none 的元素
  • backdrop-filter 值不为 none 的元素
  • perspective 值不为 none 的元素
  • isolation 值为 isolate 的元素
  • will-change 指定了上述任何属性的元素
  • contain 值为 layout、paint 或 strict 的元素
  • CSS Grid 和 Flexbox 容器的子元素,当子元素的 z-index 不为 auto 时

4. 层叠上下文的嵌套

  • 层叠上下文可以嵌套
  • 内层层叠上下文完全包含在外层层叠上下文内
  • 内层元素的 z-index 不会影响外层元素的堆叠顺序

实用示例

示例 1:基本层叠顺序

/* 基本层叠顺序示例 */
.static-element {
  position: static;
  background-color: #3498db;
  width: 200px;
  height: 200px;
  margin: 10px;
}

.relative-element {
  position: relative;
  background-color: #2ecc71;
  width: 200px;
  height: 200px;
  margin: -150px 10px;
}

.absolute-element {
  position: absolute;
  background-color: #e74c3c;
  width: 200px;
  height: 200px;
  top: 50px;
  left: 50px;
}

.z-index-element {
  position: relative;
  background-color: #f39c12;
  width: 200px;
  height: 200px;
  margin: -150px 10px;
  z-index: 1;
}

.z-index-negative {
  position: relative;
  background-color: #9b59b6;
  width: 200px;
  height: 200px;
  margin: -150px 10px;
  z-index: -1;
}

示例 2:创建层叠上下文的属性

/* 创建层叠上下文的属性示例 */
.opacity-example {
  opacity: 0.9;
  background-color: #3498db;
  width: 200px;
  height: 200px;
  position: relative;
}

.transform-example {
  transform: rotate(5deg);
  background-color: #2ecc71;
  width: 200px;
  height: 200px;
  position: relative;
  margin: -150px 10px;
}

.filter-example {
  filter: blur(1px);
  background-color: #e74c3c;
  width: 200px;
  height: 200px;
  position: relative;
  margin: -150px 10px;
}

.isolation-example {
  isolation: isolate;
  background-color: #f39c12;
  width: 200px;
  height: 200px;
  position: relative;
  margin: -150px 10px;
}

/* 内部元素 */
.inner-element {
  position: absolute;
  background-color: rgba(255, 255, 255, 0.8);
  width: 100px;
  height: 100px;
  top: 50px;
  left: 50px;
  z-index: 9999;
}

示例 3:z-index 陷阱

/* z-index 陷阱示例 */
/* 父元素 */
.parent {
  position: relative;
  background-color: #3498db;
  width: 300px;
  height: 300px;
  margin: 20px;
  /* 注意:没有 z-index,不会创建新的层叠上下文 */
}

/* 子元素 A */
.child-a {
  position: absolute;
  background-color: #e74c3c;
  width: 200px;
  height: 200px;
  top: 20px;
  left: 20px;
  z-index: 10;
}

/* 父元素 2 */
.parent-2 {
  position: relative;
  background-color: #2ecc71;
  width: 300px;
  height: 300px;
  margin: -250px 50px;
  /* 注意:设置了 z-index,创建了新的层叠上下文 */
  z-index: 1;
}

/* 子元素 B */
.child-b {
  position: absolute;
  background-color: #f39c12;
  width: 200px;
  height: 200px;
  top: 20px;
  left: 20px;
  z-index: 9999;
  /* 即使 z-index 很高,也无法超越父元素的层叠上下文 */
}

示例 4:层叠上下文嵌套

/* 层叠上下文嵌套示例 */
/* 外层容器 */
.outer-container {
  position: relative;
  background-color: #3498db;
  width: 400px;
  height: 400px;
  margin: 20px;
  z-index: 1;
  /* 创建外层层叠上下文 */
}

/* 中层容器 */
.middle-container {
  position: relative;
  background-color: #2ecc71;
  width: 300px;
  height: 300px;
  margin: 50px;
  z-index: 1;
  /* 创建中层层叠上下文 */
}

/* 内层元素 */
.inner-element {
  position: absolute;
  background-color: #e74c3c;
  width: 200px;
  height: 200px;
  top: 50px;
  left: 50px;
  z-index: 9999;
  /* 只能在中层层叠上下文中生效 */
}

/* 外部元素 */
.external-element {
  position: absolute;
  background-color: #f39c12;
  width: 200px;
  height: 200px;
  top: 100px;
  left: 100px;
  z-index: 2;
  /* 在外层层叠上下文中,比 outer-container 高 */
}

示例 5:Flexbox 和 Grid 中的层叠上下文

/* Flexbox 和 Grid 中的层叠上下文 */
/* Flex 容器 */
.flex-container {
  display: flex;
  background-color: #3498db;
  width: 400px;
  height: 200px;
  margin: 20px;
  position: relative;
}

/* Flex 子项 */
.flex-item {
  flex: 1;
  background-color: #2ecc71;
  margin: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

/* 设置了 z-index 的 Flex 子项 */
.flex-item-high {
  z-index: 1;
  /* 在 Flex 容器中,设置了 z-index 的子项会创建层叠上下文 */
  transform: translateX(-50px);
}

/* Grid 容器 */
.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  background-color: #9b59b6;
  width: 400px;
  height: 200px;
  margin: 20px;
  position: relative;
}

/* Grid 子项 */
.grid-item {
  background-color: #f39c12;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

/* 设置了 z-index 的 Grid 子项 */
.grid-item-high {
  z-index: 1;
  /* 在 Grid 容器中,设置了 z-index 的子项会创建层叠上下文 */
  transform: translateY(-30px);
}

示例 6:层叠上下文的实际应用

/* 层叠上下文的实际应用 */
/* 导航栏 */
.navbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background-color: #333;
  color: white;
  padding: 1rem;
  z-index: 1000;
  /* 创建层叠上下文,确保导航栏在其他内容之上 */
}

/* 模态框背景 */
.modal-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 1050;
  /* 创建层叠上下文,在导航栏之上 */
}

/* 模态框内容 */
.modal-content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: white;
  padding: 2rem;
  border-radius: 8px;
  z-index: 10;
  /* 在模态框背景的层叠上下文中 */
}

/* 下拉菜单 */
.dropdown {
  position: relative;
  display: inline-block;
  /* 不创建层叠上下文 */
}

.dropdown-menu {
  position: absolute;
  top: 100%;
  left: 0;
  background-color: white;
  border: 1px solid #ddd;
  border-radius: 4px;
  padding: 0.5rem 0;
  min-width: 150px;
  z-index: 1000;
  /* 相对于父元素定位,但父元素没有创建层叠上下文 */
  /* 所以 z-index 相对于根层叠上下文 */
}

/* 工具提示 */
.tooltip {
  position: relative;
  display: inline-block;
  /* 不创建层叠上下文 */
}

.tooltip-content {
  position: absolute;
  bottom: 125%;
  left: 50%;
  transform: translateX(-50%);
  background-color: #333;
  color: white;
  padding: 0.5rem;
  border-radius: 4px;
  white-space: nowrap;
  z-index: 1000;
  /* 相对于父元素定位,但父元素没有创建层叠上下文 */
  /* 所以 z-index 相对于根层叠上下文 */
}

实践练习

练习 1:创建层叠上下文层次结构

创建一个包含多个层叠上下文的页面,具有以下特点:

  • 根层叠上下文
  • 由定位元素创建的层叠上下文
  • 由 CSS 属性(如 opacity、transform)创建的层叠上下文
  • 嵌套的层叠上下文
  • 在不同层叠上下文中放置元素,观察它们的堆叠行为

练习 2:解决 z-index 陷阱

创建一个包含 z-index 陷阱的场景,然后解决它,具有以下特点:

  • 创建两个父元素,其中一个创建层叠上下文
  • 在每个父元素中放置子元素,设置不同的 z-index 值
  • 观察子元素的堆叠行为
  • 调整代码,使子元素按照预期堆叠

练习 3:构建模态框系统

构建一个模态框系统,具有以下特点:

  • 固定定位的模态框背景
  • 居中的模态框内容
  • 确保模态框显示在所有其他内容之上
  • 添加多个模态框,确保它们按照打开顺序堆叠
  • 实现模态框的关闭功能

练习 4:创建下拉菜单系统

创建一个下拉菜单系统,具有以下特点:

  • 导航栏中的下拉菜单项
  • 下拉菜单在悬停时显示
  • 确保下拉菜单显示在其他内容之上
  • 处理下拉菜单的嵌套
  • 确保在移动设备上的正确行为

总结

在本章中,我们深入探讨了 CSS 层叠上下文和堆叠顺序的概念,这些是控制元素在视觉上如何堆叠的关键。我们涵盖了:

  1. 层叠上下文的基础知识,包括其定义和工作原理
  2. 层叠顺序的默认规则和 z-index 属性的作用
  3. 创建层叠上下文的各种方法,包括定位元素和特定 CSS 属性
  4. 层叠上下文的嵌套行为和 z-index 陷阱
  5. 实际应用示例,如导航栏、模态框和下拉菜单

理解这些概念对于创建复杂的 UI 至关重要,尤其是当元素需要在视觉上重叠时。通过正确管理层叠上下文,您可以避免常见的 z-index 问题,并创建更加可预测和可维护的布局。

记住,创建层叠上下文的最佳实践是:

  • 只在必要时创建层叠上下文
  • 保持 z-index 值的管理简单明了
  • 避免过度使用高 z-index 值
  • 理解层叠上下文的继承和嵌套行为

复习问题

  1. 什么是层叠上下文?它如何影响元素的堆叠顺序?
  2. 默认的层叠顺序是什么?
  3. z-index 属性如何工作?它有什么限制?
  4. 哪些 CSS 属性可以创建层叠上下文?
  5. 什么是 z-index 陷阱?如何避免它?
  6. 层叠上下文嵌套时的行为是什么?
  7. 在 Flexbox 和 Grid 布局中,层叠上下文是如何创建的?
  8. 如何确保模态框始终显示在其他内容之上?

进一步阅读

« 上一篇 CSS 嵌套 下一篇 » CSS3 高级特性 - overscroll-behavior 属性