theme-toggle-effect

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

When to Use

适用场景

Use this skill when:
  • Implementing light/dark mode toggle with smooth animations
  • Creating theme transitions using View Transitions API
  • Building custom SVG mask animations for theme switching
  • Needing polygon or circular reveal effects

在以下场景中使用该技巧:
  • 实现带平滑动画的明暗模式切换
  • 使用View Transitions API创建主题过渡效果
  • 为主题切换构建自定义SVG遮罩动画
  • 需要多边形或圆形渐显效果

Critical Patterns

核心实现模式

The ONLY JavaScript you need:
javascript
if (!document.startViewTransition) switchTheme();
document.startViewTransition(switchTheme);
Required CSS animation timing functions:
css
:root {
  --expo-out: linear(
    0 0%, 0.1684 2.66%, 0.3165 5.49%,
    0.446 8.52%, 0.5581 11.78%,
    0.6535 15.29%, 0.7341 19.11%,
    0.8011 23.3%, 0.8557 27.93%,
    0.8962 32.68%, 0.9283 38.01%,
    0.9529 44.08%, 0.9711 51.14%,
    0.9833 59.06%, 0.9915 68.74%, 1 100%
  );
  --expo-in: linear(
    0 0%, 0.0085 31.26%, 0.0167 40.94%,
    0.0289 48.86%, 0.0471 55.92%,
    0.0717 61.99%, 0.1038 67.32%,
    0.1443 72.07%, 0.1989 76.7%,
    0.2659 80.89%, 0.3465 84.71%,
    0.4419 88.22%, 0.554 91.48%,
    0.6835 94.51%, 0.8316 97.34%, 1 100%
  );
}

你仅需以下这段JavaScript代码:
javascript
if (!document.startViewTransition) switchTheme();
document.startViewTransition(switchTheme);
所需CSS动画时间函数:
css
:root {
  --expo-out: linear(
    0 0%, 0.1684 2.66%, 0.3165 5.49%,
    0.446 8.52%, 0.5581 11.78%,
    0.6535 15.29%, 0.7341 19.11%,
    0.8011 23.3%, 0.8557 27.93%,
    0.8962 32.68%, 0.9283 38.01%,
    0.9529 44.08%, 0.9711 51.14%,
    0.9833 59.06%, 0.9915 68.74%, 1 100%
  );
  --expo-in: linear(
    0 0%, 0.0085 31.26%, 0.0167 40.94%,
    0.0289 48.86%, 0.0471 55.92%,
    0.0717 61.99%, 0.1038 67.32%,
    0.1443 72.07%, 0.1989 76.7%,
    0.2659 80.89%, 0.3465 84.71%,
    0.4419 88.22%, 0.554 91.48%,
    0.6835 94.51%, 0.8316 97.34%, 1 100%
  );
}

Effect 1: Circle

效果1:圆形

Simple circular mask that expands from center.
css
/* circle */

::view-transition-group(root) {
  animation-timing-function: var(--expo-out);
}
::view-transition-old(root),
.dark::view-transition-old(root) {
  animation: none;
  animation-fill-mode: both;
  z-index: -1;
}
::view-transition-new(root) {
  mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><circle cx="20" cy="20" r="20" fill="white"/></svg>') center / 0 no-repeat;
  animation: scale 1s;
  animation-fill-mode: both;
}
@keyframes scale {
  to {
    mask-size: 200vmax;
  }
}

从中心向外展开的简单圆形遮罩。
css
/* circle */

::view-transition-group(root) {
  animation-timing-function: var(--expo-out);
}
::view-transition-old(root),
.dark::view-transition-old(root) {
  animation: none;
  animation-fill-mode: both;
  z-index: -1;
}
::view-transition-new(root) {
  mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><circle cx="20" cy="20" r="20" fill="white"/></svg>') center / 0 no-repeat;
  animation: scale 1s;
  animation-fill-mode: both;
}
@keyframes scale {
  to {
    mask-size: 200vmax;
  }
}

Effect 2: Circle with Blur

效果2:带模糊的圆形

