type
status
date
slug
summary
tags
category
icon
password
Meta Description: 学习如何仅用 CSS (结合
border-image, mix-blend-mode, CSS 滚动驱动动画 animation-timeline) 创建一个与页面滚动联动的逼真卷轴效果。包含速度优化、浏览器兼容性处理及 JS 回退方案。(文章正文)
引言:打造吸睛的滚动交互效果
在网页设计中,富有创意的滚动交互效果总能吸引用户的目光。本文将带你一步步探索如何使用纯 CSS 技术,结合一些巧妙的视觉技巧,实现一个与页面滚动同步的卷轴动画效果,为你的网站增添独特的古典韵味。
一、 揭秘 CSS 卷轴滚动的“魔法”原理
首先需要明确,CSS 本身并没有提供真正的 3D 滚动机制来模拟卷轴。我们看到的效果,实际上是通过 2D 平移动画 结合 视觉特效 (如混合模式、阴影) 模拟出来的“伪 3D”滚动。
核心思路: 让卷轴的纹理图片进行无缝的垂直平移动画,并将其巧妙地融合到卷轴背景中。
1. 构建卷轴结构 (border-image)
我们先搭建基本的 HTML 结构:
卷轴的视觉结构,我们可以使用一张特殊的素材图片:
这张图片设计为两边固定,中间区域可拉伸。这种需求非常适合使用 CSS 的
border-image 属性来实现。我们需要指定图片的分割线,告诉浏览器哪些部分是边角(不拉伸),哪些部分是边缘(可重复或拉伸)。关于 border-image: 它允许你使用图片作为元素的边框。其语法较为复杂,包含 source, slice, width, outset, repeat 等部分。这里我们使用 fill 关键字让图片填充背景区域,并通过 slice (42 36) 和 width (14px 12px) 定义了切割和边框宽度。详细用法可查阅 MDN 文档。
具体 CSS 实现如下:
应用样式后,卷轴的基本结构就出现了:
2. 添加滚动纹理与动画
接下来,我们需要为卷轴添加滚动的“内容”——纹理。素材如下:
我们将这个纹理图片作为
.reel-bg 元素的背景,并让它进行无限循环的垂直平移动画。关键在于背景图的高度要设置为纹理实际需要滚动距离的两倍(例如,如果纹理本身高 184px,背景 height 设置为 368px,background-size 为 auto 50%),这样动画从 translateY(-50%) 到 translateY(0%) 时,就能实现无缝滚动效果。初始效果(无混合模式):
这个效果看起来很“平”,纹理像是贴在表面,没有融入卷轴的凹槽感。
3. 提升真实感 (mix-blend-mode)
为了让纹理看起来像是卷轴本身的一部分,我们需要使用 CSS 混合模式 (Blend Modes)。
mix-blend-mode: multiply; (正片叠底) 是一个不错的选择,它可以将元素的颜色与背景颜色相乘,暗色区域会叠加,产生融入的效果。应用
mix-blend-mode: multiply; 后的效果:现在看起来立体感强多了!
(注:前面已将
overflow: hidden 和 box-shadow 添加到 .reel 样式中,确保纹理不出界并增加阴影。)最终静态滚动效果:
二、联动页面滚动:CSS 滚动驱动动画 (animation-timeline)
现在我们已经有了一个自顾自滚动的卷轴,如何让它的滚动与整个页面的滚动关联起来呢?这就要用到强大的 CSS 滚动驱动动画 (Scroll-Driven Animations)。
CSS 滚动驱动动画简介: 这是一项较新的 CSS 功能,允许动画的进度直接由滚动容器(如 window 或某个 div)的滚动位置来控制,而不再依赖于时间。核心属性是 animation-timeline。
1. 页面布局与样式
首先,我们需要一个可滚动的页面布局。这里我们设置卷轴固定在顶部 (
position: sticky),下方是可滚动的内容区域 (<article>)。相应的 CSS 样式(美化页面,实现 sticky 布局):
布局效果(注意顶部的遮挡伪元素):
2. 应用 animation-timeline
现在,我们将
.reel-bg 的动画与页面(根元素 html 或 body,即 root)的滚动时间线关联起来。只需添加 animation-timeline 属性:现在,当你滚动页面时,卷轴就会跟着“转动”了!
<img src="https://mmbiz.qpic.cn/mmbiz_gif/xvBbEKrVNtIpsKuUwOEo4qufWnCtBv8D2g70Us5S5XbHcRasPGowibibFCIJjtSuATuWbPeE0Ziaw5spWSmXrpmnQ/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="卷轴动画与页面滚动联动效果 (animation-timeline)">
但是,你可能会发现一个问题:卷轴转得似乎太慢了。
原因: 默认情况下,
animation-timeline: scroll(root) 会将整个页面的滚动范围(从顶部滚动到底部)映射到动画的一次完整播放(0% 到 100%)。如果页面内容很长,滚动距离很大,那么卷轴完成一圈就需要滚动很远,看起来自然就慢了。三、优化卷轴滚动速度与平滑度
如何让卷轴滚动速度更符合预期,并且不受页面内容长短的影响?
方法一:增加动画迭代次数 (简单但不完美)
一个简单的想法是让动画在整个滚动过程中重复播放多次。可以通过
animation-iteration-count (或在 animation 简写中指定次数) 实现:效果:
这样速度确实变快了。但这种方法不够理想,因为最佳的迭代次数与页面内容的总高度强相关。如果内容是动态加载的,你需要动态调整这个次数,比较麻烦。
方法二:结合 animation-range 实现匀速滚动 (推荐)
更健壮的方法是使用 CSS 滚动驱动动画的另一个属性:
animation-range。它允许我们自定义动画在哪段滚动区间内播放。我们可以设定一个非常大的虚拟滚动范围,并结合计算出的迭代次数,让卷轴在实际滚动过程中保持一个相对恒定的“视觉速度”。
思路:
- 设置一个足够大的
animation-range-end值 (例如999999px)。这意味着页面需要滚动这么远,动画才会完成一次。
- 根据这个大范围和我们期望卷轴“滚动一圈”对应的实际像素距离,计算出动画需要重复播放的总次数 (
animation-iteration-count)。
解释:
animation-range: 0 calc(var(--scroll-range-end) * 1px);定义了动画从页面滚动 0px 开始,到滚动999999px结束(理论上)。
animation-iteration-count计算了在这个巨大的虚拟范围内,动画应该播放多少次。这里的var(--texture-height) / var(--pi)可以理解为模拟卷轴滚动一圈所对应的页面滚动距离(这个值可以根据视觉效果调整)。
- 这样,无论页面实际可滚动距离是多少,卷轴的转动速度都会由
(单圈高度 * Pi)这个相对固定的值决定,看起来更加匀速和自然。
最终效果(匀速滚动):
核心代码精简:
四、处理浏览器兼容性:CSS @supports 与 JS 回退
CSS 滚动驱动动画目前(截至 2024 年初)还是一个较新的特性,并非所有浏览器都支持。
因此,在生产环境中使用时,必须考虑兼容性处理。
1. CSS @supports 检测与优雅降级
我们可以使用 CSS 的
@supports 规则来检测浏览器是否支持 animation-timeline。如果支持,则应用滚动驱动动画;如果不支持,则不应用(卷轴保持静止或使用基础动画)。2. JavaScript 回退方案 (可选)
如果希望在不支持 CSS 滚动驱动动画的浏览器中也实现类似的滚动联动效果,就需要借助 JavaScript。
思路: 监听
window 的 scroll 事件,获取当前的滚动位置 (window.scrollY 或 document.documentElement.scrollTop),然后根据滚动位置计算出纹理背景 (reel-bg) 应该处于的 transform: translateY 值。JS 回退方案在 Safari 等浏览器中的效果:
在线示例:
- CodePen Demo: CSS QYN book (codepen.io) (请替换为实际链接)
- 掘金文章对应示例: CSS QYN book (juejin.cn) (请替换为实际链接)
- 手机扫码体验:
五、总结与回顾
本文详细介绍了如何利用现代 CSS 技术创建一个与页面滚动联动的卷轴动画效果。关键知识点包括:
- 视觉原理: 通过纹理的垂直平移动画结合混合模式 (
mix-blend-mode: multiply;) 和阴影 (box-shadow) 模拟出滚动的立体感。
- 结构实现: 使用
border-image快速构建出自适应的卷轴边框结构。
- 滚动联动: 核心是 CSS 滚动驱动动画 (
animation-timeline: scroll(root);),将动画进度绑定到页面滚动。
- 速度优化: 通过结合
animation-range和计算出的animation-iteration-count,实现不受内容长度影响的、视觉上更匀速的滚动效果。
- 兼容性处理: 利用
@supports检测浏览器支持情况,并提供 JavaScript 回退方案,确保在不同浏览器下都能提供良好体验。
这个有趣的交互效果不仅展示了 CSS 的强大能力,也提醒我们在追求炫酷效果的同时,要关注性能和兼容性。希望你通过本文学到了新的知识和技巧!
上一篇
React 数字动画 Hook 实战:用 requestAnimationFrame 创建平滑计数效果 (附源码与优化)
下一篇
前端必备:详解 XHR 与 Fetch 获取请求进度 (下载/上传进度条,面试常问)
- 作者:90_blog
- 链接:https://blog.tri7e.com/article/css_jaunzhou
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
