CSS sibling-index() 实现螺旋滚动特效

我承认:scroll-timeline() 的性能优势我看过,但每次看到那些用 JavaScript 写的华丽滚动网站,心里还是忍不住犯嘀咕——传统的滚动方案真的那么差吗?

直到看到这些网站作者自己跳出来说他们「撞上了真实瓶颈」,移动端「效果打折、构图崩裂」,最后干脆「为了保护第一印象把手机端关了」——我就知道,问题八成出在 JavaScript 性能上。

另一个让我惊艳的滚动实验作者也坦白:文字漩涡那块「如果能给每个字符单独处理,效果肯定更好,但以目前的技术会带来难以承受的性能损耗」。

行,接招。

他无意中给出了一个极具参考价值的性能测试:如何基于滚动平滑地动画化数百个元素。

今天我们就用现代 CSS 复刻一个类似效果——让文字随滚动平滑螺旋。他还提到了 sibling-index(),虽然 Firefox 暂时还不支持,但这不影响我们尝尝鲜。

说好的纯 CSS,还是偷偷用了点 JS

唯一的 JavaScript 用途是把文字拆成单个字符的 div,动画部分完全是纯 CSS。纯 HTML 硬编码也不是不行,就是改起来麻烦。字符拆分用的是 GSAP 旗下的 SplitText 插件,免费开源,用起来很顺手,还自带 aria-label 对屏幕阅读器友好。唯一的小麻烦是空格——我需要每个空格也独立占一个 div 来方便定位,最后用了个特殊空格字符来解决。

const el = document.querySelector(".vortex");
el.innerHTML = el.innerHTML.replaceAll(/\s/g, ⠀);
new SplitText(".title", { type: "chars", charsClass: "char" });
.vortex {
  position: fixed;
  left: 50%;
  height: 100vh;
  animation-name: vortex;
  animation-duration: 20s;
  animation-fill-mode: forwards;
  animation-timeline: scroll();

  .char {
    --radius: calc(10vh - (7vh/sibling-count() * sibling-index()));
    --rotation: calc((360deg * 3/sibling-count()) * sibling-index());
    position: absolute !important;
    top: 50%;
    left: 50%;
    transform: rotate(var(--rotation))
      translateY(calc(-2.9 * var(--radius)))
      scale(calc(.4 - (.25/(sibling-count()) * sibling-index())));
    animation-name: fade-in;
    animation-range-start: calc(90%/var(sibling-count()) * var(--sibling-index()));
    animation-fill-mode: forwards;
    animation-timeline: scroll();
  }
}

公式很简单,效果很惊艳

核心公式就一行:

propertyValue = startValue - ((reductionValue/totalCharacters) * characterIndex)

第一个字符取最大值,后面的字符按索引依次递减一点,最终螺旋向内收敛到目标值。这套公式同时控制了 scale、rotation 和离中心距离三个属性。

如果目标是排成一个圆而不是螺旋,本来可以用 CSS 三角函数。但螺旋的算法更简洁,连三角函数都省了——原来那个 JavaScript 版本也没有用三角函数。滚动本身就更简单了:只需要对父容器做缩放和旋转,就产生了观众被吸入漩涡的视觉感。

唯一单独应用到字符上的动画是 fade-in,通过递增 animation-range-start 让每个字符在滚动时依次延迟淡入。

写到这里我突然意识到:我们之所以频繁依赖 JavaScript,往往只是因为它能基于元素索引来操作样式。一旦 sibling-index() 进入 Baseline,许多这类效果都可以用纯 CSS 重写。你还想到什么例子?欢迎留言!

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容