告别基础加载动画!纯 CSS 实现仿苹果 FaceID 顶级加载效果

还在用水波纹、波浪圆球这类千篇一律的加载动画?纯原生 CSS 实现的仿苹果 FaceID 加载动画,凭借 CSS 自定义属性、SVG 遮罩、多轨关键帧动画的巧妙结合,打造出极具科技感和视觉层次感的动态效果,无需 JavaScript,轻量且高效,直接嵌入项目即可使用。
20260227160613_rec_-convert

效果核心亮点

这款加载动画之所以能还原 FaceID 的科技感,核心在于三个设计巧思:

  1. 多维度视觉层次:通过外层阴影、渐变底色、SVG 遮罩层的叠加,实现立体的光影效果;
  2. 多轨异步动画:多个多边形围绕不同原点旋转,配合延迟差实现错落的动态轨迹,还原 FaceID 的扫描感;
  3. 动态色彩与对比度变化:通过色相旋转和对比度调节,让动画在运动中产生视觉张力,避免单调。

同时,动画全程基于transformfilter实现,不触发页面重排,依托 GPU 加速保证流畅性,符合现代前端性能优化要求。

实现原理拆解

整个动画的实现分为HTML 结构搭建CSS 样式与动画定义两部分,核心用到 CSS 自定义属性、SVG mask 遮罩、@keyframes 关键帧动画三大核心技术,以下逐一对核心逻辑拆解。

1. HTML 结构:极简容器 + SVG 遮罩

HTML 部分仅需一个核心加载容器.loader,内部包含实现遮罩的 SVG 和视觉载体.box,结构极简,无冗余标签:

  • SVG 标签定义mask遮罩层,通过 7 个多边形的组合,形成 FaceID 标志性的扫描轮廓;
  • 遮罩层通过id="clipping"与 CSS 中的mask属性关联,实现对.box元素的视觉裁剪;
  • 外层.loader作为动画主容器,承载所有样式和动画属性。
.loader {
  --color-one: #ffbf48; /* 主色1 */
  --color-two: #be4a1d; /* 主色2 */
  --color-three: #ffbf4780; /* 浅透色1 */
  --color-four: #bf4a1d80; /* 浅透色2 */
  --color-five: #ffbf4740; /* 超透色1 */
  --time-animation: 2s; /* 基础动画时长 */
  --size: 1; /* 整体缩放比例,可直接调整大小 */
}

通过--size缩放属性,只需修改一个值,即可适配不同页面的尺寸需求,无需调整宽高、间距等多个属性。

3. 视觉基底:渐变 + 阴影打造立体光影

动画的基础视觉效果由.loader和其伪元素::before实现,通过线性渐变内外层阴影的组合,打造出圆润的立体光影基底:

  • 外层通过box-shadow添加扩散阴影,模拟发光效果;
  • 伪元素::before设置圆形轮廓,通过上下边框配色、线性渐变背景,实现底色的层次变化;
  • 内层阴影inset进一步强化立体感,让基底更具质感。

4. 核心遮罩:SVG mask 实现轮廓裁剪

这是还原 FaceID 视觉特征的关键步骤,通过CSS mask 属性关联 SVG 中的mask遮罩层,对.box的渐变背景进行裁剪:

  • SVG 中定义 7 个多边形,黑色区域为显示区,白色区域为裁剪区,组合成 FaceID 的扫描轮廓;
  • 为兼容 webkit 内核浏览器,同时设置mask-webkit-mask属性;
  • 对多边形添加blur模糊和contrast对比度滤镜,让轮廓边缘更柔和,还原原生 FaceID 的模糊扫描效果。

5. 动态灵魂:多轨关键帧动画

整个动画的动态效果由三个自定义@keyframes关键帧动画和多元素异步旋转实现,形成错落有致的扫描动效:

(1)rotation:基础旋转动画

定义 0° 到 360° 的线性旋转,作为所有多边形的基础动态,通过设置不同的旋转原点(transform-origin)旋转方向(reverse)动画延迟(animation-delay),让 7 个多边形围绕不同点异步旋转,形成复杂且自然的扫描轨迹。

(2)roundness:对比度动态调节

对遮罩层进行对比度的周期性调节,让扫描轮廓在 “清晰 - 模糊 - 清晰” 之间切换,模拟 FaceID 扫描时的对焦效果,增强动态张力。

(3)colorize:色相旋转动画

对主容器进行hue-rotate色相旋转,让整个动画的色彩在周期内缓慢变化,避免单一色彩的视觉疲劳,同时通过ease-in-out缓动函数,让色彩变化更自然。

HTML:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSS仿FaceID加载动画</title>
  <style>
    /* 此处粘贴下方CSS代码 */
    body {
      margin: 0;
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      background: #111;
    }
  </style>
