简体   繁体   English

::在子边框后面的伪元素之前

[英]::before pseudo-element behind child border

I have an h1 tag, and I'm attempting to add a cool animation to it, where the border will 'grow' from the top-left and bottom-right points. 我有一个h1标签,并且尝试向其中添加很酷的动画,其中边框将从左上角和右下角点“增长”。

I'm doing this by wrapping my h1 in two div s, and each div has a ::before and ::after pseudo-element. 我是通过将h1封装在两个div的,每个div都有一个::before::after伪元素。

When the root div is moused over, the pseudo-elements of these divs will 'shrink', revealing the border below. 将根div鼠标悬停时,这些div的伪元素将“缩小”,从而露出下面的边框。

The issue is, the ::before pseudo-element of my root div is behind the border, and so the border is shown immediately on mouseover. 问题是,我的根div的::before伪元素位于边框的后面 ,因此鼠标悬停时会立即显示边框。 Setting the z-index of the ::before s and ::after s will fix it; 设置::before s和::afterz-index 可以解决它; however, I do not want to do this -- this is a snippet of code I'm making for copy / pasting. 但是,我不想这样做-这是我正在复制/粘贴的一小段代码。 No z-index s are set, so I'm confused as to why this is happening. 没有设置z-index ,所以我对为什么发生这种情况感到困惑。

Before, I had no div s besides what was needed for the animation, and it worked fine -- but how would that have to do with it? 以前,除了动画所需的内容外,我没有div ,而且效果很好-但是那与动画有什么关系呢?

This seems to be the issue: ::before pseudo-element stacking order issue . 这似乎是问题所在::: before伪元素堆叠顺序问题

However, no answers are suggested as to how to fix it. 但是,没有建议如何解决它的答案。 I could add a third div, of course, but I'd like to keep that as a last resort. 当然,我可以添加第三个div,但我想保留它作为最后的选择。

Fiddle of issue: https://jsfiddle.net/zppqgn6s/ 小提琴问题: https : //jsfiddle.net/zppqgn6s/

To see it fixed with z-index ; 看到它用z-index固定; to see what it's supposed to look like, uncomment line 34. 要查看其外观,请取消注释第34行。

Reason for pseudo-element's border being below child: 伪元素的边界低于子元素的原因:

Answer to the original question on why the pseudo-element's ( :before ) background goes behind the child ( h1 ) can be found in BoltClock's answer (that you had linked within the question). 关于为何伪元素( :before )背景落后于子( h1 )的原始问题的答案可以在BoltClock的答案中找到(您已在问题中进行了链接)。 The :before pseudo-element is actually inserted before the content of the root div (which includes the h1 ). :before伪元素实际上是在根div内容(包括h1 )之前插入的。

Here is the general structure of the elements that are used in the demo: 这是演示中使用的元素的一般结构:

#anim              /* This is the first element inside root and is positioned (relative) */
    #anim:before   /* This is positioned absolutely with respect to the parent */
    div            /* This element is positioned relatively */
        div:before /* This element is positioned absolutely with respect to the div */
        h1         /* This element doesn't have any positioning */
        div:after  /* This element is positioned absolutely with respect to the div */
    #anim:after    /* This is positioned absolutely with respect to the parent */

Now based on the specs for the visual rendering layers , the below is what happens: 现在, 基于视觉渲染层的规格,将发生以下情况:

#anim              /* Parent element and its background, border gets painted first (Layer 0) */
    #anim:before   /* Positioned descendant, creates stacking context nested within parent (Layer 0.1)*/
    div            /* Positioned descendant of #anim, second child in flow (Layer 0.2) */
        div:before /* Positioned descendant of div, first child in flow (Layer 0.2.2) */
        h1         /* Non positioned, as per Point 3 gets positioned lowest (Layer 0.2.1) */
        div:after  /* Positioned descendant of div, second such child in flow (Layer 0.2.3) */
    #anim:after    /* Positioned descendant of #anim, third child in flow (Layer 0.3) */

As can be seen based on layer numbers (provided in inline comments), the h1 element is positioned above #anim:before (but below all the other three elements that produce the border shrink effect). 从图层编号(内联注释中提供)可以看出, h1元素位于#anim:before之上(但位于产生边框缩小效果的所有其他三个元素之下)。

Solutions: 解决方案:

