Z-index实际如何工作

我们生命中几乎每个人至少有一次使用过z-index属性。 此外,每个开发人员都可以确定自己知道其工作原理。 实际上,这可能比整数操作(将它们比较并分配给元素)更简单。 但是,一切看起来乍看之下是否简单?

也许我将在下面介绍的信息实际上是微不足道的。 但是,我相信许多人会发现它对自己有用。 那些已经知道它的人将能够在困难时期将此文本用作备忘单。 所以欢迎猫。

图片

实际上,一个人通常会在以下三种情况下开始尝试为自己寻找一个新领域:如果他在工作中遇到意想不到的结果并且不了解正在发生的事情; 是否有必要超越视野,从另一个角度看待这个问题; 最后,只是出于体育兴趣。

我的案件显然不属于第三类。 最初,我一生中几次在不同的项目中工作时遇到了第一种情况。 但是,由于懒惰以及缺少带有示例的清晰易懂的材料,他无法完全理解问题。 然后,从今年年初开始,我开始编写一个Web引擎,这使我开始阅读标准,并大体上了解流行浏览器中不同的琐碎事情是如何工作的,最重要的是, 为什么它们如此工作。

让我们从一个简单的开始。 什么是z-index?它的作用是什么?

显然,这是为某些元素指定的沿Z轴的坐标。 Z轴指向用户。 较大的数字是更接近的元素。

图片

为什么Z索引数字是整数? 一切都很简单。 该范围实际上在顶部和底部是无限的,因此我们不需要使用分数。 由于实际的监视器没有第三维(我们只能模拟),因此我们需要一些无量纲的数量,其唯一任务是提供元素的比较(即集合的顺序)。 整数在完成此任务方面做得很好,而它们比真实的更具可视性。

似乎这些知识足以开始在页面上使用z-index。 但是,并非一切都那么简单。

<div style="background: #b3ecf9; z-index: 1"></div> <div style="background: #b3ecb3; margin-top: -86px; margin-left: 38px; z-index: 0"></div> 

图片

似乎出了点问题。 我们使第一个块的z-index大于第二个块的z-index,为什么它显示在下面? 是的,它早先通过了代码-但似乎只有在z-index值相等的情况下,它才应该发挥作用。

现在,是时候打开关于覆盖上下文处理的CSS2.1标准,或者是它的应用程序。 这是链接

您可以从这小而简明的文本中立即提取许多重要信息。

  1. z-index控制不覆盖单个元素,而是覆盖上下文(元素组)
  2. 我们不能在彼此相对的上下文中任意控制元素:这里的层次结构起作用。 如果我们已经处于“低”上下文中,那么我们就不能使其成为“高”上下文中元素的上方。
  3. 对于常规流(其position属性为静态)中的元素,z-index根本没有任何意义。 在上面的示例中,我们陷入了这个陷阱。
  4. 为使元素定义新的叠加层上下文,必须对其进行定位并为其分配z索引。
  5. 如果定位了元素,但未设置z-index,则我们可以有条件地假定它等于零(对于简单的情况,像这样工作,我们将在以后考虑细微差别)。
  6. 各个叠加上下文由不透明度值小于1的元素设置。 这样做是为了使您可以轻松地将alpha混合转移到渲染的最后阶段,以供视频卡进行处理。

但这还不是全部。 事实证明,对于没有z-index的元素,它也不像看起来那样简单。

渲染上下文子树的元素的过程可以分为几个阶段(其中前两个阶段是直接输出设置上下文的当前元素的背景色和背景图像)。

因此,请考虑整个列表。

3.带有负z索引的子上下文的派生
4.正常流程中子块元素的输出(仅背景)
5.子浮点元素的输出
6.普通流中元素内容的输出:内联和内联块后代,内联内容在块后代中,包括文本行*
7.具有零和自动z-index **的子上下文的输出
8.带有正z索引的子上下文的派生

*为了遍历深度优先树
**对于具有z-index:自动的上下文,请将所有子上下文视为当前上下文的后代,即将其“拉”到当前级别

已经不是那么容易了,对吧? 您可以通过以下图片大致说明此方案:

图片

也可以在Codepen上打开一个示例, 然后自己动手玩。

