1. 先看成品
codepen体验
(因为图片大小问题,只截取了一部分。实际效果是始终滚动,不会有动画复位的割裂感。)
2. 问题拆分
首先看到这个需要的时候,感觉比拟难做,次要是上面的起因:须要斜着滚动,且须要有限,再就是icon错位排列的问题。
起初思考了下,对这个问题进行了拆分:
- 编写容器及icon等的 css
- 排列好icon并且丢到一个wrapper中
- 将整个wrapper歪斜30度
- 为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。
咱们依照图示动态的摆放一下:
<div class="box"> <div class="lean-box"> <div class="wrapper"> <div class="icon-pair"> <div class="icon">1</div> <div class="icon">2</div> </div> <div class="icon-pair"> <div class="icon">3</div> <div class="icon">4</div> </div> <div class="icon-pair"> <div class="icon">5</div> <div class="icon">6</div> </div> <div class="icon-pair"> <div class="icon">7</div> <div class="icon">8</div> </div> </div> </div></div>
.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;}
这样看起来就很有精力了,接下来咱们须要让它动起来
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 也相应更新下:
<div class="box"> <div class="lean-box"> <div class="wrapper"> <div class="icon-pair"> <div class="icon">1</div> <div class="icon">2</div> </div> <div class="icon-pair"> <div class="icon">3</div> <div class="icon">4</div> </div> <div class="icon-pair"> <div class="icon">5</div> <div class="icon">6</div> </div> <div class="icon-pair"> <div class="icon">7</div> <div class="icon">8</div> </div> <div class="icon-pair"> <div class="icon">1</div> <div class="icon">2</div> </div> <div class="icon-pair"> <div class="icon">3</div> <div class="icon">4</div> </div> <div class="icon-pair"> <div class="icon">5</div> <div class="icon">6</div> </div> <div class="icon-pair"> <div class="icon">7</div> <div class="icon">8</div> </div> </div> </div></div>
3.6 欠缺一下
如果每次都要依据组件个数去计算的话,的确有点low了,其实会搁置两个截然不同的icons,所以translateX的间隔不须要计算,设置为-50%就好了,最终代码如下(能够在codepen上体验):
<div class="box"> <div class="lean-box"> <div class="wrapper"> <div class="icon-pair"> <div class="icon">1</div> <div class="icon">2</div> </div> <div class="icon-pair"> <div class="icon">3</div> <div class="icon">4</div> </div> <div class="icon-pair"> <div class="icon">5</div> <div class="icon">6</div> </div> <div class="icon-pair"> <div class="icon">7</div> <div class="icon">8</div> </div> <div class="icon-pair"> <div class="icon">1</div> <div class="icon">2</div> </div> <div class="icon-pair"> <div class="icon">3</div> <div class="icon">4</div> </div> <div class="icon-pair"> <div class="icon">5</div> <div class="icon">6</div> </div> <div class="icon-pair"> <div class="icon">7</div> <div class="icon">8</div> </div> </div> </div></div>
@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;}