Files
hunli/vite-tailwindcss/src/styles/animations.css
2026-08-12 13:52:54 +08:00

212 lines
7.4 KiB
CSS

/* ============================================================
婚礼纪 · 动效样式库
集中管理关键帧与可复用动画工具类
============================================================ */
/* ---------- 滚动入场 (配合 v-reveal 指令) ---------- */
.reveal {
opacity: 0;
transition:
opacity 1.1s cubic-bezier(0.25, 0.46, 0.45, 0.94),
transform 1.1s cubic-bezier(0.25, 0.46, 0.45, 0.94),
filter 1.1s ease;
will-change: opacity, transform, filter;
}
.reveal-up { transform: translateY(48px); }
.reveal-down { transform: translateY(-48px); }
.reveal-left { transform: translateX(-56px); }
.reveal-right { transform: translateX(56px); }
.reveal-scale { transform: scale(0.9); }
.reveal-blur { transform: scale(1.04); filter: blur(14px); }
/* 明信片飞入:带轻微旋转,弹性回正(单图明信片/异形边框用) */
.reveal-postcard {
transform: translateY(70px) rotate(-7deg) scale(0.94);
transform-origin: 50% 80%;
transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.reveal--in { opacity: 1; transform: none; filter: none; }
@media (prefers-reduced-motion: reduce) {
/* filter 只清 blur 变体:同元素可能还有 .gf-shape-shadow 的 drop-shadow */
.reveal { opacity: 1 !important; transform: none !important; transition: none; }
.reveal-blur { filter: none !important; }
}
/* ---------- 邮戳盖章(单图 明信片/邮票 边框的入场收尾) ---------- */
.gf-postmark {
position: absolute;
top: 16px;
right: 14px;
width: 56px;
height: 56px;
border-radius: 50%;
border: 2px solid rgba(187, 72, 62, 0.85);
outline: 1px solid rgba(187, 72, 62, 0.5);
outline-offset: -7px;
color: rgba(187, 72, 62, 0.9);
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-calligraphy, serif);
font-size: 22px;
line-height: 1;
transform: rotate(-14deg);
opacity: 0;
pointer-events: none;
z-index: 2;
}
.gf-postmark::before { content: '囍'; }
.reveal--in .gf-postmark {
animation: postmarkStamp 0.55s cubic-bezier(0.2, 1.4, 0.45, 1) 0.65s both;
}
@keyframes postmarkStamp {
0% { opacity: 0; transform: rotate(-14deg) scale(1.9); }
55% { opacity: 0.95; transform: rotate(-14deg) scale(0.92); }
75% { transform: rotate(-14deg) scale(1.05); }
100% { opacity: 0.9; transform: rotate(-14deg) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
.reveal--in .gf-postmark { animation: none; opacity: 0.9; }
}
/* ---------- 飘落花瓣(优雅:柔和渐变 + 轻微摇曳) ---------- */
/* 性能约定:摇曳动画一律作用在内层元素的 transform 上,
外层只跑位移动画 —— 全程合成层处理,不触发布局。 */
@keyframes petalFall {
0% { transform: translate3d(0, -12vh, 0) rotate(0deg); opacity: 0; }
10% { opacity: 0.8; }
90% { opacity: 0.65; }
100% { transform: translate3d(6vw, 112vh, 0) rotate(360deg); opacity: 0; }
}
@keyframes petalDrift {
0%, 100% { transform: translateX(-12px) rotate(-7deg); }
50% { transform: translateX(12px) rotate(7deg); }
}
.petal {
position: absolute;
top: 0;
pointer-events: none;
will-change: transform, opacity;
animation: petalFall var(--p-dur, 12s) linear infinite;
}
.petal-inner {
display: block;
width: 100%;
height: 100%;
will-change: transform;
animation: petalDrift var(--p-sway, 6s) ease-in-out infinite alternate;
}
/* ---------- 漂浮爱心(全屏自然上升,三层景深) ---------- */
@keyframes heartFloat {
0% { transform: translate3d(0, 20px, 0) scale(0.7); opacity: 0; }
12% { opacity: var(--h-opacity, 0.7); }
85% { opacity: calc(var(--h-opacity, 0.7) * 0.75); }
100% { transform: translate3d(24px, -118vh, 0) scale(1.08); opacity: 0; }
}
@keyframes heartSway {
0%, 100% { transform: translateX(-14px) scale(0.97); }
50% { transform: translateX(14px) scale(1.03); }
}
.heart-bubble {
position: absolute;
will-change: transform, opacity;
animation: heartFloat var(--float-duration, 18s) linear infinite;
}
.heart-inner {
display: inline-block;
will-change: transform;
animation: heartSway var(--sway-duration, 5s) ease-in-out infinite alternate;
}
/* ---------- 背景柔光层(淡金/淡粉光斑,缓慢漂移,不喧宾夺主) ---------- */
.bg-glow { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.bg-glow i { position: absolute; border-radius: 50%; filter: blur(46px); will-change: transform; }
.bg-glow .g1 {
width: 300px; height: 300px; top: -90px; right: -70px;
background: radial-gradient(circle, rgba(233, 206, 168, 0.5), transparent 68%);
animation: glowDrift1 17s ease-in-out infinite alternate;
}
.bg-glow .g2 {
width: 260px; height: 260px; bottom: -80px; left: -60px;
background: radial-gradient(circle, rgba(244, 194, 194, 0.42), transparent 68%);
animation: glowDrift2 21s ease-in-out infinite alternate;
}
.bg-glow .g3 {
width: 210px; height: 210px; top: 38%; left: 58%;
background: radial-gradient(circle, rgba(212, 175, 55, 0.16), transparent 70%);
animation: glowDrift3 24s ease-in-out infinite alternate;
}
@keyframes glowDrift1 { to { transform: translate(-34px, 26px) scale(1.08); } }
@keyframes glowDrift2 { to { transform: translate(30px, -24px) scale(1.06); } }
@keyframes glowDrift3 { to { transform: translate(-26px, 20px) scale(1.12); } }
/* ---------- 心跳脉冲 ---------- */
@keyframes pulseHeart {
0%, 100% { transform: scale(1); }
15% { transform: scale(1.25); }
30% { transform: scale(1); }
45% { transform: scale(1.18); }
60% { transform: scale(1); }
}
.animate-pulse-heart { animation: pulseHeart 2.4s ease-in-out infinite; }
/* ---------- 旋转 ---------- */
@keyframes spin { to { transform: rotate(360deg); } }
.rotate-spin { animation: spin 4s linear infinite; }
/* ---------- 入场揭幕 (封面帘幕) ---------- */
@keyframes curtainRise {
0% { transform: translateY(0); }
100% { transform: translateY(-100%); }
}
.curtain {
animation: curtainRise 1.4s cubic-bezier(0.76, 0, 0.24, 1) 1.6s forwards;
}
@keyframes curtainSeal {
0% { transform: scaleX(0); opacity: 0; }
60% { transform: scaleX(1); opacity: 1; }
100% { transform: scaleX(1); opacity: 1; }
}
.curtain-seal {
transform-origin: center;
animation: curtainSeal 1.2s cubic-bezier(0.22, 1, 0.36, 1) both;
}
/* ---------- 渐变流光文字 ---------- */
@keyframes gradientShift { to { background-position: 200% center; } }
.gradient-text {
background: linear-gradient(90deg, var(--c-primary), #e8a5b2, #d4af37, var(--c-primary));
background-size: 200% auto;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: gradientShift 6s linear infinite;
}
/* ---------- 柔光呼吸 ---------- */
@keyframes softFloat {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.float-soft { animation: softFloat 6s ease-in-out infinite; }
/* ---------- 成功提交弹入 ---------- */
@keyframes fadeUp {
0% { opacity: 0; transform: translateY(20px); }
100% { opacity: 1; transform: translateY(0); }
}
.animate-fade-up { animation: fadeUp 0.7s cubic-bezier(0.22, 1, 0.36, 1) both; }
/* ---------- 微光描边 ---------- */
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
.shimmer-line {
background: linear-gradient(90deg, transparent, rgba(var(--c-primary-rgb),0.6), transparent);
background-size: 200% 100%;
animation: shimmer 3s linear infinite;
}