[英]::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和::after
的z-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
):
h1
to position: relative
with z-index: -1
(so that it goes behind #anim:before
) h1
设置为position: relative
对于z-index: -1
(这样它就位于#anim:before
) 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.