问题
项目中一个弹框的关闭按钮,按钮有背景图片,文字使用缩进隐藏:
html
<style>
.modal-close {
width: 20px;
height: 20px;
background-image: xxx;
text-indent: 100%;
overflow: hidden;
}
</style>
<div class="modal">
<div class="modal-header">
<button class="modal-close" onclick="onClose()">关闭</button>
</div>
</div>
<script>
function onClose() {
console.log('关闭');
}
</script>
问题是什么呢?
点击没有效果。仔细观察,似乎是按钮右边一个区域无法点击,而左上的区域即使超出了元素范围也可以点击。
尝试
为什么 text-indent 使用值 100% 呢,因为用的 tailwindcss,一开始发现 100% 似乎好写一点,class="indent-[100%]"
。
MDN 中:
<percentage>
:Indentation is a <percentage>
of the containing block's width.
缩进包含容器宽度的百分比。理论上没问题啊,只要能隐藏文本。
使用 text-indent: -9999px;
:
css
.modal-close {
text-indent: -9999px;
}
可以解决问题。
不使用 button 元素:
html
<div class="modal-close" onclick="onClose()">关闭</div>
也可以解决问题。
或者根本不用写文字和使用 text-indent。
但是这个现象到底是什么原因导致的呢?
一个 demo
为了研究这个问题,给出一个具体的 demo:
红色按钮,靠右边大致红框的区域无法触发点击事件。
打开网页,打开控制台,打开 toggle device toolbar,点击第一个按钮,控制台输出 111,小心的把鼠标移动到按钮右侧的边缘附近,就会发现点击失效。而 div 元素没有此现象。
探究
Chrome 模拟移动设备
在探究的过程中,发现,只有在 Chrome 模拟移动设备中,才会出现这个问题,正常 PC 模式下没问题。按钮的任何区域都可以点击。
模拟移动设备似乎还有一个问题,Chrome 似乎为了方便移动端点击事件,给元素增加了一个点击范围,也就是说,即使超出了元素范围一点点,也是可以点击的。经过尝试,这个距离大概是 15px。
这里反映了一个同样的问题:html elements are picking click events outside their bounds
我搜了一下,却没有找到相关的说明(不知道什么原因)。却有很多 "Emulate Touch Events in Chrome" 的说明,找了半天,似乎当前 Chrome 已经没有了这个设置:
另外这里有个相关问题:Wrong clickable area of a button on mobile
以上,只是说明 Chrome 模拟移动设备的这个特性。
overflow: hidden
当删除 overflow: hidden;
时,是没有问题的。说明是文本缩进
和超出隐藏
共同影响了点击范围。
在我们的 demo 中,text-indent 和 overflow 让文本的一部分隐藏了,一部分仍然在元素范围中。
元素的点击范围应该只是元素本身?
还是说 button 比较特殊,它的点击和文本有关系?
不同大小的元素比较
为了便于观察,扩大点击的范围,同时重置了一些 button 的默认样式:
html
<style>
.close {
text-align: left;
padding: 0;
padding-block: 0;
padding-inline: 0;
writing-mode: horizontal-tb;
word-wrap: break-word;
margin: 15px;
border: 1px solid red;
width: 300px;
height: 300px;
text-indent: 300px;
/* text-indent: -9999px; */
overflow: hidden;
}
</style>
<div class="close-wrapper">
<button class="close" onclick="onClose()">关闭</button>
</div>
放大元素之后发现,不可点击的范围只是右边的一个小区域。
隐藏和扩大的可点击范围相结合
会发现,整个绿色的区域基本上都可以点击,除了大概蓝色的区域。不确定这个区域的具体范围,但是这个区域不就是缩进的文本周围吗??
就是说,"关"字虽然被隐藏了,就不能响应点击事件了,但是它又影响了什么?
经过反复测试,text-indent: 298px;
text-indent: 295px;
text-indent: 320px;
当 text-indent: 298px;
:
蓝色区域意料中的不能点击,但是黄色区域有一个小小的区域可以点击!
为了说明,特地录了个视频(结果还要上传西瓜视频):
反复尝试之后,似乎终于发现了问题所在:
- Chrome 模拟移动设备为元素增加了点击范围,大概 15px;
- 所以 button 元素周围 15px 可点击;
text-overflow: hidden;
隐藏文本,隐藏的部分当然不可点击,即使在 button 周围可点击范围;- 隐藏的部分也有一个扩大点击范围,因为隐藏的部分不可点击,它的扩大范围也不可点击,即使在元素本身的可点击范围之内;
- 点击和不可点击(overflow-hidden)相互叠加之后,不可点击范围覆盖点击范围;
因此隐藏的文本"关"有一个扩大的不可点击范围,覆盖在了 button 按钮之上,所以造成了这种现象。
当 text-indent: 320px;
:
为了验证这种想法,当 text-indent: 320px;
时,应该 button 右侧大概 5px 可以点击。当当 text-indent: 315px;
时,应该红框之间都不能点击。
但是在实际测的过程,还是有些不合理。当然扩大的点击范围值只是我的猜测,而且,这一切,都是我的假设和推理。
最后
虽然想要搞清楚,真实的实现原理还是不知道,苦于这方面的文档不知道怎么找。希望有看到和了解的,可以分享一下~