Circular mask with Gaussian blur for a soft glow effect.
css
/* circle-with-blur */

::view-transition-group(root) {
  animation-timing-function: var(--expo-out);
}
::view-transition-new(root) {
  mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><defs><filter id="blur"><feGaussianBlur stdDeviation="2"/></filter></defs><circle cx="20" cy="20" r="18" fill="white" filter="url(%23blur)"/></svg>') center / 0 no-repeat;
  animation: scale 1s;
  animation-fill-mode: both;
}
::view-transition-old(root),
.dark::view-transition-old(root) {
  animation: none;
  animation-fill-mode: both;
  z-index: -1;
}
.dark::view-transition-new(root) {
  animation: scale 1s;
  animation-fill-mode: both;
}
@keyframes scale {
  to {
    mask-size: 200vmax;
  }
}

带高斯模糊的圆形遮罩,呈现柔和发光效果。
css
/* circle-with-blur */

::view-transition-group(root) {
  animation-timing-function: var(--expo-out);
}
::view-transition-new(root) {
  mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><defs><filter id="blur"><feGaussianBlur stdDeviation="2"/></filter></defs><circle cx="20" cy="20" r="18" fill="white" filter="url(%23blur)"/></svg>') center / 0 no-repeat;
  animation: scale 1s;
  animation-fill-mode: both;
}
::view-transition-old(root),
.dark::view-transition-old(root) {
  animation: none;
  animation-fill-mode: both;
  z-index: -1;
}
.dark::view-transition-new(root) {
  animation: scale 1s;
  animation-fill-mode: both;
}
@keyframes scale {
  to {
    mask-size: 200vmax;
  }
}

Effect 3: Circle Blur Top Left

效果3:左上角模糊圆形

Circular mask with blur, pivoting from top-left corner.
css
/* circle-blur-top-left */

::view-transition-group(root) {
  animation-timing-function: var(--expo-out);
}
::view-transition-new(root) {
  mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><defs><filter id="blur"><feGaussianBlur stdDeviation="2"/></filter></defs><circle cx="0" cy="0" r="18" fill="white" filter="url(%23blur)"/></svg>') top left / 0 no-repeat;
  mask-origin: content-box;
  animation: scale 1s;
  animation-fill-mode: both;
  transform-origin: top left;
}
::view-transition-old(root),
.dark::view-transition-old(root) {
  animation: scale 1s;
  animation-fill-mode: both;
  transform-origin: top left;
  z-index: -1;
}
@keyframes scale {
  to {
    mask-size: 350vmax;
  }
}

带模糊效果的圆形遮罩,从左上角开始展开。
css
/* circle-blur-top-left */

::view-transition-group(root) {
  animation-timing-function: var(--expo-out);
}
::view-transition-new(root) {
  mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><defs><filter id="blur"><feGaussianBlur stdDeviation="2"/></filter></defs><circle cx="0" cy="0" r="18" fill="white" filter="url(%23blur)"/></svg>') top left / 0 no-repeat;
  mask-origin: content-box;
  animation: scale 1s;
  animation-fill-mode: both;
  transform-origin: top left;
}
::view-transition-old(root),
.dark::view-transition-old(root) {
  animation: scale 1s;
  animation-fill-mode: both;
  transform-origin: top left;
  z-index: -1;
}
@keyframes scale {
  to {
    mask-size: 350vmax;
  }
}

Effect 4: Polygon

效果4:多边形

Polygon clip-path reveal effect (no blur support).
css
/* polygon */

::view-transition-group(root) {
  animation-duration: 0.7s;
  animation-timing-function: var(--expo-out);
}
::view-transition-new(root) {
  animation-name: reveal-light;
  animation-fill-mode: both;
}
::view-transition-old(root),
.dark::view-transition-old(root) {
  animation: none;
  animation-fill-mode: both;
  z-index: -1;
}
.dark::view-transition-new(root) {
  animation-name: reveal-dark;
  animation-fill-mode: both;
}
@keyframes reveal-dark {
  from {
    clip-path: polygon(50% -71%, -50% 71%, -50% 71%, 50% -71%);
  }
  to {
    clip-path: polygon(50% -71%, -50% 71%, 50% 171%, 171% 50%);
  }
}
@keyframes reveal-light {
  from {
    clip-path: polygon(171% 50%, 50% 171%, 50% 171%, 171% 50%);
  }
  to {
    clip-path: polygon(171% 50%, 50% 171%, -50% 71%, 50% -71%);
  }
}