但这还不是全部。 看来该算法已经非常复杂:我们需要首先在伪上下文中提取子上下文(还记得auto的值),然后对两个z-index列表进行排序,将它们按数字序列排列,然后遍历子对象:首先,块在正常流中,然后浮动,然后是内联和内联块...

但是在这里,我们正在等待两个惊喜。 首先,幸运的是,我们不会担心。 这与以下事实有关:带有框架的背景和块元素的内容在不同的阶段显示-但是如果我们为每个文本节点自行创建的引擎创建一个自动内联元素,那么一切都会好起来的,它们自然会在以后显示。

但是第二个并不是那么简单。 被标记
对于这些元素中的每一个,都应将元素视为已创建新的堆栈上下文,但实际上已创建新的堆栈上下文的所有已定位后代和后代均应视为父级堆栈上下文的一部分,而不是此新堆栈上下文。

float和inline-block / inline(但不是block!)元素。

在实践中这意味着什么? 这意味着我们必须以与带有z-index的元素相同的方式来处理它们:auto。 也就是说,首先,绕过它们的子树并从那里拉出子上下文,将它们放在当前级别。 但是对于其余部分,我们应该将它们视为定义上下文的元素。 这意味着它们内部的所有子树(在爬网到线性列表后都将被拉伸)应保持原子状态。 或者,换句话说,我们不能混洗元素的顺序,以使该元素的后代“浮动”在其父代之上。 并且如果对于子上下文而言,它在直观上是清晰的(因为该算法是递归的),那么事实并非如此。

因此,在编写引擎代码时,我们必须欺骗自己,以便使float,inline和inline-block元素暂时不显示其后代(具有定位和z-index的子代除外,它们形成叠加上下文),然后为它们运行整个函数是递归的,但是相反,考虑到在遍历期间应跳过子上下文的事实。

一些例子来证明这种现象:

 <div style="float: left; background: #b3ecf9;"> <div style="width: 40px; height: 40px; background: #fff700; position: relative; z-index: -1; top: -20px; left: -20px;"></div> </div> 

图片

此处孩子具有z-index并被定位。 它会弹出,但显示在蓝色正方形下,因为在阶段3中显示z索引为负的元素,在阶段5中显示浮动元素。

 <div style="float: left; margin-top: -30px; background: #b3ecf9;"> <div style="width: 40px; height: 40px; background: #fff700; position: relative; z-index: 0;"></div> </div> <div style="background: #b3ecb3; margin-top: 52px; margin-left: 38px;"> <div style="width: 40px; height: 40px; background: #ff0000; position: relative; z-index: 0;"></div> </div> 

图片

在此示例中,第二个元素(绿色)显示在第一个元素(蓝色)之前,因此显示在下面。 但是,子代会被拉起(因为他们设置了自己的上下文),因此在这种情况下,子代的排列顺序与原始树中的排列顺序完全相同(排列后祖先的顺序并不重要!)。 如果将第一个子对象的z-index设置为等于1,则得到以下图片:

图片

添加更多元素。

 <div style="float: left; background: #b3ecf9;"> <div style="float: left"> <div style="width: 40px; height: 40px; background: #fff700; position: relative; z-index: 0;"></div> </div> </div> <div style=" background: #b3ecb3; margin-top: 32px; margin-left: 40px;"> <div style="position: relative"> <div style="width: 40px; height: 40px; background: #ff0000; position: relative; z-index: 0;"></div> </div> </div> 

图片

在这里,子上下文从浮点数和普通块中提取,而顺序则保留在原始树中。

最后,最后一个例子:

 <div style="background: #b3ecf9;"> <div style="display: inline-block; width: 40px; height: 40px; background: #fc0;"></div> </div> <div style="background: #b3ecb3; margin-top: -100px; margin-left: 22px;"></div> 

图片

如您所见,与其他情况相比,“跳出”一个block元素是完全可能的,并且由于我们弹出一个inline-block元素,因此它将是本文档中的最后一个元素。

如您所见,z-index允许您执行许多有趣的技巧(使用子元素上的负z-index,至少值得将该元素隐藏在其直接父元素下)。 希望本文对您有所帮助。

Source: https://habr.com/ru/post/zh-CN431046/


All Articles