</head>
<body>
  <div class="loader">
    <svg width="100" height="100" viewBox="0 0 100 100">
      <defs>
        <mask id="clipping">
          <polygon points="0,0 100,0 100,100 0,100" fill="black"></polygon>
          <polygon points="25,25 75,25 50,75" fill="white"></polygon>
          <polygon points="50,25 75,75 25,75" fill="white"></polygon>
          <polygon points="35,35 65,35 50,65" fill="white"></polygon>
          <polygon points="35,35 65,35 50,65" fill="white"></polygon>
          <polygon points="35,35 65,35 50,65" fill="white"></polygon>
          <polygon points="35,35 65,35 50,65" fill="white"></polygon>
        </mask>
      </defs>
    </svg>
    <div class="box"></div>
  </div>
</body>
</html>

CSS

.loader {
  --color-one: #ffbf48;
  --color-two: #be4a1d;
  --color-three: #ffbf4780;
  --color-four: #bf4a1d80;
  --color-five: #ffbf4740;
  --time-animation: 2s;
  --size: 1; /* 调整此值改变动画大小,如1.5为1.5倍 */
  position: relative;
  border-radius: 50%;
  transform: scale(var(--size));
  box-shadow:
    0 0 25px 0 var(--color-three),
    0 20px 50px 0 var(--color-four);
  animation: colorize calc(var(--time-animation) * 3) ease-in-out infinite;
}

.loader::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  border-top: solid 1px var(--color-one);
  border-bottom: solid 1px var(--color-two);
  background: linear-gradient(180deg, var(--color-five), var(--color-four));
  box-shadow:
    inset 0 10px 10px 0 var(--color-three),
    inset 0 -10px 10px 0 var(--color-four);
}

.loader .box {
  width: 100px;
  height: 100px;
  background: linear-gradient(
    180deg,
    var(--color-one) 30%,
    var(--color-two) 70%
  );
  mask: url(#clipping);
  -webkit-mask: url(#clipping);
}

.loader svg {
  position: absolute;
}

.loader svg #clipping {
  filter: contrast(15);
  animation: roundness calc(var(--time-animation) / 2) linear infinite;
}

.loader svg #clipping polygon {
  filter: blur(7px);
}

.loader svg #clipping polygon:nth-child(1) {
  transform-origin: 75% 25%;
  transform: rotate(90deg);
}

.loader svg #clipping polygon:nth-child(2) {
  transform-origin: 50% 50%;
  animation: rotation var(--time-animation) linear infinite reverse;
}

.loader svg #clipping polygon:nth-child(3) {
  transform-origin: 50% 60%;
  animation: rotation var(--time-animation) linear infinite;
  animation-delay: calc(var(--time-animation) / -3);
}

.loader svg #clipping polygon:nth-child(4) {
  transform-origin: 40% 40%;
  animation: rotation var(--time-animation) linear infinite reverse;
}

.loader svg #clipping polygon:nth-child(5) {
  transform-origin: 40% 40%;
  animation: rotation var(--time-animation) linear infinite reverse;
  animation-delay: calc(var(--time-animation) / -2);
}

.loader svg #clipping polygon:nth-child(6) {
  transform-origin: 60% 40%;
  animation: rotation var(--time-animation) linear infinite;
}

.loader svg #clipping polygon:nth-child(7) {
  transform-origin: 60% 40%;
  animation: rotation var(--time-animation) linear infinite;
  animation-delay: calc(var(--time-animation) / -1.5);
}

/* 关键帧动画定义 */
@keyframes rotation {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

@keyframes roundness {
  0% {
    filter: contrast(15);
  }
  20% {
    filter: contrast(3);
  }
  40% {
    filter: contrast(3);
  }
  60% {
    filter: contrast(15);
  }
  100% {
    filter: contrast(15);
  }
}

@keyframes colorize {
  0% {
    filter: hue-rotate(0deg);
  }
  20% {
    filter: hue-rotate(-30deg);
  }
  40% {
    filter: hue-rotate(-60deg);
  }
  60% {
    filter: hue-rotate(-90deg);
  }
  80% {
    filter: hue-rotate(-45deg);
  }
  100% {
    filter: hue-rotate(0deg);
  }
}

总结

完美体现了纯 CSS 实现复杂动态效果的可能性,核心在于对 CSS 自定义属性、mask 遮罩、多轨关键帧动画的灵活组合。相比传统的水波纹、圆球旋转动画,它不仅视觉效果更精致、更具科技感,而且性能更优、可定制性更强,只需几行代码修改,即可融入各类前端项目,提升用户等待时的视觉体验。

告别单调的加载动画,用这款纯 CSS 实现的 FaceID 效果,为你的项目增添一抹高级的科技感吧!

4 个赞

我 C,太爱了!!!

4 个赞

下次记得来这里抄加载

2 个赞

@汤圆 太帅了,多发点这种前端的内容,多写用啥做的,