前端 > 知识 > 有关伪元素的思考.md

有关伪元素的思考

在Github编辑

情景演绎

当时,我看到一个链接,很快啊,就点进去了,然后无意中发现他们的标题元素是根据文本的宽度下方有一个浅色的条纹,当时觉得这不停简单的吗,就是一个h2元素里面包一个行内块元素吗,有啥稀奇的。为了验证下猜想,于是果断按了F12,一检查,根本没有子元素,就是一个元素加上两个伪元素实现的,当时也没猜透是怎么实现的,现在经过严谨的分析,开始本文的解说。

demo
查看源码

<style>
    h2 {
        display: inline;
        width: auto;
        background: linear-gradient(to bottom, transparent 70%, rgba(26, 188, 156, .3) 0) no-repeat;
    }
    h2::before {
        content: "";
        margin-top: 1.2em;
        display: block;
    }
    h2::after {
        content: "";
        margin-top: 1.2em;
        display: block;
    }
</style>
<div>上部元素</div>
<h2>
    标题
</h2>
<div>下部元素</div>

大家可以查看框架源码,可以真切的看到就是只有一个元素。

详细重现

为了能够更加深入整个话题,我重新设计了一个Demo。

demo
查看源码

<style>
        .red{
            background: red;
            display: inline;
        }

        .red::before{
            content: "";
            display: block;
            margin-top: 25px;
        }

        .red::after{
            content: "";
            display: block;
            margin-bottom: 15px;
        }
    </style>
    <div id="a">aaaaaa</div>
    <div id="output1"></div>
    
    <div class="top">top</div>
    <div class="red">aaaaaa</div>
    <div class="bottom">bottom</div>
    <div id="output2"></div>
    <script>
        document.getElementById("output1").innerText = `普通元素高度为:${document.querySelector('#a').offsetHeight}px`
        document.getElementById("output2").innerText = `中间元素的高度为:${document.querySelector('.red').offsetHeight}px`
    </script>

可以看到,中间的元素的高度等于21+15=36px,相当于aaaaaa本身的高度加上after伪元素margin高度。但是为啥不加上before伪元素的margin高度呢?实际上,不是不加,如果将css改成这样,那么可以看到元素就是61px了。

demo
查看源码

<style>
.red{
    background: red;
    overflow: hidden;
}

.red::before{
    content: "";
    display: block;
    margin-top: 25px;
}

.red::after{
    content: "";
    display: block;
    margin-bottom: 15px;
}
</style>
<div id="a">aaaaaa</div>
<div id="output1"></div>
<div class="top">top</div>
<div class="red">aaaaaa</div>
<div class="bottom">bottom</div>
<div id="output2"></div>
<script>
    document.getElementById("output1").innerText = `普通元素高度为:${document.querySelector('#a').offsetHeight}px`
    document.getElementById("output2").innerText = `中间元素的高度为:${document.querySelector('.red').offsetHeight}px`
</script>

由此,可以推断出,伪元素实际是如下结构:

<div>
    ::before
    text
    ::after
</div>

=>

<div>
    <div>before content<div>
    text
    <div>after content<div>
</div>

这种结构刚好与上面的情况符合:

  • before margin的高度没有计算上。
    这是由于margin的合并造成的,第一个元素如果存在margin-top,会把整个父元素也顶下来,解决办法是触发BFC即可。关于margin合并,可以看这篇文章
  • 为啥要注释display: inline;
    因为不变的话就会变成如下结构。但行内元素是不能嵌套块状元素的,否则块状元素会失去其特性,这点后面分析出来在写一篇文章。
    <span>
        <div>before content<div>
        text
        <div>after content<div>
    </span>
© 2022 NPMRUN. All rights reserved.

Built with ♥ by pure-blog