The only solution to this is to make the child ( h1 ) get painted after the :before element. 唯一的解决方案是使子元素( h1 )在:before元素之后绘制。 This can be achieved by doing either of the below (but both of them require a z-index to be set): 这可以通过执行以下任一操作来实现(但它们都需要设置z-index ):

  • Setting the h1 to position: relative with z-index: -1 (so that it goes behind #anim:before ) h1设置为position: relative对于z-index: -1 (这样它就位于#anim:before
  • Setting z-index: 1 (or above) to the #anim:before element (so that it goes above the h1 ) z-index: 1 (或更高)设置为#anim:before元素(以使其高于h1

Alternate Solutions/Approaches: 替代解决方案/方法:

Actually, you don't need all the extra elements for this particular animation (of borders converging from top-left and bottom-right to meet each other). 实际上,您不需要此特定动画的所有额外元素(边界从左上角和右下角收敛以彼此交汇)。 They can be achieved using the single h1 element itself and I am posting this answer to illustrate two of those methods. 它们可以使用单个h1元素本身来实现,我将发布此答案以说明其中的两种方法。 Although you weren't asking for other methods, I like the effect and it seemed to be a good place to post this answer. 尽管您没有要求其他方法,但我喜欢这种效果,它似乎是发布此答案的好地方。

By using linear-gradient background images: 通过使用 linear-gradient 背景图像:

In this approach, we create one gradient (actually nothing but a solid color as it doesn't change colors) for each side of the border, position them appropriately and then transition the size from 0% to 100% . 在这种方法中,我们为边框的每一侧创建一个渐变(实际上只不过是纯色,因为它不会改变颜色),将其适当放置,然后将大小从0%100% For top and bottom borders, the size in X-axis should be changed from 0% to 100% on hover while for left and right borders, size in Y-axis should be changed from 0% to 100% . 对于顶部和底部边框, hover时X轴的大小应从0%更改为100% ;对于左侧和右侧边框,Y轴的大小应从0%更改为100%

 h1 { position: relative; display: inline-block; padding: 4px; background: linear-gradient(to right, #000, #000), linear-gradient(to right, #000, #000), linear-gradient(to bottom, #000, #000), linear-gradient(to bottom, #000, #000); background-position: 0% 0%, 100% 100%, 0% 0%, 100% 100%; background-size: 0% 2px, 0% 2px, 2px 0%, 2px 0%; /* 2px is border thickness */ background-repeat: no-repeat; transition: all 1s; } h1:hover { background-size: 100% 2px, 100% 2px, 2px 100%, 2px 100%; /* 2px is border thickness */ } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script> <h1>Hover me</h1> <br> <h1>How about me?<br>I have dynamic height!</h1> <div id="wrap"> <h1>Look at me, I am responsive!!!</h1> </div> 


By using pseudo-elements: 通过使用伪元素:

This can also be done using pseudo-elements by transitioning the height and width of them on hover . 这也可以使用伪元素通过在hover转换它们的高度和宽度来完成。 You were already on the right course here but the extra elements were not required. 您这里的路线已经正确,但是不需要其他元素。

 h1 { position: relative; display: inline-block; padding: 4px; } h1:after, h1:before { position: absolute; content: ''; height: 0%; width: 0%; transition: width 1s, height 1s, border .01s 1s; /* border has a delay because it should become invisible only after height and width become 0 */ } h1:before { left: 0; top: 0; border-top: 2px solid transparent; border-left: 2px solid transparent; } h1:hover:before { border-top: 2px solid black; border-left: 2px solid black; } h1:after { bottom: 0; right: 0; border-right: 2px solid transparent; border-bottom: 2px solid transparent; } h1:hover:after { border-right: 2px solid black; border-bottom: 2px solid black; } h1:hover:before, h1:hover:after { height: calc(100% - 2px); width: calc(100% - 2px); transition: width 1s, height 1s, border .01s; /* border has a shorter duration because it immediately needs to change colors */ } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script> <h1>Hover me</h1> <br> <h1>How about me?<br>I have dynamic height!</h1> <div id="wrap"> <h1>Look at me, I am responsive!!!</h1> </div> 

Both these approaches work even when extra div elements are added around (as can be seen from the snippets). 即使在周围添加了额外的div元素,这两种方法也都可以工作(如摘要所示)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM