::before 子边框后面的伪元素
::before pseudo-element behind child border
我有一个 h1
标签,我正在尝试为其添加一个很酷的动画,其中边框将从左上角和右下角的点 'grow'。
我通过将我的 h1
包装在两个 div
中来做到这一点,每个 div
都有一个 ::before
和 ::after
伪元素.
当鼠标悬停在根 div
上时,这些 div 的伪元素将 'shrink',显示下面的边框。
问题是,我的根 div 的 ::before
伪元素 在 边框后面,因此边框会在鼠标悬停时立即显示.设置 ::before
和 ::after
的 z-index
将 修复它;但是,我不想这样做——这是我为复制/粘贴而制作的一段代码。没有设置 z-index
,所以我很困惑为什么会这样。
以前,除了动画需要的东西外,我没有 div
s,而且效果很好——但这与它有什么关系?
这似乎是问题所在:::before pseudo-element stacking order issue。
但是,没有关于如何修复它的建议答案。当然,我可以添加第三个 div,但我想保留它作为最后的手段。
Fiddle 期:https://jsfiddle.net/zppqgn6s/
看到它用z-index
修复了;要查看它应该是什么样子,请取消注释第 34 行。
pseudo-element的边框低于child的原因:
关于为什么 pseudo-element (:before
) 的背景落后于 child (h1
) 的原始问题的答案可以在 BoltClock 的答案中找到 (您已在问题中链接)。 :before
pseudo-element 实际上插入在根 div
的内容之前(包括 h1
)。
下面是演示中使用的元素的一般结构:
#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 */
现在 based on the specs for the visual rendering layers,下面是发生的情况:
#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) */
根据层数可以看出(在行内注释中提供),h1
元素位于 #anim:before
上方(但在产生边框收缩效果的所有其他三个元素下方) .
解法:
唯一的解决办法是在 :before
元素之后绘制 child (h1
)。这可以通过执行以下任一操作来实现(但它们都需要设置 z-index
):
- 使用
z-index: -1
将 h1
设置为 position: relative
(使其落后于 #anim:before
)
- 将
z-index: 1
(或更高)设置为 #anim:before
元素(使其高于 h1
)
备用 Solutions/Approaches:
实际上,您不需要此特定动画的所有额外元素(从 top-left 和 bottom-right 交汇的边界)。它们可以使用单个 h1
元素本身来实现,我正在 post 这个答案来说明其中两种方法。虽然你没有要求其他方法,但我喜欢这种效果,它似乎是 post 这个答案的好地方。
通过使用 linear-gradient
背景图片:
在这种方法中,我们为边框的每一侧创建一个渐变(实际上只是一种纯色,因为它不会改变颜色),适当地放置它们,然后将大小从 0%
过渡到100%
。对于顶部和底部边框,X-axis 中的大小应在 hover
上从 0%
更改为 100%
,而对于左右边框,Y-axis 中的大小应从 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>
通过使用pseudo-elements:
这也可以使用 pseudo-elements 通过在 hover
上转换它们的高度和宽度来完成。您已经走上了正确的道路,但不需要额外的元素。
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>
即使在周围添加了额外的 div
元素(从代码片段中可以看出),这两种方法都有效。
我有一个 h1
标签,我正在尝试为其添加一个很酷的动画,其中边框将从左上角和右下角的点 'grow'。
我通过将我的 h1
包装在两个 div
中来做到这一点,每个 div
都有一个 ::before
和 ::after
伪元素.
当鼠标悬停在根 div
上时,这些 div 的伪元素将 'shrink',显示下面的边框。
问题是,我的根 div 的 ::before
伪元素 在 边框后面,因此边框会在鼠标悬停时立即显示.设置 ::before
和 ::after
的 z-index
将 修复它;但是,我不想这样做——这是我为复制/粘贴而制作的一段代码。没有设置 z-index
,所以我很困惑为什么会这样。
以前,除了动画需要的东西外,我没有 div
s,而且效果很好——但这与它有什么关系?
这似乎是问题所在:::before pseudo-element stacking order issue。
但是,没有关于如何修复它的建议答案。当然,我可以添加第三个 div,但我想保留它作为最后的手段。
Fiddle 期:https://jsfiddle.net/zppqgn6s/
看到它用z-index
修复了;要查看它应该是什么样子,请取消注释第 34 行。
pseudo-element的边框低于child的原因:
关于为什么 pseudo-element (:before
) 的背景落后于 child (h1
) 的原始问题的答案可以在 BoltClock 的答案中找到 (您已在问题中链接)。 :before
pseudo-element 实际上插入在根 div
的内容之前(包括 h1
)。
下面是演示中使用的元素的一般结构:
#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 */
现在 based on the specs for the visual rendering layers,下面是发生的情况:
#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) */
根据层数可以看出(在行内注释中提供),h1
元素位于 #anim:before
上方(但在产生边框收缩效果的所有其他三个元素下方) .
解法:
唯一的解决办法是在 :before
元素之后绘制 child (h1
)。这可以通过执行以下任一操作来实现(但它们都需要设置 z-index
):
- 使用
z-index: -1
将h1
设置为position: relative
(使其落后于#anim:before
) - 将
z-index: 1
(或更高)设置为#anim:before
元素(使其高于h1
)
备用 Solutions/Approaches:
实际上,您不需要此特定动画的所有额外元素(从 top-left 和 bottom-right 交汇的边界)。它们可以使用单个 h1
元素本身来实现,我正在 post 这个答案来说明其中两种方法。虽然你没有要求其他方法,但我喜欢这种效果,它似乎是 post 这个答案的好地方。
通过使用 linear-gradient
背景图片:
在这种方法中,我们为边框的每一侧创建一个渐变(实际上只是一种纯色,因为它不会改变颜色),适当地放置它们,然后将大小从 0%
过渡到100%
。对于顶部和底部边框,X-axis 中的大小应在 hover
上从 0%
更改为 100%
,而对于左右边框,Y-axis 中的大小应从 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>
通过使用pseudo-elements:
这也可以使用 pseudo-elements 通过在 hover
上转换它们的高度和宽度来完成。您已经走上了正确的道路,但不需要额外的元素。
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>
即使在周围添加了额外的 div
元素(从代码片段中可以看出),这两种方法都有效。