纯CSS实现电影《极限审判》中的倒计时效果

468 阅读4分钟

前言

最近在电影院看了一部AI主题的科幻惊悚片《Mercy》(极限审判),Chris Pratt 饰演的主角需要在 90 分钟内向 AI 法官证明自己的清白。

image.png

这部电影有个非常巧妙的设计——全片都有一个倒计时器在屏幕上显示,让观众和主角一起感受时间的紧迫。这个倒计时组件的设计相当精美,于是我决定用纯 CSS 来复刻一个类似的效果。

最终效果

先来看看最终实现的效果,采用了苹果液态玻璃(Liquid Glass)风格:

核心原理

这个倒计时效果的核心原理其实非常简单:垂直堆叠数字 + overflow:hidden + CSS动画位移

1. 数字堆叠结构

每一位数字实际上是多个数字垂直堆叠在一个容器中,容器设置 overflow: hidden,只显示其中一个数字:

<div class="time-part seconds ones">
  <div class="digit-wrapper">
    <!-- 9,8,7,6,5,4,3,2,1,0,9 - 末尾重复9实现无缝循环 -->
    <span class="digit">9</span>
    <span class="digit">8</span>
    <span class="digit">7</span>
    <span class="digit">6</span>
    <span class="digit">5</span>
    <span class="digit">4</span>
    <span class="digit">3</span>
    <span class="digit">2</span>
    <span class="digit">1</span>
    <span class="digit">0</span>
    <span class="digit">9</span>
    <!-- 重复的9,用于无缝循环 -->
  </div>
</div>
.time-part {
  height: var(--digit-height);
  overflow: hidden; /* 只显示一个数字 */
}

.digit {
  display: inline-block;
  height: var(--digit-height);
  line-height: 1;
}

2. 动画位移实现倒计时

通过 CSS @keyframes 动画,让 digit-wrapper 向上位移,从而显示不同的数字:

@keyframes animate-10 {
  0% {
    transform: translateY(0);
  } /* 显示 9 */
  10% {
    transform: translateY(calc(var(--digit-height) * -1));
  } /* 显示 8 */
  20% {
    transform: translateY(calc(var(--digit-height) * -2));
  } /* 显示 7 */
  30% {
    transform: translateY(calc(var(--digit-height) * -3));
  } /* 显示 6 */
  40% {
    transform: translateY(calc(var(--digit-height) * -4));
  } /* 显示 5 */
  50% {
    transform: translateY(calc(var(--digit-height) * -5));
  } /* 显示 4 */
  60% {
    transform: translateY(calc(var(--digit-height) * -6));
  } /* 显示 3 */
  70% {
    transform: translateY(calc(var(--digit-height) * -7));
  } /* 显示 2 */
  80% {
    transform: translateY(calc(var(--digit-height) * -8));
  } /* 显示 1 */
  90% {
    transform: translateY(calc(var(--digit-height) * -9));
  } /* 显示 0 */
  100% {
    transform: translateY(calc(var(--digit-height) * -10));
  } /* 显示重复的 9 */
}

3. 无缝循环的秘密 ✨

这是整个效果最精妙的地方!

注意数字列表的末尾有一个重复的 9。当动画运行到 100% 时,显示的是这个重复的 9。当动画循环回到 0% 时,translateY 重置为 0,但此时显示的仍然是 9(列表开头的那个)。

视觉上数字没有任何变化,实现了完美的无缝循环!

20260130012324_rec_.gif

截了一个长图方便理解原理

4. 震动效果

为了让倒计时更有紧迫感,我给秒钟的个位数添加了一个微妙的震动效果——数字切换时会先向上过冲一点,然后回弹到正确位置

@keyframes animate-10-vibrate {
  /* 显示 8 */
  17% {
    transform: translateY(calc(var(--digit-height) * -1));
  } /* 保持在 8 */
  18.5% {
    transform: translateY(calc(var(--digit-height) * -2.15));
  } /* 过冲!超过目标位置 */
  20% {
    transform: translateY(calc(var(--digit-height) * -2));
  } /* 回弹到 7 */

  /* ... 其他数字同理 */
}

效果如下:

20260130011654_rec_.gif

这个 -2.15 中的 .15 就是过冲量,可以根据需要调整震动的强度。

5. 不同位数的动画配置

倒计时器有分钟、秒钟、百分秒三个部分,每个部分的十位和个位动画周期不同:

/* 秒钟个位:0-9,每10秒循环一次 */
.time-part.seconds.ones .digit-wrapper {
  animation-name: animate-10-vibrate;
  animation-duration: 10s;
  animation-iteration-count: 360; /* 1小时内循环360次 */
}

/* 秒钟十位:0-5,每60秒循环一次 */
.time-part.seconds.tens .digit-wrapper {
  animation-name: animate-6;
  animation-duration: 60s;
  animation-iteration-count: 60;
}

/* 百分秒:更新更快,不需要震动效果 */
.time-part.hundredths .digit-wrapper {
  animation-timing-function: cubic-bezier(1, 0, 1, 0); /* 瞬间切换 */
}

液态玻璃风格

为了让界面更加现代化,我采用了苹果最新的液态玻璃(Liquid Glass)设计风格:

.wrapper {
  /* 毛玻璃效果 */
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);

  /* 玻璃边框和阴影 */
  border-radius: 24px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.3),
    inset 0 1px 0 rgba(255, 255, 255, 0.1);
}

配合深色渐变背景和浮动的光晕效果,营造出科幻电影的氛围感。

总结

这个纯 CSS 倒计时效果的核心技巧:

  1. 数字堆叠 + overflow:hidden — 基础结构
  2. translateY 动画 — 实现数字滚动
  3. 重复末尾数字 — 实现无缝循环
  4. 过冲回弹 — 添加震动效果
  5. 不同周期配置 — 分钟/秒钟/百分秒协调运转

整个效果不依赖任何 JavaScript,完全由 CSS 驱动,性能优秀,兼容性好。

希望这篇文章对你有帮助,如果觉得不错欢迎点赞收藏 👍


完整代码可以在码上掘金中查看和运行