css动画库
纯 CSS 实现“佛系水豚”漫步 Loader
Dec 22, 2025
191 阅读
官方团队
这是一个纯 CSS 绘制的**水豚(Capybara)** 漫步动画。它没有使用任何 SVG 或图片,完全由 `div` 配合 `border-radius` 和 `gradient`(渐变)拼接而成。看着它迈着六亲不认的步伐,等待的过程似乎也没那么焦虑了。
### 效果预览
请欣赏这只正在跑步机上努力营业的水豚:
***donghua
<style>
/* 推荐在深色或浅灰色背景下使用 */
.loader-wrapper {
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
background: #f4f4f4;
}
/* From Uiverse.io by Novaxlo */
.capybaraloader {
width: 14em;
height: 10em;
position: relative;
z-index: 1;
/* 定义主题色,方便一键换肤 */
--color: rgb(204, 125, 45); /* 浅棕色皮毛 */
--color2: rgb(83, 56, 28); /* 深棕色五官/阴影 */
transform: scale(0.75);
}
.capybara {
width: 100%;
height: 7.5em;
position: relative;
z-index: 1;
}
.loader {
width: 100%;
height: 2.5em;
position: relative;
z-index: 1;
overflow: hidden;
}
/* 身体部分:利用渐变制造立体感 */
.capy {
width: 85%;
height: 100%;
background: linear-gradient(var(--color), 90%, var(--color2));
border-radius: 45%;
position: relative;
z-index: 1;
animation: movebody 1s linear infinite;
}
/* 头部 */
.capyhead {
width: 7.5em;
height: 7em;
bottom: 0em;
right: 0em;
position: absolute;
background-color: var(--color);
z-index: 3;
border-radius: 3.5em;
box-shadow: -1em 0em var(--color2); /* 脖子阴影 */
animation: movebody 1s linear infinite;
}
/* 耳朵 */
.capyear {
width: 2em;
height: 2em;
background: linear-gradient(-45deg, var(--color), 90%, var(--color2));
top: 0em;
left: 0em;
border-radius: 100%;
position: absolute;
overflow: hidden;
z-index: 3;
}
.capyear:nth-child(2) {
left: 5em;
background: linear-gradient(25deg, var(--color), 90%, var(--color2));
}
.capyear2 {
width: 100%;
height: 1em;
background-color: var(--color2);
bottom: 0em;
left: 0.5em;
border-radius: 100%;
position: absolute;
transform: rotate(-45deg);
}
/* 五官细节 */
.capymouth {
width: 3.5em;
height: 2em;
background-color: var(--color2);
position: absolute;
bottom: 0em;
left: 2.5em;
border-radius: 50%;
display: flex;
justify-content: space-around;
align-items: center;
padding: 0.5em;
}
.capylips {
width: 0.25em;
height: 0.75em;
border-radius: 100%;
transform: rotate(-45deg);
background-color: var(--color);
}
.capylips:nth-child(2) {
transform: rotate(45deg);
}
.capyeye {
width: 2em;
height: 0.5em;
background-color: var(--color2);
position: absolute;
bottom: 3.5em;
left: 1.5em;
border-radius: 5em;
transform: rotate(45deg);
}
.capyeye:nth-child(4) {
transform: rotate(-45deg);
left: 5.5em;
width: 1.75em;
}
/* 腿部 */
.capyleg {
width: 6em;
height: 5em;
bottom: 0em;
left: 0em;
position: absolute;
background: linear-gradient(var(--color), 95%, var(--color2));
z-index: 2;
border-radius: 2em;
animation: movebody 1s linear infinite;
}
.capyleg2 {
width: 1.75em;
height: 3em;
bottom: 0em;
left: 3.25em;
position: absolute;
background: linear-gradient(var(--color), 80%, var(--color2));
z-index: 2;
border-radius: 0.75em;
box-shadow: inset 0em -0.5em var(--color2); /* 脚底阴影 */
animation: moveleg 1s linear infinite;
}
.capyleg2:nth-child(3) {
width: 1.25em;
left: 0.5em;
height: 2em;
animation: moveleg2 1s linear infinite 0.075s; /* 稍微错开时间,更自然 */
}
/* 动画定义 */
@keyframes moveleg {
0% { transform: rotate(-45deg) translateX(-5%); }
50% { transform: rotate(45deg) translateX(5%); }
100% { transform: rotate(-45deg) translateX(-5%); }
}
@keyframes moveleg2 {
0% { transform: rotate(45deg); }
50% { transform: rotate(-45deg); }
100% { transform: rotate(45deg); }
}
@keyframes movebody {
0% { transform: translateX(0%); }
50% { transform: translateX(2%); }
100% { transform: translateX(0%); }
}
/* 地面线条动画 */
.loaderline {
width: 50em;
height: 0.5em;
border-top: 0.5em dashed var(--color2);
animation: moveline 10s linear infinite;
}
@keyframes moveline {
0% { transform: translateX(0%); opacity: 0%; }
5% { opacity: 100%; }
95% { opacity: 100%; }
100% { opacity: 0%; transform: translateX(-70%); }
}
</style>
<div class="loader-wrapper">
<div class="capybaraloader">
<div class="capybara">
<div class="capyhead">
<div class="capyear">
<div class="capyear2"></div>
</div>
<div class="capyear"></div>
<div class="capymouth">
<div class="capylips"></div>
<div class="capylips"></div>
</div>
<div class="capyeye"></div>
<div class="capyeye"></div>
</div>
<div class="capyleg"></div>
<div class="capyleg2"></div>
<div class="capyleg2"></div>
<div class="capy"></div>
</div>
<div class="loader">
<div class="loaderline"></div>
</div>
</div>
</div>
***
### 核心逻辑拆解
这个动画不仅可爱,在 CSS 技术上也有几个值得学习的点:
#### 1. 几何拆解与层级 (Z-Index)
作者把水豚拆解成了几个简单的几何部分:
* **身体 (`.capy`)**:一个巨大的椭圆。
* **头 (`.capyhead`)**:圆角矩形,通过 `box-shadow` 制造了脖子处的阴影连接感。
* **腿 (`.capyleg`, `.capyleg2`)**:利用 `z-index` 精确控制了遮挡关系。注意看,前腿在身体后面,后腿在身体前面,制造出透视感。
#### 2. 相对运动原理
水豚其实是**原地踏步**的。
* **路面 (`.loaderline`)**:这是一个很长的虚线 `border-top`,通过 `translateX` 向左快速移动。
* **视觉错觉**:背景向后退,物体原地动,大脑就会自动脑补出“它在前进”的画面。这和横版过关游戏的原理是一样的。
#### 3. 步态动画 (Gait Animation)
为了让走路看起来自然,而不是像僵尸一样平移,作者加了两个细节:
* **腿部摆动**:`moveleg` 和 `moveleg2` 是两个相反的旋转动画(一个从 -45deg 到 45deg,另一个相反),模拟双腿交替。
* **身体晃动**:`movebody` 动画让身体和头部在水平方向有轻微的位移 (`translateX(2%)`)。这模拟了真实生物走路时重心的前后摆动,让画面瞬间有了“生命力”。
#### 4. 细节质感
注意看 CSS 变量 `--color` 和 `--color2` 的运用。
作者大量使用了 `linear-gradient`(线性渐变)来给纯色块增加光影。比如身体下方颜色更深,模拟了自然光照下的体积感。
### 源码自取
代码中使用了 `em` 作为单位,这意味着你只需要改变父容器的 `font-size`,整个水豚的大小就会等比例缩放,非常方便集成。
```html
<style>
/* 推荐在深色或浅灰色背景下使用 */
.loader-wrapper {
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
background: #f4f4f4;
}
.capybaraloader {
width: 14em;
height: 10em;
position: relative;
z-index: 1;
/* 定义主题色,方便一键换肤 */
--color: rgb(204, 125, 45); /* 浅棕色皮毛 */
--color2: rgb(83, 56, 28); /* 深棕色五官/阴影 */
transform: scale(0.75);
}
.capybara {
width: 100%;
height: 7.5em;
position: relative;
z-index: 1;
}
.loader {
width: 100%;
height: 2.5em;
position: relative;
z-index: 1;
overflow: hidden;
}
/* 身体部分:利用渐变制造立体感 */
.capy {
width: 85%;
height: 100%;
background: linear-gradient(var(--color), 90%, var(--color2));
border-radius: 45%;
position: relative;
z-index: 1;
animation: movebody 1s linear infinite;
}
/* 头部 */
.capyhead {
width: 7.5em;
height: 7em;
bottom: 0em;
right: 0em;
position: absolute;
background-color: var(--color);
z-index: 3;
border-radius: 3.5em;
box-shadow: -1em 0em var(--color2); /* 脖子阴影 */
animation: movebody 1s linear infinite;
}
/* 耳朵 */
.capyear {
width: 2em;
height: 2em;
background: linear-gradient(-45deg, var(--color), 90%, var(--color2));
top: 0em;
left: 0em;
border-radius: 100%;
position: absolute;
overflow: hidden;
z-index: 3;
}
.capyear:nth-child(2) {
left: 5em;
background: linear-gradient(25deg, var(--color), 90%, var(--color2));
}
.capyear2 {
width: 100%;
height: 1em;
background-color: var(--color2);
bottom: 0em;
left: 0.5em;
border-radius: 100%;
position: absolute;
transform: rotate(-45deg);
}
/* 五官细节 */
.capymouth {
width: 3.5em;
height: 2em;
background-color: var(--color2);
position: absolute;
bottom: 0em;
left: 2.5em;
border-radius: 50%;
display: flex;
justify-content: space-around;
align-items: center;
padding: 0.5em;
}
.capylips {
width: 0.25em;
height: 0.75em;
border-radius: 100%;
transform: rotate(-45deg);
background-color: var(--color);
}
.capylips:nth-child(2) {
transform: rotate(45deg);
}
.capyeye {
width: 2em;
height: 0.5em;
background-color: var(--color2);
position: absolute;
bottom: 3.5em;
left: 1.5em;
border-radius: 5em;
transform: rotate(45deg);
}
.capyeye:nth-child(4) {
transform: rotate(-45deg);
left: 5.5em;
width: 1.75em;
}
/* 腿部 */
.capyleg {
width: 6em;
height: 5em;
bottom: 0em;
left: 0em;
position: absolute;
background: linear-gradient(var(--color), 95%, var(--color2));
z-index: 2;
border-radius: 2em;
animation: movebody 1s linear infinite;
}
.capyleg2 {
width: 1.75em;
height: 3em;
bottom: 0em;
left: 3.25em;
position: absolute;
background: linear-gradient(var(--color), 80%, var(--color2));
z-index: 2;
border-radius: 0.75em;
box-shadow: inset 0em -0.5em var(--color2); /* 脚底阴影 */
animation: moveleg 1s linear infinite;
}
.capyleg2:nth-child(3) {
width: 1.25em;
left: 0.5em;
height: 2em;
animation: moveleg2 1s linear infinite 0.075s; /* 稍微错开时间,更自然 */
}
/* 动画定义 */
@keyframes moveleg {
0% { transform: rotate(-45deg) translateX(-5%); }
50% { transform: rotate(45deg) translateX(5%); }
100% { transform: rotate(-45deg) translateX(-5%); }
}
@keyframes moveleg2 {
0% { transform: rotate(45deg); }
50% { transform: rotate(-45deg); }
100% { transform: rotate(45deg); }
}
@keyframes movebody {
0% { transform: translateX(0%); }
50% { transform: translateX(2%); }
100% { transform: translateX(0%); }
}
/* 地面线条动画 */
.loaderline {
width: 50em;
height: 0.5em;
border-top: 0.5em dashed var(--color2);
animation: moveline 10s linear infinite;
}
@keyframes moveline {
0% { transform: translateX(0%); opacity: 0%; }
5% { opacity: 100%; }
95% { opacity: 100%; }
100% { opacity: 0%; transform: translateX(-70%); }
}
</style>
<div class="loader-wrapper">
<div class="capybaraloader">
<div class="capybara">
<div class="capyhead">
<div class="capyear">
<div class="capyear2"></div>
</div>
<div class="capyear"></div>
<div class="capymouth">
<div class="capylips"></div>
<div class="capylips"></div>
</div>
<div class="capyeye"></div>
<div class="capyeye"></div>
</div>
<div class="capyleg"></div>
<div class="capyleg2"></div>
<div class="capyleg2"></div>
<div class="capy"></div>
</div>
<div class="loader">
<div class="loaderline"></div>
</div>
</div>
</div>
```