想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!css
z-index
属性,尽管已经写了这么多,仍然被普遍地误解和错误地处理。在复杂的单页web应用程序中堆积问题可能会成为一个主要问题。然而,坚持一些原则,咱们能够很容易地避免这些问题。html
若是你有过任何复杂的Web UI开发,那么你可能有些时候会疯狂地尝试将元素的 z-index
设置为上千或者很大的一个数,却发现它不能帮助你把它放在其余元素之上,这些元素的z-index
更低,甚至根本没有定义。前端
为何会这样?更重要的是,如何避免这些问题?git
在本文中,我将讲述z-index
其实是什么,以及如何中止猜想它是否适用于任何特定的状况,并开始像对待任何其余方便的工具同样对待它。github
层叠上下文的层次结构web
若是你把网页想象成三维的,那么z-index
是定义了一个元素的z
坐标(也称为它的层叠顺序)属性:值越大,元素离观察者越近。你也能够将它看做是影响绘制顺序的属性,由于屏幕是由像素组成的二维网格。所以,z-index
值越大,元素在页面上绘制的时间就越晚。segmentfault
然而,一个主要的复杂因素是 z-index
值空间不平 - 它是分层的。 元素能够建立层叠上下文,该上下文成为其后代的z-index
值的根。 接着经过一个例子来解释层叠上下文的概念。架构
文档正文有五个div
节点:div1
,div2
,div3
,div1-1
和div2-1
。 它们都是绝对定位的而且彼此重叠。 div1-1
是div1
的子节点,div2-1
是div2
的子节点。ide
<body> <div class="div1"> <strong>div1</strong> <br/> (z-index: auto) <div class="div1-1"> <strong>div1-1</strong> <br/> (z-index: 10) </div> </div> <div class="div2"> <strong>div2</strong> <br/> (z-index: 1) <div class="div2-1"> <strong>div2-1</strong> <br/> (z-index: 10) </div> </div> <div class="div3"> <strong>div3</strong> <br/> (z-index: 2) </div> </body>
div { box-sizing: border-box; border: 1px solid black; padding: 5px; position: absolute; font-family: Verdana; } .div1, .div2, .div3 { width: 500px; height: 200px; } .div1-1, .div2-1 { width: 200px; height: 150px; } .div1 { left: 10px; top: 10px; background-color: rgba(220, 220, 170, 0.9); } .div1-1 { left: 250px; top: 30px; background-color: rgba(220, 170, 170, 0.9); z-index: 10; } .div2 { left: 20px; top: 90px; background-color: rgba(220, 170, 220, 0.9); z-index: 1; } .div2-1 { left: 120px; top: 30px; background-color: rgba(170, 220, 170, 0.9); z-index: 10; } .div3 { left: 30px; top: 170px; background-color: rgba(170, 220, 220, 0.9); z-index: 2; }
接着咱们解释咱们所看到的现象。这里有详细绘制顺序,但这里咱们只须要比较两件事。工具
若是元素具备更高的z-index,则绘制会比值小的晚。
若是 z-index
值相同,那么在样式文件中出现越靠后,绘制越晩。
所以,根据咱们的 CSS 文件,若是咱们不考虑层叠上下文,顺序应该以下:
注意,div2-1
实际上位于 div3
后面的,为何会这样?
注意:z-index 值为 auto 不会建立一个 层叠上下文
若是一个元素要建立一个层叠上下文,它会为其子元素的 z-index
值建立一个地基或者局部框,所以在肯定绘制顺序时,它们永远不会与层叠上下文以外的任何内容进行比较。 换句话说,当一个建立层叠上下文的元素被绘制时,这个元素下的的全部子元素都在它以后和它的任何兄弟以前绘制。
回到示例,body 后代div
的实际绘制顺序是
注意列表中没有 div2-1
,它是div2
的一个子元素,它建立了一个层叠上下文(由于它是一个绝对定位的元素,除了auto
的默认值以外,它还有z-index
),因此它是在div2
以后绘制的,但在div3
以前。
div1
没有建立层叠上下文,由于它的z-index
值为 auto
,因此在div2
和div3
以后绘制div1-1
(div1的子元素,由于div1-1
的 z-index
值为 10
大于 div2
和 div3
。
若是你没有看懂,请不要担忧。如下是一些资源能够更好地解释这些概念:
然而,本文的重点是,当页面由数十个和数百个组件组成时,如何处理z-index
,每一个组件均可能定义了z-index
的子组件。
关于z-index
最流行的一篇文章建议将全部z-index值分组在一个地方,可是若是这些值不属于相同的层叠上下文(在大型应用程序中可能不容易实现),那么比较这些值就没有意义了。
这里一个例子。 假设咱们有一个包含 header
和 main
部分的页面。 因为某种缘由,main 里面内容样式必须设置:position: relative
和 z-index: 1
。
// html <div class="header"> Header </div> <div class="main"> Main Content </div>
// css body { margin: 0; font-family: Verdana; text-align: center; background-color: white; } div { display: flex; align-items: center; justify-content: center; } .header { background-color: rgba(255, 255, 220, 0.5); font-size: 10vmin; position: relative; height: 30vh; } .main { background-color: rgba(220, 255, 255, 0.5); font-size: 10vmin; height: 70vh; position: relative; z-index: 1; }
运行效果:
在这里使用的是组件体系结构,因此根组件和每一个子组件的 CSS 都是在专用部分中定义的。实际上,组件将驻留在单独的文件中,而且标记将使用你选择的 JavaScript 库(如React)生成,但出于演示目的,将全部内容放在一块儿也没有问题。
如今,假设咱们的任务是在header
中建立一个下拉菜单。固然,它必须位于main
上面,因此咱们给它一个z-index:10
// html <div class="header"> Header <div class="overlay"> Overlay </div> </div> <div class="main"> Main Content </div>
// css body { margin: 0; font-family: Verdana; text-align: center; background-color: white; } div { display: flex; align-items: center; justify-content: center; } .header { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; } .overlay { position: absolute; z-index: 10; background-color: rgba(255, 220, 255, 0.8); left: 10vw; top: 25vh; width: 50vw; height: 50vh; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.3)); } .overlay::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: 100%; width: 0; height: 0; border-top: 10px solid transparent; border-right: 10px solid transparent; border-left: 10px solid transparent; border-bottom: 10px solid rgba(255, 220, 255, 0.8); } .main { background-color: rgba(220, 255, 255, 0.8); font-size: 10vmin; height: 70vh; position: relative; z-index: 1; }
运行效果:
如今,几个月后,为了让一些不相关的东西更好地工做,咱们须要在 header 样式多加一个 transform: translateZ(0)
。
// 部分代码 .header { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; transform: translateZ(0); }
如你所见,布局现已被打破。 在没有z-index
规则的状况下,z-index:1
的元素位于具备z-index:10
的元素的顶部。 缘由是header
使用transform
属性 它建立了一个层叠上下文,默认会有本身的z-index
,值为0
低于 main
中 z-index (1)。
解决方案很简单:给header
一个z-index
值为2
。
// 部分代码 .header { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; transform: translateZ(0); z-index: 2; }
运行效果:
问题是,若是咱们在组件内的组件中有组件,每一个组件具备不一样的z-index
元素,咱们应该怎么作到这个解决方案? 咱们如何确保更改 header 的z-index
不会破坏其余任何内容?
答案是须要一种协定,消除了猜想的须要,它是这样的:更改组件内的z-index
应该只影响该组件,而不影响其余任何东西。换句话说,在处理某个CSS文件中的z-index
值时,理想状况下咱们应该只关心该文件中的其余值。
实现它很容易。 咱们应该简单地确保每一个组件的根建立层叠上下文。 最简单的方法是为它提供鹊确切的 position
和 z-index
的值,而不是使用默认它们本身的默认值。
下面是构建应用程序的一种方法。它使用的元素比前一个多,可是相对额外的DOM元素相关联的计算来讲是很划算的,节省开发人员在处理层叠上下文问题时间。
// html <!-- root component starts --> <div class="root__container"> <div class="root__header"> <!-- header component starts --> <div class="header__container"> Header <div class="header__overlay"> Overlay </div> </div> <!-- header component ends --> </div> <div class="root__main"> <!-- main component starts --> <div class="main__container"> Main Content </div> <!-- main component ends --> </div> </div> <!-- root component ends -->
// css body { margin: 0; font-family: Verdana; text-align: center; background-color: white; } /* Root styles */ .root__container { position: relative; z-index: 0; } .root__header { position: relative; z-index: 2; } .root__main { position: relative; z-index: 1; } /* Header styles */ .header__container { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; transform: translateZ(0); display: flex; align-items: center; justify-content: center; z-index: 0; } .header__overlay { position: absolute; z-index: 1; background-color: rgba(255, 220, 255, 0.8); left: 10vw; top: 25vh; width: 50vw; height: 50vh; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.3)); display: flex; align-items: center; justify-content: center; } .header__overlay::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: 100%; width: 0; height: 0; border-top: 10px solid transparent; border-right: 10px solid transparent; border-left: 10px solid transparent; border-bottom: 10px solid rgba(255, 220, 255, 0.8); } /* Main section styles */ .main__container { background-color: rgba(220, 255, 255, 0.8); font-size: 10vmin; height: 70vh; display: flex; align-items: center; justify-content: center; position: relative; z-index: 0; }
运行效果:
header__container
和 main__container
都有 position: relative
和z-index: 0
header overlay
现有z-index: 1
(咱们不须要很大的值,由于它只会与 header
中的其余元素进行比较)root__header
现有z-index: 2
,而 root__main
保持其z-index: 1
,这就是两兄弟正确层叠的缘由(还要注意,二者都有position: relative
,由于 z-index 不适用于 position:static的元素。)
若是咱们如今查看 header
代码,咱们会注意到咱们能够彻底从container
和 overlay
层中删除z-index
属性,由于overlay 层是那里惟必定位的元素。 一样,main container 上不须要z-index
。 这样分类最大好处:在查看z-index
时,只注重组件自己,而不是它的上下文。
// 删除上述所说的 z-index body { margin: 0; font-family: Verdana; text-align: center; background-color: white; } /* Root styles */ .root__container { position: relative; z-index: 0; } .root__header { position: relative; z-index: 2; } .root__main { position: relative; z-index: 1; } /* Header styles */ .header__container { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; transform: translateZ(0); display: flex; align-items: center; justify-content: center; } .header__overlay { position: absolute; background-color: rgba(255, 220, 255, 0.8); left: 10vw; top: 25vh; width: 50vw; height: 50vh; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.3)); display: flex; align-items: center; justify-content: center; } .header__overlay::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: 100%; width: 0; height: 0; border-top: 10px solid transparent; border-right: 10px solid transparent; border-left: 10px solid transparent; border-bottom: 10px solid rgba(255, 220, 255, 0.8); } /* Main section styles */ .main__container { background-color: rgba(220, 255, 255, 0.8); font-size: 10vmin; height: 70vh; display: flex; align-items: center; justify-content: center; }
运行效果:
这种架构并不是没有缺点。 它以牺牲一些灵活性为代价使应用程序更具可预测性。 例如,你将没法在header
和main section
内建立此类叠加层:
// html <div class="header"> Header <div class="header-overlay"> Header Overlay </div> </div> <div class="main"> Main Content <div class="main-overlay"> Main Overlay </div> </div>
// css body { margin: 0; font-family: Verdana; text-align: center; background-color: white; } div { display: flex; align-items: center; justify-content: center; } .header { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; } .header-overlay { position: absolute; z-index: 10; background-color: rgba(255, 220, 255, 0.8); left: 2vw; top: 25vh; width: 47vw; height: 50vh; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.3)); } .header-overlay::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: 100%; width: 0; height: 0; border-top: 10px solid transparent; border-right: 10px solid transparent; border-left: 10px solid transparent; border-bottom: 10px solid rgba(255, 220, 255, 0.8); } .main { background-color: rgba(220, 255, 255, 0.8); font-size: 10vmin; height: 70vh; position: relative; } .main-overlay { position: absolute; z-index: 10; background-color: rgba(255, 255, 255, 0.8); left: 51vw; bottom: 40vh; width: 47vw; height: 50vh; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.3)); } .main-overlay::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); top: 100%; width: 0; height: 0; border-top: 10px solid rgba(255, 255, 255, 0.8); border-right: 10px solid transparent; border-left: 10px solid transparent; border-bottom: 10px solid transparent; }
然而,根据个人经验,这不多是一个问题。 你可使用 main section 中的 overlay 层向下而不是向上,以使其不与header
相交。 或者,若是你真的须要它,你能够在正文的末尾注入叠加HTML 并给它一个大的 z-index 值(“大”是比顶层其余部分更大)。
再次说明
z-index
值隔离组件;auto
以外的z-index
值,则没必要执行此操做;10
的步长,或者你可使用变量——这都取决于你的项目约定和组件的大小。最好只将z-index
分配给同级元素。不然,你可能会无心中在一个组件中引入更多的层叠上下文。z-index
。你的点赞是我持续分享好东西的动力,欢迎点赞!