text-indent 导致点击事件失效?

问题

项目中一个弹框的关闭按钮,按钮有背景图片,文字使用缩进隐藏:

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:

codepen.io/zangbianxue...

红色按钮,靠右边大致红框的区域无法触发点击事件。

打开网页,打开控制台,打开 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;时,应该红框之间都不能点击。

但是在实际测的过程,还是有些不合理。当然扩大的点击范围值只是我的猜测,而且,这一切,都是我的假设和推理。

最后

虽然想要搞清楚,真实的实现原理还是不知道,苦于这方面的文档不知道怎么找。希望有看到和了解的,可以分享一下~

相关推荐
Hello_WOAIAI1 小时前
批量将 Word 文件转换为 HTML:Python 实现指南
python·html·word
sanguine__1 小时前
APIs-day2
javascript·css·css3
LUwantAC2 小时前
CSS(一):选择器
前端·css
Simaoya4 小时前
【vue】圆环呼吸灯闪烁效果(模拟扭蛋机出口处灯光)
javascript·css·vue.js
GISer_Jing4 小时前
2025年前端面试热门题目——HTML|CSS|Javascript|TS知识
前端·javascript·面试·html
坐望云起4 小时前
什么是WebAssembly?怎么使用?
html·web·wasm·js
LOVE️YOU5 小时前
HTML&CSS&JavaScript&DOM 之间的关系?
前端·javascript·css·html
NoneCoder6 小时前
CSS系列(26)-- 动画性能优化详解
前端·css·性能优化
萧寂1736 小时前
ios底部小横条高度适配
css
好开心336 小时前
axios的使用
开发语言·前端·javascript·前端框架·html