纯 CSS 检测文本是否溢出

server/2024/11/15 4:44:25/

介绍一个CSS检测文本溢出的小技巧。

一直以来,CSS 都无法很好的检测出一段文本是否溢出。但这又是一个非常普遍的需求,比如多行文本展开,展开按钮只有在文本溢出的时候才出现

image-20240112160428979

由于无法直接CSS判断,这使得不得不借助 JavaScript或者CSS奇技淫巧来实现,之前提到了不下于3种不同的思路来解决这个问题,在以下这些文章中都有提到

  • dom 获取不到?试试 CSS 动画监听元素渲染吧
  • 尝试借助CSS @container实现多行文本展开收起
  • 突发奇想!借助CSS自定义彩色字体来实现多行文本展开收起
  • CSS 实现多行文本“展开收起”
  • CSS 文本超出提示效果

有兴趣的可以回顾一下,还是挺有意思的

时代在进步,CSS也在不断推出新特性,现在,CSS终于可以完美的解决这个问题了,也就是可以准确无误地判断文本是否溢出了,一起看看吧

一、CSS 滚动驱动动画

要实现文本溢出检测,需要用到两个新特性

  1. CSS 滚动驱动动画
  2. CSS 样式查询

为什么是这两个呢?听我慢慢分析。

首先我们想一想,在 JS中是如何判断是否溢出的?很简单

 

js

复制代码

dom.scrollHeight > dom.offsetHeight;

其实也就是表示这个容器是“可滚动”的,因为滚动高度超过了可视高度

image-20240313193828526

回到 CSS 这里,有没有办法区分呢?答案就是CSS滚动驱动动画

关于 CSS 滚动驱动动画,可以先回顾这篇文章:CSS 滚动驱动动画终于正式支持了~ 

假设有这样一个布局,就两段文本

 

html

复制代码

<div class="txt"> 欢迎关注前端侦探,这里有一些有趣的、你可能不知道的HTML、CSS、JS小技巧技巧。欢迎关注前端侦探,这里有一些有趣的、你可能不知道的HTML、CSS、JS小技巧技巧。欢迎关注前端侦探,这里有一些有趣的、你可能不知道的HTML、CSS、JS小技巧技巧。 </div> <div class="txt"> 欢迎关注前端侦探 </div>

稍微修饰一下,给个高度,让文本可以超出滚动

 

css

复制代码

