2

CSS 数学函数与容器查询实现不定宽文本溢出跑马灯效果 - ChokCoco

 1 year ago
source link: https://www.cnblogs.com/coco1s/p/17170627.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在许久之前,曾经写过这样一篇文章 -- 不定宽溢出文本适配滚动。我们实现了这样一种效果:

  1. 文本内容不超过容器宽度,正常展示
  2. 文本内容超过容器的情况,内容可以进行跑马灯来回滚动展示

像是这样:

6e62e7bff69d4fbba04a29d16374e94a~tplv-k3u1fbpfcp-watermark.image?

但是,之前的方案,有一个很明显的缺点,如果我们事先知道了容器的宽度,那么没问题,但是如果没法确定容器的宽度,也就文本宽度不确定,容器宽度也不确定的话,那么整个效果会有一点瑕疵

瑕疵在于,当时的 CSS 技术,其实没法判断当前文本内容长度是否超过了其容器宽度,导致即便文本没有没有超长,Hover 上去也会进行一个来回滚动,像是这样:

6c9e2a923dba491d994c4aca4e9fccdf~tplv-k3u1fbpfcp-watermark.image?

容器查询 cqw 和 CSS 数学函数 max

背景描述大概是这样,感兴趣的同学,可以简单翻看一下上午提到的文章 -- 不定宽溢出文本适配滚动

到今天,我们重新审视这个问题。看看到今天,我们可以如何更加简单便捷的解决这个问题!

首先,我们的问题其实可以抽象成:

  1. 判断文本宽度与容器宽度的大小差异,文本宽度是否大于容器宽度
  2. 如果超出,则设置来回位移动画,位移的幅度为容器宽度与文本宽度的差值

那么,我们一步一步来。

假设我们的 HTML 结构如下:

<div class="marquee">
	<span>Lorem ipsum dolor sit amet elit. Animi, aliquid.<span>
</div>

其中,div 为容器,span 为文本内容。同时,我们利用容器查询,设置父容器 marquee 为容器查询的容器,并且将基于容器的inline-size 维度。

.marquee {
	white-space: nowrap;
	container-type: inline-size;
}

继续,我们如何能够在 span 中得知,当前 span 的内容长度与父容器宽度谁比较大呢?

在之前,这是很难办到的,但是现在,我们有了 容器查询 后,可以靠容器查询单位 cqw 完成。

首先,什么是容器查询?容器查询它给予了 CSS,在不改变浏览器视口宽度的前提下,只是根据容器的宽度变化,对布局做成调整的能力。

对容器查询想了解更多的,可以戳:新时代布局新特性 -- 容器查询

容器查询带来了很多新的单位,其中有:

  • cqw 容器查询宽度(Container Query Width)占比。1cqw 等于容器宽度的 1%。假设容器宽度是 1000px,则此时 1cqw 对应的计算值就是 10px。
  • cqh 容器查询高度(Container Query Height)占比。1cqh 等于容器高度的 1%。
  • cqi 表示容器查询内联方向尺寸(Container Query Inline-Size)占比。这个是逻辑属性单位,默认情况下等同于 cqw
  • cqb 容器查询块级方向尺寸(Container Query Block-Size)占比。同上,默认情况下等同于 cqh
  • cqmin 容器查询较小尺寸的(Container Query Min)占比。取 cqw 和 cqh 中较小的一个
  • cqmax 表示容器查询较大尺寸的(Container Query Min)占比。取 cqw 和 cqh 中较大的一个

本文,我们会运用到其中的 cqw,1cqw 等于容器宽度的 1%。那么,当前容器的宽度,其实就是 100 cqw。

  1. width: 100% ,对于 span 行内元素而言,其文本长度就是其整个的宽度,100% 代表的就是文本内容的长度
  2. width: 100cqw 表示的是设置了容器查询的 .marquee 的宽度(也就是父容器的宽度)

OK,有了 100%100cqw 怎么比较他们谁大谁小呢?其实我们的关键不是谁大谁小,而是:

  1. 如果当前容器的宽度(也就是文本宽度)大于父容器宽度,需要得到一个动画位置值
  2. 如果当前容器的宽度(也就是文本宽度)小于父容器宽度,无需动画,也就是动画位移值为 0

那么,我们的核心就变成了,0 与两个宽度差值的比较。刚好,CSS 中提供了比较大小数学函数 max()min()

关于 CSS 数学函数,你可以参考我的这篇文章 -- 现代 CSS 解决方案:CSS 数学函数

铺垫了这么久,最终,我们得到最为核心的一行代码:

max(100% - 100cqw, 0px)

当然,换一种思维,使用 min() 也是可以的:

min(100cqw - 100%, 0px)

如果 span 内容长度,大于容器宽度,也就是 100% - 100cqw 大于 0px,那么其实也就得到了跑马灯效果应该位移的距离。

我们顺便也就将整个效果的代码写完了,完整的代码:

.marquee {
	overflow: hidden;
	white-space: nowrap;
	width: 200px;
	resize: horizontal;
	container-type: inline-size;
}
.marquee span {
      animation: marquee 3s linear infinite both alternate;
}
@keyframes marquee {
	to {
		transform: translateX(min(100cqw - 100%, 0px));
	}
}

效果如下:

b39ca4ed8e2f4a51bf4d373a5c8096b5~tplv-k3u1fbpfcp-watermark.image?

这样,到今天,我们可以轻易的实现:

  1. 文本内容不超过容器宽度,正常展示
  2. 文本内容超过容器的情况,内容可以进行跑马灯来回滚动展示

也就是如下的效果:

3f1b55aced98400ab5e144e28f17aa30~tplv-k3u1fbpfcp-watermark.image?

完整的代码,你可以戳这里:Pure CSS Marquee

当然,硬要说的话,本方案还是存在一个缺陷,就是动画的时长是固定的,没法根据内容的长短响应式的进行适配。可能更适合文本内容相差不大的场景使用。

本案例 DEMO 由日服第一切图仔佐子哥倾情贡献。好了,本文到此结束,希望本文对你有所帮助 😃

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

想 Get 到最有意思的 CSS 资讯,千万不要错过我的 iCSS 公众号 😄 :

image

如果觉得文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK