纯htmlcss实现一个炫酷的无限滚动动效

1. 先看成品

codepen体验
成品效果

(因为图片大小问题,只截取了一部分。实际效果是一直滚动,不会有动画复位的割裂感。)

2. 问题拆分

首先看到这个需求的时候,感觉比较难做,主要是下面的原因:需要斜着滚动,且需要无限,再就是icon错位排列的问题。

后来考虑了下,对这个问题进行了拆分:

  1. 编写容器及icon等的 css
  2. 排列好icon并且丢到一个wrapper中
  3. 将整个wrapper倾斜30度
  4. 为wrapper添加无限的横向滚动动画

话不多说,开始写代码

3. 开始行动

为了方便看边界,对于一些dom添加了边框~

3.1 创建容器

容器是一个固定大小的比较好写

.box {
    height: 666px;
    width: 1182px;
    border-radius: 36px;
    border: 1px solid;
    overflow: hidden;
    text-align: center;
    font-size: 30px;
}

3.2 然后撸个icon出来

这里就不使用图片来做了,统一用这个mock 一下~

.icon {
    width: 267px;
    height: 267px;
    border-radius: calc(267px * 0.23);
    background-image: conic-gradient(
        hsl(360, 100%, 50%),
        hsl(315, 100%, 50%),
        hsl(270, 100%, 50%),
        hsl(225, 100%, 50%),
        hsl(180, 100%, 50%),
        hsl(135, 100%, 50%),
        hsl(90, 100%, 50%),
        hsl(45, 100%, 50%),
        hsl(0, 100%, 50%)
    );
}

3.3 排列icon到wrapper中

我们把脖子沿逆时针方向旋转30度发现,实际上就是错落有致的摆放着两排icon。

我们按照图示静态的摆放一下:

1
2
3
4
5
6
7
8
.lean-box {
    display: flex;
    transform: rotate(-30deg);
}

.wrapper {
    margin-top: 180px;
    display: flex;
    flex-wrap: nowrap;
}

.wrapper .icon:nth-child(even) {
    margin-top: 45px;
    transform: translate(155px);
}

.icon-pair {
    margin-left: 45px;
}

.icon {
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-size: 66px;
    font-weight: bold;
}

image-20210214225056621

这样看起来就很有精神了,接下来我们需要让它动起来

3.4 添加动画

这里动起来使用的是animation,于是,编写下列代码并且添加到wrapper上:

@keyframes rowup {
    from {
        transform: translateX(0%);
    }

    to {
        transform: translateX(-500px);
    }
}
.wrapper {
    margin-top: 180px;
    display: flex;
    flex-wrap: nowrap;
    animation: rowup 5s linear infinite;
}

这时候动是动起来了,接下来的问题是,怎么无限的进行滚动呢?

无限到是动态添加dom,销毁dom,就是在这一组wrapper后创建一组一模一样的wrapper,等本组完全消失后销毁。

可是,这个成本会很高不是吗,而且这种实现方式势必需要随时间去更新icon的位置,一定有更好的方法

3.5 无缝滚动

animation动画结束后会回归第一帧,假设我们让第一帧的动画和最后一帧重合,那么是不是就看起来是无缝的了?

于是我将wrapper里面的元素重新拷贝一份放在后面(当前组称为A,拷贝组称为B),当动画结束时,B刚好移动到A的初始位置。

我们来计算一下:

这里一组8个icon排两排情况,移动的宽度应该为4个 icon宽度+ 4个margin,(267 4) + (45 4) = 1248px,这样 B 就可以刚好移动到 A 了

更新下动画:

@keyframes rowup {
    from {
        transform: translateX(0%);
    }

    to {
        transform: translateX(-1248px);
    }
}

html 也相应更新下:

1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8

3.6 完善一下

如果每次都要根据组件个数去计算的话,确实有点low了,其实会放置两个一模一样的icons,所以translateX的距离不需要计算,设置为-50%就好了,最终代码如下(可以在codepen上体验):

1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
@keyframes rowup {
    from {
        transform: translateX(0%);
    }

    to {
        transform: translateX(-50%);
    }
}
.box {
    height: 666px;
    width: 1182px;
    border-radius: 36px;
    border: 1px solid;
    overflow: hidden;
    text-align: center;
    font-size: 30px;
}

.icon {
    width: 267px;
    height: 267px;
    border-radius: calc(267px * 0.23);
    background-image: conic-gradient(
        hsl(360, 100%, 50%),
        hsl(315, 100%, 50%),
        hsl(270, 100%, 50%),
        hsl(225, 100%, 50%),
        hsl(180, 100%, 50%),
        hsl(135, 100%, 50%),
        hsl(90, 100%, 50%),
        hsl(45, 100%, 50%),
        hsl(0, 100%, 50%)
    );
}

.lean-box {
    display: flex;
    transform: rotate(-30deg);
}

.wrapper {
    margin-top: 180px;
    display: flex;
    flex-wrap: nowrap;
    animation: rowup 5s linear infinite;
}

.wrapper .icon:nth-child(even) {
    margin-top: 45px;
    transform: translate(155px);
}

.icon-pair {
    margin-left: 45px;
}

.icon {
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-size: 66px;
    font-weight: bold;
}

你可能感兴趣的:(csshtml)