写一个文字水平滚动跑马灯效果

最近的一个页面需要一个文字水平滚动的效果,效果如图所示:


文字水平滚动.gif

本来想在网上直接找代码一把梭,但发现现有代码都是用的 jQuery + animation,不符合项目的技术栈,就想干脆自己实现一个。最终用了18行代码实现了上面的效果。

原理

具体原理跟轮播图类似,把包裹文字的元素复制多一个出来,当第一个元素滚动到看不见的时候,把第一个元素重新插到尾部,因为两个元素是紧挨着的,第一个元素滚动到看不见的一瞬间,第二个元素也已经到了开始的位置,所以肉眼看不出来元素插入的过程。最终实现了滚动效果。

实现

HTML
<div class="scrollX">
     <p class="scrollTxt">窗前明月光,疑是地上霜,举头望明月,低头思故乡</p>
</div>

第一步,拿到<p>标签并复制,插入到父容器中:

const domScroll = document.querySelector('.scrollTxt');
const cloneNode = document.querySelector('.scrollTxt').cloneNode(true);
domScroll.parentNode.appendChild(cloneNode);

此时的HTML标签就变成了:

<div class="scrollX">
     <p class="scrollTxt">窗前明月光,疑是地上霜,举头望明月,低头思故乡</p>
     <p class="scrollTxt">窗前明月光,疑是地上霜,举头望明月,低头思故乡</p>
</div>

这样有两个问题:
①父元素随着子元素的增大而增大,需要给父元素一个固定的宽度,且隐藏溢出的部分;
②两个<p>标签不在同一行,需要让两个元素在同一行才有水平滚动的效果。

针对第一个问题,给 scrollX一个固定宽度加 overflow: hidden就可以解决。
第二个问题,我是用了 flex布局,在父元素定义 display: flex就让两个子元素在了同一个水平线上。最终的CSS:

.scrollX {
   display: flex;
   height: 100%;
   width: 500px;
   overflow: hidden;

  p {
    height: 100%;
    lex-shrink: 0;
    padding-right: 20px;
    white-space: nowrap;
   }
 }
让元素动起来

让元素滚动有两种方法
①将元素设置为 position: absolute并控制元素的left属性,让元素往左移动。
②使用transform并控制translateX()让元素往左移动。

没吃过猪肉也见过猪跑,没写过动画的人,也知道第二种方法的性能会比第一种要好。为什么好呢,我们放在最后面总结,先把动画实现起来~

我们要让元素往左滚,那么要滚多远呢?就是元素本身的宽度,当元素滚动的距离超过自身宽度时,进行元素插入尾部的操作:

const domScroll2 = document.querySelectorAll('.scrollTxt')[1];
let width = domScroll2.getAttribute('width');
const animation = () => {
  if (width > -100) {
    domScroll.style = `transform: translateX(${width}%)`;
    domScroll2.style = `transform: translateX(${width}%)`;
    width -= 1;
  } else {
    domScroll.parentNode.appendChild(domScroll);
    width = 0;
  }
  setTimeout(animation, 100);    // 使用setTimeout 嵌套代替 setInterval
};
animation();

代码写到这里,动画就可以动起来了。

这里有一个实现的细节是,setTimeout 的嵌套代替setInterval,原因是 setInterval 的运行机制并不是真实的“每隔XX秒后调用指定的函数”,因为setInterval并不会将指定函数需要执行的时间考虑在内。比如我们用setInterval每隔100ms调用一次函数A,如果A本身的执行需要95ms,那么A执行完,经过至少5ms就会马上被调用,所以为了保证每次执行都有一定的间隔,要使用 setTimeout代替setInterval

在查资料的过程中,想起来还有requestAnimationFrame这个API,这个API相当于一个时间被固定为 浏览器绘制频率(一般为16ms一次) 的setTimeout,但它是setTimeout的改进版,浏览器会为requestAnimationFrame做优化,以每一次浏览器的重绘为间隔执行动画。而且,当浏览器不在当前 tab 的时候,requestAnimationFrame调用的动画会停止。会根据浏览器绘制频率调整刷新时机。

GPU渲染导致的动画中字体模糊的问题

一开始实现的时候考虑过用 transition 来实现运动效果,发现运动过程中字体会变得模糊,而且不仅是动画中的字体会模糊,连页面上的其他字体也变得模糊起来。在实现了动画后考虑过使用will-change优化动画,发现也存在同样的问题(区别是will-change只会导致运动的字体变模糊)。
一番查找发现文字模糊是因为浏览器启用了GPU渲染,而GPU渲染不具备CPU渲染的次像素抗锯齿,导致了文字会出现模糊。

参考文章:
【翻译】:CSS 的 will-change 属性详解 - 前端 - 掘金
CSS3动画那么强,requestAnimationFrame还有毛线用? « 张鑫旭-鑫空间-鑫生活
你所不知道的setInterval | 晚晴幽草轩
深入理解requestAnimationFrame - 最骚的就是你 - 博客园

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容