记一次由::selection引起的小小bug

786 阅读3分钟

背景

最近做了个需求,在一个显示邮件详情的页面中可以选中邮件主体的文本内容,进行高亮划线,然后再将数据通过接口存储到数据库中。

设计同学给出的设计稿中,需要对高亮内容的样式进行修改: image.png

没怎么做过文本相关需求的我自然是直接百度一把梭,聪明的度娘告诉我用CSS中的::selection伪元素就可以实现啦。

并且幸运的是,刚好::selection可以修改的为数不多的属性中就包括了background-color,那真是美滋滋了yeah(可以不用加班了呢

前端高手.png

喜闻乐见出bug了

在度娘的指引下,我写下了第一版的代码:

::selection {
    background-color: yellow;
}

这样选中文本后,选中部分确实有了我们自定义的背景颜色。

但是页面中还有其他的元素,除了这部分内容,其他的都不需要高亮样式,怎么办呢?

我想了想,加个class限制一下呗,于是我又写下了第二版的代码:

.main-text ::selection {
    background-color: yellow;
}

本地测试下了,没啥问题;提测给测试同学了,测了几天,也没啥问题。

于是上线了。

上线之后我随手点开了一个线上的页面测试了下,不点不知道,一点吓一跳————喜闻乐见的出bug了。

ff77d6058b57c360ef8971fa7.jpg 真是脸上笑嘻嘻,心里mmp……

这是我预期的: image.png

然后这是我在线上看到的样式无效的: image.png 焦虑症本焦的我自然是受不了这种bug啦,为了下个迭代能够快乐地做新需求,不被遗留的bug拖住后腿,自然是要解决它滴。

分析

于是进行了一波分析。

上线后自然不止我一个人注意到了这个bug,测试和后端同学都发现了这个样式的bug。从后端同学的口中我得知了一个重要信息:

邮件主体有两种格式,一种是html内容,一种是纯文本内容

邮件详情主体内容是动态渲染的html。然而无论是开发还是测试过程中,我都默认主体内容就是html,所以根本不知道还有纯文本的内容。

html结构的主体内容是这样的:

<div class="main-text">
    <div id="defaultwrapper">
        <p style="font-size: 14pt">这是一段html格式的邮件详情</p>
    </div>
</div>

在这种结构下,使用后代选择器,是可以实现高亮样式的:

.main-text ::selection {
    background-color: yellow;
}

而对于纯文本的主体内容:

<div class="main-text">
    这里是纯文本的邮件详情
</div>

上述的后代选择器就是无效的。

解决

经过上面的分析,问题就很明了了,究其原因就是使用后代选择器无法命中纯文本的选区。

跑去瞅了眼MDN,发现官方文档就是很标准的伪元素用法:

.main-text::selection {
    background-color: yellow;
}

伪元素直接跟在选择器后面,直接作用于当前选择器的节点,于是纯文本内容的高亮样式也生效了。

那我们把两种情况兼容下呗,都加上,问题就解决了:

.main-text::selection,
.main-text ::selection
{
    background-color: yellow;
}

思考

改完bug后,我开始思考,为什么直接用了后代选择器,而不是常规的伪元素用法。

首先是开发测试过程中没有cover到所有的case,导致一部分内容没有测试到,出现了样式的bug;其次是开发时隐约记得第一次是用了伪元素的常规写法,好像没生效,然后就直接加了个空格,见到样式生效了就没想太多了 —— 于是最后翻车了。

所以说啊,干点啥都得过过脑子,事前预防总是比事后复盘成本低的~