A single page · 2026
极光·边界
你脚下的这片流动极光,是一枚实时光线步进的 WebGL2 片元着色器。
而这一页里所有的滚动魔法,几乎全部由 CSS 独立完成——没有一行滚动监听。
向下滚动,页面的色相会随你的位置环游整个色轮。
第一章 · GPU 上的诗
背景不是视频,
是每帧现算的数学。
你看到的极光由 fbm(分形布朗运动)噪声场驱动:六个八度的值噪声互相叠加、扭曲,
再按滚动深度改变流速与色相,按鼠标位置弯曲流场。全部计算发生在 GPU 上,
每一帧、每一个像素、并行完成——这是任何视频素材都做不到的:它永不重复,且只有几 KB。
// 片元着色器核心:域扭曲的分形噪声 float fbm(vec2 p) { float v = 0.0, a = 0.5; for (int i = 0; i < 6; i++) { v += a * noise(p); p = p * 2.03 + vec2(1.7, 9.2); // 旋转+平移打破网格感 a *= 0.5; } return v; } // q 与 r:两层域扭曲,让噪声"流动"起来 vec2 q = vec2(fbm(p), fbm(p + vec2(5.2, 1.3))); vec2 r = vec2(fbm(p + 4.0*q + u_time*0.15), fbm(p + 4.0*q + u_mouse)); float f = fbm(p + 4.0 * r); // ← 你眼前的极光
第二章 · 滚动即时间线
这些动画,
一行 JavaScript 都没有。
2024 年落地、2026 年已可放心使用的 animation-timeline: scroll() 与 view(),
把"滚动位置"变成了 CSS 动画的时间轴。右上角的进度环、章节的浮现、
全页色相的旋转、下方的横向画廊——统统跑在浏览器合成线程上,与主线程无关,永不掉帧。
scroll(root)
以整页滚动为时间轴。本页用它驱动进度环的 conic-gradient 角度,以及 --hue 从 260° 环游到 330° 的全局色相之旅。
view()
以"元素在视口中的位置"为时间轴。你看到的每一段文字浮现、每一张卡片上升,都是 view() + animation-range 的声明式产物。
@property
把 CSS 变量注册为可插值类型。本页用它让渐变角度、色相数字、甚至整数计数器都能被动画驱动——请看下面的统计数字。
↑ 这些数字在滚入视口时从 0 计数到目标值——用的是 @property 注册的整数变量 +
counter(),同样零 JS。
OKLCH 色彩
本页所有颜色都写在 OKLCH 空间:感知均匀,色相旋转时明度不漂移。CSS 颜色终于有了物理直觉。
容器与视口单位
clamp() + 视口单位让每一号字体在手机与巨屏之间连续缩放,没有一个断点。
backdrop-filter
你透过这些玻璃卡片看到的极光,是实时模糊+饱和的着色器输出——两个渲染管线的合谋。
mix-blend-mode
移动鼠标看看光标:difference 混合模式让它在任何背景上都保持可见,并自动反色。
这条横向轨道
外层是一个 320vh 的高容器,内层 sticky 钉住;view() 时间线把纵向滚动映射为横向位移。依然,零 JS。
第三章 · 会呼吸的文字
聚拢又散开
上面这行字的 letter-spacing、模糊与透明度被绑定到它自己穿越视口的进度上:
滚入时从雾中聚拢,滚出时重新散去。排版不再是静态的版面,而是与阅读节奏同步的乐器。
text-wrap: balance 则在你没注意的地方,悄悄让每个标题的断行两侧均衡。
终章
网页的极限
不在引擎里,
在想象力里。
一个 HTML 文件。没有框架,没有构建,没有依赖。
一枚着色器、一组滚动时间线、一个色彩空间——以及把它们编成一次旅程的耐心。
按 Home 键回到开头,再走一遍:极光每一次都不一样。