背景
最近做了个需求,在一个显示邮件详情的页面中可以选中邮件主体的文本内容,进行高亮划线,然后再将数据通过接口存储到数据库中。
设计同学给出的设计稿中,需要对高亮内容的样式进行修改:
没怎么做过文本相关需求的我自然是直接百度一把梭,聪明的度娘告诉我用CSS中的::selection
伪元素就可以实现啦。
并且幸运的是,刚好::selection
可以修改的为数不多的属性中就包括了background-color
,那真是美滋滋了yeah(可以不用加班了呢
喜闻乐见出bug了
在度娘的指引下,我写下了第一版的代码:
::selection {
background-color: yellow;
}
这样选中文本后,选中部分确实有了我们自定义的背景颜色。
但是页面中还有其他的元素,除了这部分内容,其他的都不需要高亮样式,怎么办呢?
我想了想,加个class限制一下呗,于是我又写下了第二版的代码:
.main-text ::selection {
background-color: yellow;
}
本地测试下了,没啥问题;提测给测试同学了,测了几天,也没啥问题。
于是上线了。
上线之后我随手点开了一个线上的页面测试了下,不点不知道,一点吓一跳————喜闻乐见的出bug了。
真是脸上笑嘻嘻,心里mmp……
这是我预期的:
然后这是我在线上看到的样式无效的:
焦虑症本焦的我自然是受不了这种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;其次是开发时隐约记得第一次是用了伪元素的常规写法,好像没生效,然后就直接加了个空格,见到样式生效了就没想太多了 —— 于是最后翻车了。
所以说啊,干点啥都得过过脑子,事前预防总是比事后复盘成本低的~