背景
在上一篇文章一个炫酷的css动画里面,我们实现了一个酷炫的css动画。
那个最终实现上面,用了很多的标签在里面,有一些是效果需要,但是有一些是可以精简的。
于是想减少一下标签的使用来实现类似的效果,既然减少了,不如干脆一点,我们就用一个标签来尝试实现类似的效果。(不一完全一样的想效果,有些效果一个标签不好实现,下文会详细提到)
这是我们最终用单标签将要实现的效果。
老规矩,先分析一下效果,一共有六个部分,最外层圈,第二层圈,下面的一对圆环,上面的一对圆环,还有类流星雨动画的元素。
先把唯一的一个元素放好。
<div class="box"></div>
好,就这一个元素,html部分结束,下面全是css部分了!!!
最外层圈
这里第一反应应该是border,但是其实还有outline可以用,这里我们把border留给第二层用,我们第一层用outline来实现。
js
.box {
width: 300px;
height: 300px;
border-radius: 50%;
outline: 2px solid rgb(42, 153, 255);
outline-offset: 10px;
}
得到外面的圆环
第二层圈
第二层我们用border, 然后把上下或者左右的边设为透明
box的样式上加上这些代码
js
{
border: 5px solid rgb(42, 153, 255);
border-left-color: transparent;
border-right-color: transparent;
}
下面的一堆圆环
在上一篇文章里面,我们用了两种方式实现这个圆环
一种是conic-gradient 加mask,先利用角向渐变生成扇形,然后用mask遮住下面部分,得到圆环,然后重复多个,给每个不同的旋转角度。
第二种是repeating-conic-gradient 加mask,就是一次性生成带黑色间隔的扇形,然后mask遮住。
这里面我们还有第三种实现方式:
repeating-radial-gradient 加 repeating-conic-gradient
重复的径向渐变加重复的角向渐变来实现。
径向渐变可以得到一个完整的圆环,角向渐变可以得到黑色间隙的一堆小圆环。 这里面我们给box加上background
js
background: repeating-radial-gradient(
#000,
#000 50%,
transparent 50%,
transparent 60%,
#000 60%,
#000 100%
),
repeating-conic-gradient(
rgb(42, 153, 255) 0,
rgb(42, 153, 255) 4%,
transparent 4%,
transparent 5%
);
上面的一堆圆环
上面的一堆圆环实现起来其实和下面的一样,只是我们不能再用box的backgorund来实现了,因为有一个3d效果,需要沿着z轴做位移。
那我们其实还有两个工具没有用,那就是伪元素。这里我们先用一个::before
js
.box::before {
content: '';
position: absolute;
width: 300px;
height: 300px;
top: 0px;
left: 0px;
background: repeating-radial-gradient(
#000,
#000 50%,
transparent 50%,
transparent 60%,
#000 60%,
#000 100%
),
repeating-conic-gradient(
rgb(42, 153, 255) 0,
rgb(42, 153, 255) 4%,
transparent 4%,
transparent 5%
);
transform: translateZ(200px);
}
类流星雨元素
还剩下一个元素,我们就可以用另一个伪元素了,::after。 上一篇文章里面,我们用了一些元素来实现流星雨的动画,每一个元素代表其中一颗。这里我们只用一个伪元素实现的话,第一反应应该是用box-shadow来实现。
用box-shadow来实现对自身的多次复制,不过这里有一个缺陷,就是box-shadow默认是黑色,可以指定颜色但是不支持渐变。所以用box-shadow行不通,我们换一种方式来实现。
这里我们还是用repeating-linear-gradient 和mask来实现的。
重复的线性渐变实现几个自上而下的渐变色
然后我们再用mask,获得色条
js
.box::after {
content: '';
position: absolute;
width: 300px;
height: 300px;
top: 0px;
left: 0px;
background: #fff;
background: repeating-linear-gradient(
to bottom,
transparent 0,
transparent 80px,
rgba(42, 153, 255, 0.1) 80px,
rgb(42, 153, 255) 130px
);
-webkit-mask: repeating-linear-gradient(
to right,
transparent 0px,
transparent 80px,
#000 80px,
#000 82px
);
transform: rotateX(90deg);
animation: line 2s linear infinite;
}
到这里,我们就完整的用单标签实现了这样的一个动画效果。
全部代码如下:
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
background: #000;
display: flex;
align-items: center;
justify-content: center;
padding-top: 300px;
transform: translateZ(-150px);
transform-style: preserve-3d;
}
.box {
width: 300px;
height: 300px;
transform-style: preserve-3d;
position: relative;
border-radius: 50%;
border: 5px solid rgb(42, 153, 255);
border-left-color: transparent;
border-right-color: transparent;
outline: 2px solid rgb(42, 153, 255);
outline-offset: 10px;
background: repeating-radial-gradient(
#000,
#000 50%,
transparent 50%,
transparent 60%,
#000 60%,
#000 100%
),
repeating-conic-gradient(
rgb(42, 153, 255) 0,
rgb(42, 153, 255) 4%,
transparent 4%,
transparent 5%
);
animation: rotate2 2s linear infinite;
}
.box::before {
content: '';
position: absolute;
width: 300px;
height: 300px;
top: 0px;
left: 0px;
background: repeating-radial-gradient(
#000,
#000 50%,
transparent 50%,
transparent 60%,
#000 60%,
#000 100%
),
repeating-conic-gradient(
rgb(42, 153, 255) 0,
rgb(42, 153, 255) 4%,
transparent 4%,
transparent 5%
);
transform: translateZ(200px);
animation: rotate1 2s linear infinite;
}
.box::after {
content: '';
position: absolute;
width: 300px;
height: 300px;
top: 0px;
left: 0px;
background: #fff;
background: repeating-linear-gradient(
to bottom,
transparent 0,
transparent 80px,
rgba(42, 153, 255, 0.1) 80px,
rgb(42, 153, 255) 130px
);
-webkit-mask: repeating-linear-gradient(
to right,
transparent 0px,
transparent 80px,
#000 80px,
#000 82px
);
transform: rotateX(90deg);
animation: line 2s linear infinite;
}
@keyframes line {
0% {
transform: translateZ(-50px) rotateX(90deg) rotateY(0deg);
}
100% {
transform: translateZ(200px) rotateX(90deg) rotateY(-360deg);
}
}
@keyframes rotate1 {
0% {
transform: translateZ(200px) rotateZ(0deg);
}
100% {
transform: translateZ(200px) rotateZ(-720deg);
}
}
@keyframes rotate2 {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
</style>
</head>
<body>
<div class="box"></div>
<script>
var elem = document.querySelector('body')
var isDragging = false // 用于判断是否正在拖动
var initialX = 0 // 初始鼠标X坐标
var initialY = 0 // 初始鼠标Y坐标
var currentX = 0 // 当前鼠标X坐标
var currentY = 0 // 当前鼠标Y坐标
var initialRotationY = 0 // 初始旋转角度(Y轴)
var initialRotationX = 0 // 初始旋转角度(X轴)
elem.addEventListener('mousedown', function (e) {
// 当鼠标按下时
initialY = e.clientY // 获取初始鼠标Y坐标
initialRotationY = parseInt(
getComputedStyle(elem)
.getPropertyValue('transform')
.replace(/[^0-9-.,]/g, '')
.split(',')[4]
) // 获取初始旋转角度(Y轴)
initialRotationX = parseInt(
getComputedStyle(elem)
.getPropertyValue('transform')
.replace(/[^0-9-.,]/g, '')
.split(',')[5]
) // 获取初始旋转角度(X轴)
isDragging = true // 设置isDragging为true,表示正在拖动
})
document.addEventListener('mousemove', function (e) {
// 当鼠标移动时
if (isDragging) {
// 如果正在拖动
currentY = e.clientY // 获取当前鼠标Y坐标
var dy = currentY - initialY // Y轴方向移动的距离
var newRotationY = initialRotationY + dy * -1 // 根据移动方向计算新的旋转角度(Y轴)
console.log(111, dy, newRotationY)
elem.style.transform = 'rotateX(' + newRotationY + 'deg)' // 设置元素的旋转角度
}
})
document.addEventListener('mouseup', function () {
// 当鼠标松开时
isDragging = false // 设置isDragging为false,表示已经停止拖动
})
</script>
</body>
</html>