纯CSS实现无限循环滚动动画
最近接到了一个需求,要求在官网展示一个合作品牌方Logo展示区域,具体需求如下:
- 品牌需要分四行展示,每行展示六个品牌logo
- 品牌logo宽高为固定大小,且需要隔行错开展示
- 品牌logo从右向左线性循环移动展示(跑马灯效果)
- 双边需要实现模糊的效果
静态效果如下
上述这种跑马灯效果其实是有个比较古老的标签<marquee>
可以直接实现的,只不过这个标签现在已经废弃了。那么如何使用CSS来实现上述的需求呢?下面将介绍两种方法来实现。
方法一:通过绝对定位+动画延时
实现思路:
- 将logo相对所在行进���绝对定位后,将logo脱离文档流,并定位到所在行的右侧
- 定义动画,使logo从右往左线性移动,终点的位置也就是相对当前行偏移出一个logo容器的宽度
- 上述步骤虽然实现了基本的动画,但是所有logo都是堆叠在一起的。所以只能看到一个元素在移动。那么如何将堆叠在一起的动画进行分离呢?这时候动画延时就派上用场了。我们可以根据logo的个数以及动画持续的时间动态计算每个logo动画的延时,从而实现将logo的动画进行分离。
- 两侧实现模糊遮盖的效果可以通过
mask-image
+linear-gradient
实现。
好了,既然思路已经有了,就可以开始实现了。
步骤
首先,定义HTML的结构如下:
<div class="wrapper">
<div class="item" style="--count: 1"></div>
<div class="item" style="--count: 2"></div>
<div class="item" style="--count: 3"></div>
<div class="item" style="--count: 4"></div>
<div class="item" style="--count: 5"></div>
<div class="item" style="--count: 6"></div>
<div class="item" style="--count: 7"></div>
<div class="item" style="--count: 8"></div>
</div>
编写wrapper样式
.wrapper {
--logo-width: 200px;
--logo-height: 100px;
--logo-count: 8;
--duration: 30s;
width: 90%;
max-width: 1200px;
margin-inline: auto;
position: relative;
height: var(--logo-height);
margin-top: 5rem;
overflow: hidden;
/* 模糊遮挡效果 */
mask-image: linear-gradient(
to right,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 1) 20%,
rgba(0, 0, 0, 1) 80%,
rgba(0, 0, 0, 0)
);
}
定义动画,终点为负的一个logo宽度
@keyframes scrollLeft {
to {
left: calc(var(--logo-width) * -1);
}
}
定义每个item的样式
.item {
width: var(--logo-width);
height: var(--logo-height);
background-color: red;
border-radius: 6px;
position: absolute;
left: calc(var(--logo-width) * var(--logo-count));
animation-name: scrollLeft;
animation-duration: var(--duration);
animation-timing-function: linear;
animation-iteration-count: infinite;
/* 动态计算出每个logo的动画延时 */
animation-delay: calc(var(--duration) / var(--logo-count) * (var(--logo-count) - var(--count)) * -1);
}
至于隔行错开的样式,可以添加一个div容器包裹所有的item项目,然后使用CSS伪类选择器,对偶数行应用margin-left
来实现。
方案二:通过双份logo进行动画循环
实现思路:
将每行的长度增加一倍,然后通过循环动画来实现无限循环滚动的效果。
这种方法的缺点在于会让元素数量增加一倍,有点在于容易理解和实现。
步骤
同样,首先定义HTML结构
<div class="wrapper">
<div class="marquee">
<div class="marquee__group">
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
</div>
<div class="marquee__group">
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
</div>
</div>
<div class="marquee">
<div class="marquee__group">
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
</div>
<div class="marquee__group" aria-hidden="true">
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
<div class="item" ></div>
</div>
</div>
</div>
接着定义CSS样式和动画
.wrapper {
--logo-width: 200px;
--logo-height: 100px;
--gap: calc(var(--logo-width) / 14);
--duration: 60s;
--scroll-start: 0;
--scroll-end: calc(-100% - var(--gap));
display: flex;
flex-direction: column;
gap: var(--gap);
margin: auto;
max-width: 100vw;
}
.marquee {
display: flex;
overflow: hidden;
user-select: none;
gap: var(--gap);
mask-image: linear-gradient(
to right,
hsl(0 0% 0% / 0),
hsl(0 0% 0% / 1) 20%,
hsl(0 0% 0% / 1) 80%,
hsl(0 0% 0% / 0)
);
}
.marquee__group {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: space-around;
gap: var(--gap);
min-width: 100%;
animation: scrollLeft var(--duration) linear infinite;
}
.wrapper .marquee:nth-child(even) {
margin-left: calc(var(--logo-width) / -2);
}
.item {
width: var(--logo-width);
height: var(--logo-height);
background-color: red;
border-radius: 6px;
}
@keyframes scrollLeft {
from {
transform: translateX(var(--scroll-start));
}
to {
transform: translateX(var(--scroll-end));
}
}
最终效果
转载自:https://juejin.cn/post/7398376017163337778