css动画库
纯 CSS 实现“星际穿越” 3D 宇宙开关
Dec 22, 2025
187 阅读
官方团队
这是一个充满赛博朋克和科幻感的 **Cosmic Toggle(宇宙开关)**。它拥有深邃的星空背景、细腻的 3D 悬浮感,以及激活时爆发的粒子特效。最惊人的是,这一切依然是 **纯 CSS** 实现的,没有使用任何 JavaScript 来计算动画。
### 效果预览
请试着点击下面的开关,并尝试把鼠标悬停在上面,感受它的 3D 倾斜效果:
***donghua
<style> /* 核心容器:提供 3D 舞台 */ .cosmic-toggle { position: relative; width: 140px; height: 70px; transform-style: preserve-3d; perspective: 500px; /* 决定 3D 效果的透视强度 */ display: inline-block; /* 确保它像普通元素一样排列 */ } /* 隐藏原生 checkbox */ .toggle { opacity: 0; width: 0; height: 0; position: absolute; } /* 开关底座 */ .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(45deg, #1a1a2e, #16213e); border-radius: 35px; transition: 0.5s; transform-style: preserve-3d; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5), inset 0 0 15px rgba(255, 255, 255, 0.05); overflow: hidden; } /* 星空背景:利用多重径向渐变绘制星星 */ .cosmos { position: absolute; inset: 0; background: radial-gradient(1px 1px at 10% 10%, #fff 100%, transparent), radial-gradient(1px 1px at 20% 20%, #fff 100%, transparent), radial-gradient(2px 2px at 30% 30%, #fff 100%, transparent), radial-gradient(1px 1px at 40% 40%, #fff 100%, transparent), radial-gradient(2px 2px at 50% 50%, #fff 100%, transparent), radial-gradient(1px 1px at 60% 60%, #fff 100%, transparent), radial-gradient(2px 2px at 70% 70%, #fff 100%, transparent), radial-gradient(1px 1px at 80% 80%, #fff 100%, transparent), radial-gradient(1px 1px at 90% 90%, #fff 100%, transparent); background-size: 200% 200%; opacity: 0.1; transition: 0.5s; } /* 核心按钮球体 */ .toggle-orb { position: absolute; height: 62px; width: 62px; left: 4px; bottom: 4px; background: linear-gradient(145deg, #ff6b6b, #4ecdc4); border-radius: 50%; transition: 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); /* 弹性缓动 */ transform-style: preserve-3d; z-index: 2; } /* 球体内部纹理 */ .inner-orb { position: absolute; inset: 5px; border-radius: 50%; background: linear-gradient(145deg, #fff, #e6e6e6); transition: 0.5s; overflow: hidden; } /* 旋转的内部图案 */ .inner-orb::before { content: ""; position: absolute; inset: 0; background: repeating-conic-gradient( from 0deg, transparent 0deg, rgba(0, 0, 0, 0.1) 10deg, transparent 20deg ); animation: patternRotate 10s linear infinite; } /* 外部光环 */ .ring { position: absolute; inset: -3px; border: 2px solid rgba(255, 255, 255, 0.1); border-radius: 50%; transition: 0.5s; } /* --- 激活状态 (Checked) --- */ .toggle:checked + .slider { background: linear-gradient(45deg, #16213e, #1a1a2e); } .toggle:checked + .slider .toggle-orb { transform: translateX(70px) rotate(360deg); background: linear-gradient(145deg, #4ecdc4, #45b7af); } .toggle:checked + .slider .inner-orb { background: linear-gradient(145deg, #45b7af, #3da89f); transform: scale(0.9); } .toggle:checked + .slider .ring { border-color: rgba(78, 205, 196, 0.3); animation: ringPulse 2s infinite; } /* --- 能量线特效 --- */ .energy-line { position: absolute; width: 100%; height: 2px; background: linear-gradient( 90deg, transparent, rgba(78, 205, 196, 0.5), transparent ); transform-origin: left; opacity: 0; transition: 0.5s; } .energy-line:nth-child(1) { top: 20%; transform: rotate(15deg); } .energy-line:nth-child(2) { top: 50%; transform: rotate(0deg); } .energy-line:nth-child(3) { top: 80%; transform: rotate(-15deg); } .toggle:checked + .slider .energy-line { opacity: 1; animation: energyFlow 2s linear infinite; } /* --- 粒子特效 --- */ .particles { position: absolute; width: 100%; height: 100%; } .particle { position: absolute; width: 4px; height: 4px; background: #4ecdc4; border-radius: 50%; opacity: 0; } .toggle:checked + .slider .particle { animation: particleBurst 1s ease-out infinite; } /* 粒子位置与延迟 */ .particle:nth-child(1) { left: 20%; animation-delay: 0s; } .particle:nth-child(2) { left: 40%; animation-delay: 0.2s; } .particle:nth-child(3) { left: 60%; animation-delay: 0.4s; } .particle:nth-child(4) { left: 80%; animation-delay: 0.6s; } .particle:nth-child(5) { left: 30%; animation-delay: 0.8s; } .particle:nth-child(6) { left: 70%; animation-delay: 1s; } /* --- 动画关键帧 --- */ @keyframes ringPulse { 0%, 100% { transform: scale(1); opacity: 0.3; } 50% { transform: scale(1.1); opacity: 0.6; } } @keyframes patternRotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes energyFlow { 0% { transform: scaleX(0) translateX(0); opacity: 0; } 50% { transform: scaleX(1) translateX(50%); opacity: 1; } 100% { transform: scaleX(0) translateX(100%); opacity: 0; } } @keyframes particleBurst { 0% { transform: translate(0, 0) scale(1); opacity: 1; } 100% { /* 使用 cos/sin 计算爆炸轨迹 */ transform: translate( calc(cos(var(--angle)) * 50px), calc(sin(var(--angle)) * 50px) ) scale(0); opacity: 0; } } /* --- 鼠标交互 (Hover) --- */ .slider:hover .toggle-orb { filter: brightness(1.2); box-shadow: 0 0 20px rgba(78, 205, 196, 0.5), 0 0 40px rgba(78, 205, 196, 0.3); } .slider:hover .cosmos { opacity: 0.2; animation: cosmosPan 20s linear infinite; } @keyframes cosmosPan { 0% { background-position: 0% 0%; } 100% { background-position: 200% 200%; } } /* 整体 3D 倾斜效果 */ .cosmic-toggle:hover .slider { transform: rotateX(10deg) rotateY(10deg); } .cosmic-toggle:hover .toggle-orb { transform: translateZ(10px); } </style> <label class="cosmic-toggle"> <input class="toggle" type="checkbox" /> <div class="slider"> <div class="cosmos"></div> <div class="energy-line"></div> <div class="energy-line"></div> <div class="energy-line"></div> <div class="toggle-orb"> <div class="inner-orb"></div> <div class="ring"></div> </div> <div class="particles"> <div style="--angle: 30deg" class="particle"></div> <div style="--angle: 60deg" class="particle"></div> <div style="--angle: 90deg" class="particle"></div> <div style="--angle: 120deg" class="particle"></div> <div style="--angle: 150deg" class="particle"></div> <div style="--angle: 180deg" class="particle"></div> </div> </div> </label> ***
### 核心技术解析
这个开关通过几个高级 CSS 技巧,营造出了“星际穿越”的氛围感:
#### 1. CSS 三角函数与粒子爆炸
这是代码中最“硬核”的部分。在 `.particleBurst` 动画中,作者使用了现代 CSS 的数学函数:
```css
transform: translate(
calc(cos(var(--angle)) * 50px),
calc(sin(var(--angle)) * 50px)
)
```
通过 HTML 中定义的 CSS 变量 `--angle`(例如 `30deg`, `60deg`),配合 `sin()` 和 `cos()`,精确计算了每个粒子爆炸时的 X/Y 轴位移。这在以前必须依赖 JavaScript 才能实现,现在 CSS 原生就能搞定!
#### 2. 3D 视差交互
为了让开关看起来像一个真实的物理装置,容器使用了 `perspective: 500px`。
* 当鼠标悬停时,`.slider` 会轻微旋转 (`rotateX(10deg) rotateY(10deg)`)。
* 同时,按钮本体 `.toggle-orb` 会执行 `translateZ(10px)`,这会让按钮看起来“浮”出表面,产生真实的纵深感。
#### 3. 纯 CSS 绘制星空
背景的星空 (`.cosmos`) 并没有使用图片,而是利用了多重 `radial-gradient`(径向渐变)。
作者定义了 9 个不同位置、大小不一的白色小圆点,叠加在一起就形成了星空。配合 `cosmosPan` 动画移动背景位置,就实现了飞船在星际航行的视觉错觉。
#### 4. 能量流动特效
当开关激活时,`.energy-line` 会出现。通过 `scaleX` 从 0 到 1 再到 0 的变化,模拟了电流或能量脉冲从左向右传输的过程,增强了“开启”的反馈感。
### 源码自取
**注意**:由于使用了 CSS 三角函数 (`sin`, `cos`),此效果在较新的浏览器(Chrome 111+, Safari 15.4+, Firefox 108+)中体验最佳。
```html
<style>
/* 容器样式:提供 3D 舞台 */
.cosmic-toggle {
position: relative;
width: 140px;
height: 70px;
transform-style: preserve-3d;
perspective: 500px; /* 决定 3D 效果的透视强度 */
}
/* 隐藏原生 checkbox */
.toggle {
opacity: 0;
width: 0;
height: 0;
position: absolute;
}
/* 开关底座 */
.slider {
position: absolute;
cursor: pointer;
inset: 0;
background: linear-gradient(45deg, #1a1a2e, #16213e);
border-radius: 35px;
transition: 0.5s;
transform-style: preserve-3d;
box-shadow:
0 0 20px rgba(0, 0, 0, 0.5),
inset 0 0 15px rgba(255, 255, 255, 0.05);
overflow: hidden;
}
/* 星空背景:利用多重径向渐变绘制星星 */
.cosmos {
position: absolute;
inset: 0;
background: radial-gradient(1px 1px at 10% 10%, #fff 100%, transparent),
radial-gradient(1px 1px at 20% 20%, #fff 100%, transparent),
radial-gradient(2px 2px at 30% 30%, #fff 100%, transparent),
radial-gradient(1px 1px at 40% 40%, #fff 100%, transparent),
radial-gradient(2px 2px at 50% 50%, #fff 100%, transparent),
radial-gradient(1px 1px at 60% 60%, #fff 100%, transparent),
radial-gradient(2px 2px at 70% 70%, #fff 100%, transparent),
radial-gradient(1px 1px at 80% 80%, #fff 100%, transparent),
radial-gradient(1px 1px at 90% 90%, #fff 100%, transparent);
background-size: 200% 200%;
opacity: 0.1;
transition: 0.5s;
}
/* 核心按钮球体 */
.toggle-orb {
position: absolute;
height: 62px;
width: 62px;
left: 4px;
bottom: 4px;
background: linear-gradient(145deg, #ff6b6b, #4ecdc4);
border-radius: 50%;
transition: 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); /* 弹性缓动 */
transform-style: preserve-3d;
z-index: 2;
}
/* 球体内部纹理 */
.inner-orb {
position: absolute;
inset: 5px;
border-radius: 50%;
background: linear-gradient(145deg, #fff, #e6e6e6);
transition: 0.5s;
overflow: hidden;
}
/* 旋转的内部图案 */
.inner-orb::before {
content: "";
position: absolute;
inset: 0;
background: repeating-conic-gradient(
from 0deg,
transparent 0deg,
rgba(0, 0, 0, 0.1) 10deg,
transparent 20deg
);
animation: patternRotate 10s linear infinite;
}
/* 外部光环 */
.ring {
position: absolute;
inset: -3px;
border: 2px solid rgba(255, 255, 255, 0.1);
border-radius: 50%;
transition: 0.5s;
}
/* --- 激活状态 (Checked) --- */
.toggle:checked + .slider {
background: linear-gradient(45deg, #16213e, #1a1a2e);
}
.toggle:checked + .slider .toggle-orb {
transform: translateX(70px) rotate(360deg);
background: linear-gradient(145deg, #4ecdc4, #45b7af);
}
.toggle:checked + .slider .inner-orb {
background: linear-gradient(145deg, #45b7af, #3da89f);
transform: scale(0.9);
}
.toggle:checked + .slider .ring {
border-color: rgba(78, 205, 196, 0.3);
animation: ringPulse 2s infinite;
}
/* --- 能量线特效 --- */
.energy-line {
position: absolute;
width: 100%;
height: 2px;
background: linear-gradient(90deg, transparent, rgba(78, 205, 196, 0.5), transparent);
transform-origin: left;
opacity: 0;
transition: 0.5s;
}
.energy-line:nth-child(1) { top: 20%; transform: rotate(15deg); }
.energy-line:nth-child(2) { top: 50%; transform: rotate(0deg); }
.energy-line:nth-child(3) { top: 80%; transform: rotate(-15deg); }
.toggle:checked + .slider .energy-line {
opacity: 1;
animation: energyFlow 2s linear infinite;
}
/* --- 粒子特效 --- */
.particles {
position: absolute;
width: 100%;
height: 100%;
}
.particle {
position: absolute;
width: 4px;
height: 4px;
background: #4ecdc4;
border-radius: 50%;
opacity: 0;
}
.toggle:checked + .slider .particle {
animation: particleBurst 1s ease-out infinite;
}
/* 粒子位置与延迟 */
.particle:nth-child(1) { left: 20%; animation-delay: 0s; }
.particle:nth-child(2) { left: 40%; animation-delay: 0.2s; }
.particle:nth-child(3) { left: 60%; animation-delay: 0.4s; }
.particle:nth-child(4) { left: 80%; animation-delay: 0.6s; }
.particle:nth-child(5) { left: 30%; animation-delay: 0.8s; }
.particle:nth-child(6) { left: 70%; animation-delay: 1s; }
/* --- 动画关键帧 --- */
@keyframes ringPulse {
0%, 100% { transform: scale(1); opacity: 0.3; }
50% { transform: scale(1.1); opacity: 0.6; }
}
@keyframes patternRotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes energyFlow {
0% { transform: scaleX(0) translateX(0); opacity: 0; }
50% { transform: scaleX(1) translateX(50%); opacity: 1; }
100% { transform: scaleX(0) translateX(100%); opacity: 0; }
}
@keyframes particleBurst {
0% { transform: translate(0, 0) scale(1); opacity: 1; }
100% {
/* 使用 cos/sin 计算爆炸轨迹 */
transform: translate(
calc(cos(var(--angle)) * 50px),
calc(sin(var(--angle)) * 50px)
)
scale(0);
opacity: 0;
}
}
/* --- 鼠标交互 (Hover) --- */
.slider:hover .toggle-orb {
filter: brightness(1.2);
box-shadow: 0 0 20px rgba(78, 205, 196, 0.5), 0 0 40px rgba(78, 205, 196, 0.3);
}
.slider:hover .cosmos {
opacity: 0.2;
animation: cosmosPan 20s linear infinite;
}
@keyframes cosmosPan {
0% { background-position: 0% 0%; }
100% { background-position: 200% 200%; }
}
/* 整体 3D 倾斜效果 */
.cosmic-toggle:hover .slider {
transform: rotateX(10deg) rotateY(10deg);
}
.cosmic-toggle:hover .toggle-orb {
transform: translateZ(10px);
}
</style>
<label class="cosmic-toggle">
<input class="toggle" type="checkbox" />
<div class="slider">
<div class="cosmos"></div>
<div class="energy-line"></div>
<div class="energy-line"></div>
<div class="energy-line"></div>
<div class="toggle-orb">
<div class="inner-orb"></div>
<div class="ring"></div>
</div>
<div class="particles">
<div style="--angle: 30deg" class="particle"></div>
<div style="--angle: 60deg" class="particle"></div>
<div style="--angle: 90deg" class="particle"></div>
<div style="--angle: 120deg" class="particle"></div>
<div style="--angle: 150deg" class="particle"></div>
<div style="--angle: 180deg" class="particle"></div>
</div>
</div>
</label>
```