效果
运行环境
- 系统:Win10系统
- IDE:
Visual Studio Code v1.79.2
- VSCode插件:
Easy LESS v2.0.0
index.html代码
<!DOCTYPE html>
<html>
<head>
<title>加载动画</title>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div class="loading">
<!--Emmet 缩写 div.dot-->
<!--Emmet 缩写 div.dot*36-->
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
</body>
</html>
index.less
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #66c7f4;
}
@ballSize: 10px;
//@halfBallSize: 5px;
@containerSize: 150px;
//@halfContainerSize: 75px;
@n:36;
@ani-diratoion:2000ms;
// @pdeg:360deg/@n;
// 当前less编译器不支持 混合运算如 360deg /36 | 150px/2
@pdeg:15deg;
.loading {
width: @containerSize;
height: @containerSize;
margin: 50px auto;
position: relative;
//矩形倒角占比 - 50%为椭圆,长宽一样为圆
border-radius: 50%;
//与圆圈的颜色
//outline: 1px solid #fff;
.dot {
//绝对位置
position: absolute;
left: 50%;
top: 50%;
//方块的宽度
width: @ballSize;
//方块的宽度
height: @ballSize;
margin-left: -(@ballSize/2);
margin-top: -(@ballSize/2);
//景深
perspective: 70px;
//景深-加强3D效果
transform-style: preserve-3d;
//方块的颜色
//background: red;
//黑白球的共有样式
&::before,&::after{
content: '';
position: absolute;
width: 100%;
height: 100%;
//矩形倒角占比 - 50%为椭圆,长宽一样为圆
border-radius: 50%;
}
//黑色小球样式
&::before{
background: #000;
top: -100%;
animation: moveBlack @ani-diratoion infinite;
}
//白色小球样式
&::after{
background: #fff;
top: 100%;
animation: moveWhite @ani-diratoion infinite;
}
}
}
// 黑球动画
@keyframes moveBlack {
0%{
animation-timing-function: ease-in;
}
25%{
transform: translate3d(0, 100% ,@ballSize);
animation-timing-function: ease-out;
}
50%{
transform: translate3d(0, 200% ,0);
animation-timing-function: ease-in;
}
75%{
transform: translate3d(0, 100% ,-@ballSize);
animation-timing-function: ease-out;
}
}
// 白球球动画
@keyframes moveWhite {
0%{
animation-timing-function: ease-in;
}
25%{
transform: translate3d(0, -100% ,-@ballSize);
animation-timing-function: ease-out;
}
50%{
transform: translate3d(0, -200% ,0);
animation-timing-function: ease-in;
}
75%{
transform: translate3d(0, -100% ,@ballSize);
animation-timing-function: ease-out;
}
}
//循环生成 n 个黑白球
.loop(@i) when(@i<=@n){
//获取第i个dot元素
.dot:nth-child(@{i}){
//transform: rotate(@pdeg * @i) translateY(-@halfContainerSize);
//每个黑白球 设置旋转角度和Y方向便宜值
transform: rotate(@pdeg * @i) translateY(-(@containerSize/2));
//每个黑白球的动画启动延迟
&::before, &::after{
animation-delay: -((@ani-diratoion/@n) * 6 * @i);
}
}
//递归调用
.loop(@i+1);
}
.loop(1);
/*
.dot:nth-child(1) {
transform: rotate(@pdeg) translateY(-@halfContainerSize);
}
.dot:nth-child(2) {
transform: rotate(@pdeg*2) translateY(-@halfContainerSize);
}
.dot:nth-child(3) {
transform: rotate(@pdeg*3) translateY(-@halfContainerSize);
}
*/
index.css
此文件有index.less 通过 less编译器自动生成,html
中引用了此文件
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #66c7f4;
}
.loading {
width: 150px;
height: 150px;
margin: 50px auto;
position: relative;
border-radius: 50%;
}
.loading .dot {
position: absolute;
left: 50%;
top: 50%;
width: 10px;
height: 10px;
margin-left: -5px;
margin-top: -5px;
perspective: 70px;
transform-style: preserve-3d;
}
.loading .dot::before,
.loading .dot::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
}
.loading .dot::before {
background: #000;
top: -100%;
animation: moveBlack 2000ms infinite;
}
.loading .dot::after {
background: #fff;
top: 100%;
animation: moveWhite 2000ms infinite;
}
@keyframes moveBlack {
0% {
animation-timing-function: ease-in;
}
25% {
transform: translate3d(0, 100%, 10px);
animation-timing-function: ease-out;
}
50% {
transform: translate3d(0, 200%, 0);
animation-timing-function: ease-in;
}
75% {
transform: translate3d(0, 100%, -10px);
animation-timing-function: ease-out;
}
}
@keyframes moveWhite {
0% {
animation-timing-function: ease-in;
}
25% {
transform: translate3d(0, -100%, -10px);
animation-timing-function: ease-out;
}
50% {
transform: translate3d(0, -200%, 0);
animation-timing-function: ease-in;
}
75% {
transform: translate3d(0, -100%, 10px);
animation-timing-function: ease-out;
}
}
.dot:nth-child(1) {
transform: rotate(15deg) translateY(-75px);
}
.dot:nth-child(1)::before,
.dot:nth-child(1)::after {
animation-delay: -333.33333333ms;
}
.dot:nth-child(2) {
transform: rotate(30deg) translateY(-75px);
}
.dot:nth-child(2)::before,
.dot:nth-child(2)::after {
animation-delay: -666.66666667ms;
}
.dot:nth-child(3) {
transform: rotate(45deg) translateY(-75px);
}
.dot:nth-child(3)::before,
.dot:nth-child(3)::after {
animation-delay: -1000ms;
}
.dot:nth-child(4) {
transform: rotate(60deg) translateY(-75px);
}
.dot:nth-child(4)::before,
.dot:nth-child(4)::after {
animation-delay: -1333.33333333ms;
}
.dot:nth-child(5) {
transform: rotate(75deg) translateY(-75px);
}
.dot:nth-child(5)::before,
.dot:nth-child(5)::after {
animation-delay: -1666.66666667ms;
}
.dot:nth-child(6) {
transform: rotate(90deg) translateY(-75px);
}
.dot:nth-child(6)::before,
.dot:nth-child(6)::after {
animation-delay: -2000ms;
}
.dot:nth-child(7) {
transform: rotate(105deg) translateY(-75px);
}
.dot:nth-child(7)::before,
.dot:nth-child(7)::after {
animation-delay: -2333.33333333ms;
}
.dot:nth-child(8) {
transform: rotate(120deg) translateY(-75px);
}
.dot:nth-child(8)::before,
.dot:nth-child(8)::after {
animation-delay: -2666.66666667ms;
}
.dot:nth-child(9) {
transform: rotate(135deg) translateY(-75px);
}
.dot:nth-child(9)::before,
.dot:nth-child(9)::after {
animation-delay: -3000ms;
}
.dot:nth-child(10) {
transform: rotate(150deg) translateY(-75px);
}
.dot:nth-child(10)::before,
.dot:nth-child(10)::after {
animation-delay: -3333.33333333ms;
}
.dot:nth-child(11) {
transform: rotate(165deg) translateY(-75px);
}
.dot:nth-child(11)::before,
.dot:nth-child(11)::after {
animation-delay: -3666.66666667ms;
}
.dot:nth-child(12) {
transform: rotate(180deg) translateY(-75px);
}
.dot:nth-child(12)::before,
.dot:nth-child(12)::after {
animation-delay: -4000ms;
}
.dot:nth-child(13) {
transform: rotate(195deg) translateY(-75px);
}
.dot:nth-child(13)::before,
.dot:nth-child(13)::after {
animation-delay: -4333.33333333ms;
}
.dot:nth-child(14) {
transform: rotate(210deg) translateY(-75px);
}
.dot:nth-child(14)::before,
.dot:nth-child(14)::after {
animation-delay: -4666.66666667ms;
}
.dot:nth-child(15) {
transform: rotate(225deg) translateY(-75px);
}
.dot:nth-child(15)::before,
.dot:nth-child(15)::after {
animation-delay: -5000ms;
}
.dot:nth-child(16) {
transform: rotate(240deg) translateY(-75px);
}
.dot:nth-child(16)::before,
.dot:nth-child(16)::after {
animation-delay: -5333.33333333ms;
}
.dot:nth-child(17) {
transform: rotate(255deg) translateY(-75px);
}
.dot:nth-child(17)::before,
.dot:nth-child(17)::after {
animation-delay: -5666.66666667ms;
}
.dot:nth-child(18) {
transform: rotate(270deg) translateY(-75px);
}
.dot:nth-child(18)::before,
.dot:nth-child(18)::after {
animation-delay: -6000ms;
}
.dot:nth-child(19) {
transform: rotate(285deg) translateY(-75px);
}
.dot:nth-child(19)::before,
.dot:nth-child(19)::after {
animation-delay: -6333.33333333ms;
}
.dot:nth-child(20) {
transform: rotate(300deg) translateY(-75px);
}
.dot:nth-child(20)::before,
.dot:nth-child(20)::after {
animation-delay: -6666.66666667ms;
}
.dot:nth-child(21) {
transform: rotate(315deg) translateY(-75px);
}
.dot:nth-child(21)::before,
.dot:nth-child(21)::after {
animation-delay: -7000ms;
}
.dot:nth-child(22) {
transform: rotate(330deg) translateY(-75px);
}
.dot:nth-child(22)::before,
.dot:nth-child(22)::after {
animation-delay: -7333.33333333ms;
}
.dot:nth-child(23) {
transform: rotate(345deg) translateY(-75px);
}
.dot:nth-child(23)::before,
.dot:nth-child(23)::after {
animation-delay: -7666.66666667ms;
}
.dot:nth-child(24) {
transform: rotate(360deg) translateY(-75px);
}
.dot:nth-child(24)::before,
.dot:nth-child(24)::after {
animation-delay: -8000ms;
}
.dot:nth-child(25) {
transform: rotate(375deg) translateY(-75px);
}
.dot:nth-child(25)::before,
.dot:nth-child(25)::after {
animation-delay: -8333.33333333ms;
}
.dot:nth-child(26) {
transform: rotate(390deg) translateY(-75px);
}
.dot:nth-child(26)::before,
.dot:nth-child(26)::after {
animation-delay: -8666.66666667ms;
}
.dot:nth-child(27) {
transform: rotate(405deg) translateY(-75px);
}
.dot:nth-child(27)::before,
.dot:nth-child(27)::after {
animation-delay: -9000ms;
}
.dot:nth-child(28) {
transform: rotate(420deg) translateY(-75px);
}
.dot:nth-child(28)::before,
.dot:nth-child(28)::after {
animation-delay: -9333.33333333ms;
}
.dot:nth-child(29) {
transform: rotate(435deg) translateY(-75px);
}
.dot:nth-child(29)::before,
.dot:nth-child(29)::after {
animation-delay: -9666.66666667ms;
}
.dot:nth-child(30) {
transform: rotate(450deg) translateY(-75px);
}
.dot:nth-child(30)::before,
.dot:nth-child(30)::after {
animation-delay: -10000ms;
}
.dot:nth-child(31) {
transform: rotate(465deg) translateY(-75px);
}
.dot:nth-child(31)::before,
.dot:nth-child(31)::after {
animation-delay: -10333.33333333ms;
}
.dot:nth-child(32) {
transform: rotate(480deg) translateY(-75px);
}
.dot:nth-child(32)::before,
.dot:nth-child(32)::after {
animation-delay: -10666.66666667ms;
}
.dot:nth-child(33) {
transform: rotate(495deg) translateY(-75px);
}
.dot:nth-child(33)::before,
.dot:nth-child(33)::after {
animation-delay: -11000ms;
}
.dot:nth-child(34) {
transform: rotate(510deg) translateY(-75px);
}
.dot:nth-child(34)::before,
.dot:nth-child(34)::after {
animation-delay: -11333.33333333ms;
}
.dot:nth-child(35) {
transform: rotate(525deg) translateY(-75px);
}
.dot:nth-child(35)::before,
.dot:nth-child(35)::after {
animation-delay: -11666.66666667ms;
}
.dot:nth-child(36) {
transform: rotate(540deg) translateY(-75px);
}
.dot:nth-child(36)::before,
.dot:nth-child(36)::after {
animation-delay: -12000ms;
}
/*
.dot:nth-child(1) {
transform: rotate(@pdeg) translateY(-@halfContainerSize);
}
.dot:nth-child(2) {
transform: rotate(@pdeg*2) translateY(-@halfContainerSize);
}
.dot:nth-child(3) {
transform: rotate(@pdeg*3) translateY(-@halfContainerSize);
}
*/
扩展 关于Less四则运算除非处理
由于less编译器的版本问题可能会出现如下问题导致css生成的语句达不到预期效果如:
编写less代码
@containerSize: 150px;
@pdeg: 15deg;
@ani-diratoion: 2000ms;
@index: 2;
@count: 36;
.dot{
width: @containerSize/2;
}
.dot:nth-child(1) {
transform: rotate(@pdeg * @index) translateY(-@containerSize/2);
&::before,
&::after {
animation-delay: -@ani-diratoion / (@count * 6 * @index);
}
}
生成css代码
其中150px/2
、-150px/2
、-2000ms / 432
,这些并不能被浏览器识别,然后渲染。为什么会出现这种情况,是因为less编译器的版本、不同系统Windows、Mac等的语法兼容性导致的。
.dot {
width: 150px/2;
}
.dot:nth-child(1) {
transform: rotate(30deg) translateY(-150px/2);
}
.dot:nth-child(1)::before,
.dot:nth-child(1)::after {
animation-delay: -2000ms / 432;
}
解决方案 将除号和参与运算的变量或数字用小括号()
包起来
Less 代码
@containerSize: 150px;
@pdeg: 15deg;
@ani-diratoion: 2000ms;
@index: 2;
@count: 36;
.dot{
width: (@containerSize/2);
}
.dot:nth-child(1) {
transform: rotate(@pdeg * @index) translateY(-(@containerSize/2));
&::before,
&::after {
animation-delay: -(@ani-diratoion / @count * 6 * @index);
}
}
CSS 代码
.dot {
width: 75px;
}
.dot:nth-child(1) {
transform: rotate(30deg) translateY(-75px);
}
.dot:nth-child(1)::before,
.dot:nth-child(1)::after {
animation-delay: -666.66666667ms;
}