今天有一位掘友问我一个问题:
文字不换行,超出容器,怎么滚动显示?
比如下图中,有的列表项的文字短,有的文字长。
需求是:希望文字长的部分能通过动画滚动显示。
我的第一反应是用纯 CSS 做不了。
但是后来冥思苦想一阵子,竟然做到了!
其中涉及了一些有趣 CSS 知识点,在这里分享一下。
1. 如何让文字溢出容器?
work-break 属性是用来处理文字如何换行的,这里使用了不太常用的值 keep-all,表示只能在半角空格或连字符处换行。因为文本里没有这两种特殊字符,因此文本溢出了。
2. 如何让元素宽度随内容而定?
指定了 width 值为 fit-content,它是 CSS3 新的属性值,表示宽度与内容一致。除了 fit-content 之外,还有 max-content、 min-content 和 fill-available。具体含义如有不清楚的,请 google 之。3. 动起来?
这里我们使用关键帧动画,使其滚动起来先。关键帧定义如下:
@keyframes move {
0%{
transform: translateX(0px);
}
100%{
transform: translateX(-100%);
}
}
复制代码
具体效果是:
这里可以看出,我们在第 2 步设置元素的宽度为文字自身宽度的原因是,我们动画移动元素是相对于自身的宽度的。
目前效果还是比较粗糙,比如整体移动 100%,我们希望文字尾部与 div 容器内容盒右边卡齐:
由于我们知道父元素的 width 值的(这里是 100px),使用 calc() 就能轻松做到:
@keyframes move {
0%{
transform: translateX(0px);
}
100%{
transform: translateX(calc(-100% + 100px));
}
}
复制代码
同时再让父元素隐藏溢出部分,效果如下:
4. 如何让短文字不动?
总体上实现了滚动的效果,但是掘友的需求是,长文字滚动,短文字不动的。
说实话,我为这个需求苦恼了小半天。。。后来,直拍大腿:设置 p 的最小宽度呀!
5. 最后一步,优化动画!
现在的效果,怎么说呢,滚动得太让人闹心,可以让动画滚动开始和结束前,稍微停顿一会儿:
@keyframes move {
0%, 20%{
transform: translateX(0px);
}
80%,100%{
transform: translateX(calc(-100% + 100px));
}
}
复制代码
前 20% 保持效果不变,后 20% 亦是如此:
还有一个问题,这里我们的动画时间是 3s,我们可以根据其文字长度来设置时间。即,更长的文字需要更长的时间。
但此处,我不知道用 CSS 怎么办,尝试了几次,最终还是放弃了,使用了一小段 JS。
[...document.querySelectorAll('p')].forEach(p => {
p.style.setProperty('--duration', p.offsetWidth / 100 + 's');
})
复制代码
其中 --duration 是 CSS 变量(不熟悉的同学请 google 之),p 标签的 animation 属性也需要相应变为:
animation: move var(--duration) linear infinite;
复制代码
最后,完整代码和完整效果,请看codepen.io/laoyao/pen/…。
本文完。
谢谢阅读!
???