多边形裁剪路径渐显效果(不支持模糊)。
css
/* polygon */

::view-transition-group(root) {
  animation-duration: 0.7s;
  animation-timing-function: var(--expo-out);
}
::view-transition-new(root) {
  animation-name: reveal-light;
  animation-fill-mode: both;
}
::view-transition-old(root),
.dark::view-transition-old(root) {
  animation: none;
  animation-fill-mode: both;
  z-index: -1;
}
.dark::view-transition-new(root) {
  animation-name: reveal-dark;
  animation-fill-mode: both;
}
@keyframes reveal-dark {
  from {
    clip-path: polygon(50% -71%, -50% 71%, -50% 71%, 50% -71%);
  }
  to {
    clip-path: polygon(50% -71%, -50% 71%, 50% 171%, 171% 50%);
  }
}
@keyframes reveal-light {
  from {
    clip-path: polygon(171% 50%, 50% 171%, 50% 171%, 171% 50%);
  }
  to {
    clip-path: polygon(171% 50%, 50% 171%, -50% 71%, 50% -71%);
  }
}

Effect 5: Polygon Gradient

效果5:渐变多边形

Custom SVG with linear gradient for gradient reveal effects.
css
/* polygon-gradient - requires custom-svg.svg asset */

::view-transition-group(root) {
  animation-timing-function: var(--expo-out);
}
::view-transition-new(root) {
  mask: url('assets/custom-svg.svg') top left / 0 no-repeat;
  mask-origin: top left;
  animation: scale 1.5s;
  animation-fill-mode: both;
}
::view-transition-old(root),
.dark::view-transition-old(root) {
  animation: scale 1.5s;
  animation-fill-mode: both;
  z-index: -1;
  transform-origin: top left;
}
@keyframes scale {
  to {
    mask-size: 200vmax;
  }
}
Required
assets/custom-svg.svg
:
xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">
  <defs>
    <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" style="stop-color:white;stop-opacity:1" />
      <stop offset="100%" style="stop-color:white;stop-opacity:1" />
    </linearGradient>
  </defs>
  <polygon points="0,0 40,0 40,40" fill="url(#gradient)"/>
</svg>

自定义SVG线性渐变实现渐变渐显效果。
css
/* polygon-gradient - requires custom-svg.svg asset */

::view-transition-group(root) {
  animation-timing-function: var(--expo-out);
}
::view-transition-new(root) {
  mask: url('assets/custom-svg.svg') top left / 0 no-repeat;
  mask-origin: top left;
  animation: scale 1.5s;
  animation-fill-mode: both;
}
::view-transition-old(root),
.dark::view-transition-old(root) {
  animation: scale 1.5s;
  animation-fill-mode: both;
  z-index: -1;
  transform-origin: top left;
}
@keyframes scale {
  to {
    mask-size: 200vmax;
  }
}
所需
assets/custom-svg.svg
文件:
xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">
  <defs>
    <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" style="stop-color:white;stop-opacity:1" />
      <stop offset="100%" style="stop-color:white;stop-opacity:1" />
    </linearGradient>
  </defs>
  <polygon points="0,0 40,0 40,40" fill="url(#gradient)"/>
</svg>

Quick Reference

快速参考

EffectComplexityBlur SupportGradient Support
CircleSimpleNoNo
Circle with BlurSimpleYesNo
Circle Blur Top LeftMediumYesNo
PolygonMediumNoNo
Polygon GradientAdvancedYesYes

效果复杂度模糊支持渐变支持
圆形简单
带模糊的圆形简单
左上角模糊圆形中等
多边形中等
渐变多边形高级

Resources

资源