.txt{ height: 4em; padding: 8px; outline: 1px dashed #9747FF; font-family: cursive; border-radius: 4px; }

效果如下

image-20240313194817857

左边是可以滚动的,右边是不能滚动的。

现在,我们给左边加一个滚动驱动动画,在滚动时慢慢改变文本的颜色

 

css

复制代码

.txt{ animation: check 1s; animation-timeline: scroll(self); } @keyframes check{ to { color: #9747FF; } }

注意这个scroll(self)self表示监听自身滚动,默认是最近的祖先滚动容器,效果是这样的

Kapture 2024-03-13 at 19.55.56

可以看到随着滚动,左边文本的颜色也慢慢变化了

接着激进一点,我们在动画中把起始点都设置成一样,这样还没开始滚动就自动变色了

 

css

复制代码

@keyframes check{ from,to { /*动画起始点设置成相同*/ color: #9747FF; } }

效果如下

image-20240313195930835

这样即使还没开始滚动,也能提前知道是否可滚动了

然后,我们可以设置超出隐藏,也就是让滚动容器“不能滚动”

 

css

复制代码

.txt{ overflow: hidden; }

效果如下

image-20240313195930835

也就是说这种情况下,CSS滚动驱动动画仍然可以被触发。尝试了一下,只要不是overflow:visibleCSS都认为是“可滚动”的,即“溢出”状态。

最后,我们将文本设置成超出显示省略号

 

css

复制代码

.txt{ display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }

效果如下

image-20240313200745441

是不是有点能区分文本是否溢出了?至少目前从文本颜色可以很好判断

当然,仅仅这样是不够,还需要更加自由,比如在超出时可以控制其他标签的状态,这就需要用到 CSS 样式查询了

二、CSS 样式查询

下面介绍一下CSS样式查询。

@container - CSS: Cascading Style Sheets | MDN (mozilla.org)

CSS 样式查询是容器查询的一部分,从名称也可以看出,它可以查询元素的样式,进而设置额外的样式。

image-20240313203627795

比如,我们要查询颜色为红色的容器,然后给子元素设置背景色为黑色,可以这样

 

html

复制代码

<style> div{ color:red; } @container style(color: red) { p { background: black; } } </style> <div> <p> </p> </div>

有人可能会有疑问,为啥要设置子元素,直接设置本身不好吗?其实是为了避免冲突,假设查询到了color:red,然后你又设置了color:yellow,那浏览器该如何渲染呢?有点死循环了。所以为了避免这种情况,所有容器查询都只能设置子元素样式。

不过这种写法目前还不支持,仅支持CSS变量的写法,类似于这样

 

html

复制代码

<style> div{ --color:red; } @container style(--color: red) { p { background: black; } } </style> <div> <p> </p> </div>

回到前面的例子,我们可以给文本加一个CSS变量,就叫做 --trunc吧,表示截断

 

css

复制代码

.txt{ --trunc: false; }

然后在滚动驱动动画中改变这个变量

 

css

复制代码

@keyframes check{ from,to { /*动画起始点设置成相同*/ color: #9747FF; --trunc: true; } }

这样一来,滚动驱动动画执行的时候,这个变量也被赋值了。

最后我们就可以查询这个样式,给子元素设置样式了,这里我们就用伪元素代替

 

css

复制代码

@container style(--trunc: true) { .txt::after{ content: ''; position: absolute; inset: 2px; border: 1px solid red; } }

这段代码表示当查询到--trunc: true的条件时,设置相应的样式,这里是画了一个红色的边框,效果如下

image-20240313203030526

是不是非常容易?

你也可以查看以下在线链接(注意兼容性,需要 Chrome 115+,以下相同):

  • CSS animation-timeline + @ container style (codepen.io)

有了这个作为区分,可做的事情就比较多了,下面来看几个例子

三、CSS 多行文本展开收起

这已经是第四次用不同方式来实现这个效果了,前几次的实现可以参考文章开头部分。

这次来看新的实现方式。

首先还是把之前的结构拿过来,这些结构是为了实现右下角的“展开”按钮必不可少的,如果不太清楚是如何布局的,建议好好回顾一下之前这篇文章:CSS 实现多行文本“展开收起”

html

复制代码

<div class="text-wrap"> <div class="text-content"> <label class="expand"><input type="checkbox" hidden></label> HTML、CSS、JS小技巧技巧。 </div> </div>

相关 CSS 如下

css

复制代码

.text-wrap{ display: flex; position: relative; width: 300px; padding: 8px; outline: 1px dashed #9747FF; border-radius: 4px; line-height: 1.5; text-align: justify; font-family: cursive; } .expand{ font-size: 80%; padding: .2em .5em; background-color: #9747FF; color: #fff; border-radius: 4px; cursor: pointer; float: right; clear: both; } .expand::after{ content: '展开'; } .text-content{ display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; } .text-content::before{ content: ''; float: right; height: calc(100% - 24px); } .text-wrap:has(:checked) .text-content{ -webkit-line-clamp: 999; } .text-wrap:has(:checked) .expand::after{ content: '收起'; }

这时的效果是这样的

image-20240314152220054

通过上一节的原理,我们通过滚动驱动动画来判断是否溢出,并使用CSS变量作为标识,然后利用样式查询来控制展开按钮的显示状态,关键实现如下

css

复制代码

.expand{ /**/ display: none; } .text-content{ --trunc: false; animation: check 1s; animation-timeline: scroll(self); } @keyframes check{ from,to { --trunc: true; } } @container style(--trunc: true) { .expand{ display: initial; } }

展开按钮默认是隐藏的,这样只有在文本溢出的时候才出现,效果如下

效果出来了,不过在点击展开后按钮也跟着消失了。这是因为展开后,CSS检测出这时没有溢出,所以样式查询里的语句就不生效了,自然也就回到了之前的隐藏状态。

要解决这个问题也很简单,在展开的时候始终显示按钮就行了,用:checked可以判断是否展开

css

复制代码

.text-wrap:has(:checked) .expand{ display: initial; }

这样就正常了,完美!

CSS方式的好处是监控是实时的,比如手动改变容器的宽度,也会自动显示或者隐藏这个按钮

完整demo可以查看以下在线链接( Chrome 115+):

  • CSS container style expand (codepen.io)

四、CSS 文本超出时显示 tooltips

还有一个比较常见的需求,就是希望在文本出现省略号时,鼠标hovertooltips提示,就像这样

原理和上面几乎一致,我们一步步来看

首先还是结构,没什么特别的

 

html

复制代码

<div class="txt" data-title="这是一段可以自动出现tooltip的文本"> 这是一段可以自动出现tooltip的文本 </div>

这里加了一个data-title,是用来显示气泡的,通过伪元素content获取属性内容

 

css

复制代码

.txt{ overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 8px; outline: 1px dashed #9747FF; font-family: cursive; border-radius: 4px; } .txt::after{ content: attr(data-title); position: absolute; top: 0; width: fit-content; left: 50%; margin: auto; transform: translate(-50%,-100%); background-color: rgba(0,0,0,.6); padding: .3em 1em; border-radius: 4px; color: #fff; opacity: 0; visibility: hidden; transition: .2s .1s; }

效果如下

image-20240314160737886

目前是没有任何提示的。

下面加上CSS溢出检测,在检测到溢出时hover生效。仍然是相同的代码,添加一个滚动驱动动画,然后样式查询

 

css

复制代码

.txt{ --trunc: false; animation: check 1s; animation-timeline: scroll(x self); } @keyframes check{ from,to { --trunc: true; } } @container style(--trunc: true) { .txt:hover::after{ opacity: 1; visibility: visible; } }

注意,这里的scroll(x self),加了一个x,因为这时的文本是横向溢出的,所以需要加上滚动驱动轴(默认是垂直方向)

另外,由于超出隐藏,所以tooltip需要一个新的父级,不然就被裁掉了

 

html

复制代码

<div class="wrap"> <div class="txt" data-title="这是一段可以自动出现tooltip的文本"> 这是一段可以自动出现tooltip的文本 </div> </div>

 

css

复制代码

.wrap{ position: relative; }

这样就能实现文本超出时显示 tooltips

完整demo可以查看以下在线链接( Chrome 115+):

  • CSS container style tooltip (codepen.io)

五、最后总结一下

CSS 就是这么神奇,将两个几乎不相关的特性组合起来,就能实现完全不一样的功能,这可是在其他语言中做不到的,简单回顾一下CSS检测代码

css

复制代码

.content{ --trunc: false; animation: check 1s; animation-timeline: scroll(x self); /*注意溢出方向*/ } @keyframes check{ from,to { --trunc: true; /*滚动驱动动画*/ } } /*查询溢出状态*/ @container style(--trunc: true) { }

是不是非常容易,几乎是无侵入式的,下面总结一下本文重点

  1. 要实现文本溢出检测,需要用到两个新特性,CSS滚动驱动动画和CSS样式查询
  2. CSS滚动驱动动画可以检测出容器是否可滚动,也就是溢出,即使是在超出隐藏的情况下
  3. CSS样式查询可以查询到CSS变量的变化,从而设置不同的样式
  4. 借助CSS滚动驱动动画和CSS样式查询,可以很轻松的实现文本溢出检测
  5. 两个实例:CSS多行文本展开收起和CSS文本超出时显示 tooltips

当然除了以上一些案例,还可以做的事情很多,比如以前有写一篇判断指定高度后就显示折叠按钮,也可以用这种方式来实现,几乎所有与溢出相关的交互都可以纯CSS完成。

至于兼容性,目前仅支持 chrome 115+,还是需要多等等,多多关注,说不定哪一天就能用上了呢,比如5年前推出的CSS scroll snap,现在几乎可以愉快使用了,再也无需swiper.js这样的库了。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发 ❤❤❤

作者:XboxYan
链接:https://juejin.cn/post/7347221074704777226
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


http://www.ppmy.cn/server/38145.html

相关文章

视频号创作者分成4.0,软件无脑原创,轻松过分成计划,日入600+

详情介绍 今天给大家带来的项目是《视频号创作者分成4.0&#xff0c;软件无脑原创&#xff0c;轻松过分成计划&#xff0c;日入600》

QT 客户端软件开发

QT 是一种功能强大且灵活的跨平台应用程序开发框架&#xff0c;但也存在一些技术难点&#xff0c;需要开发者仔细考虑和克服。以下是一些常见的 QT 软件开发的技术难点。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1. 跨平台兼容性…

美易官方:1929年要重演?传奇投资者再发美股暴跌警告

近年来&#xff0c;全球经济和金融市场的波动不断加剧&#xff0c;使得投资者们倍感焦虑。在这样的背景下&#xff0c;一些传奇投资者的言论和预测备受关注。最近&#xff0c;一位传奇投资者再次发出警告&#xff0c;称1929年的股市崩盘可能会重演&#xff0c;这引发了市场的广…

golang中的继承和组合的区别

go语言中的继承 指的是一个结构体中采用匿名的方式包含另外一个结构体 这个就叫做继承&#xff0c; 注意这里的匿名 组合 一个结构体用命名的方式包含另外一个结构体&#xff0c;这个就叫做组合 继承代码示例 type A struct {Name stringAge int}type B struct {Addr string…

Leecode42:接雨水

第一反应是按照高低这个思路来求解&#xff0c;因为可以把盛雨水的容器想成是从左往右的&#xff0c;遇到一个沟就存一点雨水。 这个思路 看了下题解&#xff0c;发现自己的思路其实没问题&#xff0c;确实是按照最高最低来求&#xff0c;但是这个地方太复杂了求的&#xff0c…

线程理论篇1

本章问题&#xff1a;什么是线程?线程的使用场景&#xff1f;什么是线程池&#xff1f;线程池是如何工作的&#xff1f;线程池共享了哪些资源?线程安全代码怎么写&#xff1f;什么是线程安全? 什么是线程&#xff1f; 线程是为了提高进程的效率。进程的地址空间中保存了cpu…

【自动驾驶|毫米波雷达】卡尔曼滤波

目录 一. 滤波器分类 二.卡尔曼滤波&#xff08;Kalman Filter&#xff09;原理 &#xff08;1&#xff09;定性理解 &#xff08;2&#xff09;定量推导 1. 预测阶段 2. 更新阶段 3. 卡尔曼增益 1&#xff09;卡尔曼增益 2&#xff09;如何理解卡尔曼增益&#xff1f; 三…

【MySQL】6.强化数据防线:MySQL安全机制的配置与应用

数据库作为企业数据的核心存储地&#xff0c;其安全性直接关系到企业的命脉。MySQL&#xff0c;作为广泛使用的开源数据库管理系统&#xff0c;提供了一套全面安全机制来保护数据免受未授权访问和各种潜在威胁。本文将深入探讨MySQL安全机制的组成要素、实际应用以及它们在保障…