前言
滚动驱动的动画效果是提升用户交互体验的方法。本文将详细介绍如何使用纯CSS实现一个页面滚动的导航进度条效果,仅依靠CSS实现功能。
1. 效果演示

需要实现的效果是:顶部的导航栏进度条会随着页面滚动加载,并适应不同背景颜色
2. 代码实现
2.1 HTML结构
结构如下:
xml
<body>
<header>
<nav>
<a href="#html">html</a>
<a href="#css">css</a>
<a href="#js">js</a>
<a href="#vue">vue</a>
<a href="#react">react</a>
</nav>
</header>
<section id="html">...</section>
<section id="css">...</section>
<section id="js">...</section>
<section id="vue">...</section>
<section id="react">...</section>
</body>
<header>
和<nav>
的作用是创建固定在顶部的导航栏,使用a
标签的5个锚点链接下方5个区块。<section>
作用是定义全屏滚动的内容区块,id
属性与导航链接的href
值匹配(如#html
)。
结构非常简单:一个固定导航栏和五个全屏区块。每个区块都有对应的ID,与导航链接的锚点匹配。
2.2 CSS实现细节
2.2.1 颜色变量定义
css
:root {
--black: #373737;
--sect-1: #ff9900; /* HTML - 橙色 */
--sect-2: #2196f3; /* CSS - 蓝色 */
--sect-3: #e63232; /* JS - 红色 */
--sect-4: #4caf50; /* VUE - 绿色 */
--sect-5: #8946ff; /* REACT - 紫色 */
}
使用CSS变量定义颜色,给每个区块定义独特的颜色标识。
2.2.2 导航栏样式
css
nav {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 65px;
background: linear-gradient(0deg, #fff0 0px, var(--black) 1px 100%);
display: flex;
text-align: center;
transition: all 0.5s ease 0s;
}
导航栏使用position: fixed
固定在顶部,display: flex
让链接水平排列。背景使用渐变效果,从透明到黑色,只显示底部1px的线条。
2.2.3 进度条实现
css
nav::after {
content: "";
position: absolute;
width: calc(20vw - 5px);
height: 100%;
background: linear-gradient(90deg,
var(--sect-1) 0px calc(20vw - 5px),
var(--sect-2) 0px calc(40vw - 6px),
var(--sect-3) 0px calc(60vw - 7px),
var(--sect-4) 0px calc(80vw - 8px),
var(--sect-5) 0px calc(100vw));
bottom: 0;
left: 0;
animation: progress linear;
animation-timeline: scroll(root);
z-index: -1;
}
这是整个效果的核心部分:
- 使用
::after
伪元素创建进度条 - 初始宽度为
calc(20vw - 5px)
,即每个颜色区块占20%视口宽度减去调整值 - 背景使用线性渐变,五种颜色按比例分布
animation-timeline: scroll(root)
将动画与根元素的滚动位置绑定
2.2.4 滚动驱动动画
css
@keyframes progress {
100% {
width: 100%;
}
}
动画非常简单,只是将宽度从初始值变为100%。关键点在于animation-timeline: scroll(root)
,它使动画进度与页面滚动位置同步。
2.2.5 区块样式
css
section {
--bg: var(--sect-1);
height: 100vh;
background: var(--bg);
color: #ffffff;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
font-size: 4rem;
padding-top: 30px;
align-content: center;
}
每个区块都是100vh高度,使用flex布局使内容居中。背景色通过CSS变量设置,每个区块有特定的颜色:
css
#html { --bg: var(--sect-1); }
#css { --bg: var(--sect-2); }
#js { --bg: var(--sect-3); }
#vue { --bg: var(--sect-4); }
#react { --bg: var(--sect-5); }
3. 完整代码
xml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
:root {
--black: #373737;
--sect-1: #ff9900;
--sect-2: #2196f3;
--sect-3: #e63232;
--sect-4: #4caf50;
--sect-5: #8946ff;
}
body {
margin: 0;
padding: 0;
transition: all 0.5s ease 0s;
}
header {
width: 100%;
}
a {
width: 100%;
z-index: 1;
color: #ffffff;
text-decoration: none;
padding: 16px 10px;
position: relative;
font-size: 1.6rem;
border: 2px solid #000;
border-top-width: 0;
border-bottom-width: 4px;
}
a:first-child {
border-left-width: 0;
}
a:last-child {
border-right-width: 0;
}
h2,
p {
margin: 0;
width: 100%;
text-align: center;
}
nav {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 65px;
background: linear-gradient(0deg, #fff0 0px, var(--black) 1px 100%);
display: flex;
text-align: center;
transition: all 0.5s ease 0s;
}
nav::after {
content: "";
position: absolute;
width: calc(20vw - 5px);
height: 100%;
background: linear-gradient(90deg,
var(--sect-1) 0px calc(20vw - 5px),
var(--sect-2) 0px calc(40vw - 6px),
var(--sect-3) 0px calc(60vw - 7px),
var(--sect-4) 0px calc(80vw - 8px),
var(--sect-5) 0px calc(100vw));
bottom: 0;
left: 0;
animation: progress linear;
animation-timeline: scroll(root);
z-index: -1;
}
@keyframes progress {
100% {
width: 100%;
}
}
section {
--bg: var(--sect-1);
height: 100vh;
background: var(--bg);
color: #ffffff;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
font-size: 4rem;
padding-top: 30px;
align-content: center;
}
#html {
--bg: var(--sect-1);
}
#css {
--bg: var(--sect-2);
}
#js {
--bg: var(--sect-3);
}
#vue {
--bg: var(--sect-4);
}
#react {
--bg: var(--sect-5);
}
</style>
</head>
<body>
<header>
<nav>
<a href="#html">html</a>
<a href="#css">css</a>
<a href="#js">js</a>
<a href="#vue">vue</a>
<a href="#react">react</a>
</nav>
</header>
<section id="html">
<h2>HTML</h2>
<p>超文本标记语言</p>
</section>
<section id="css">
<h2>CSS</h2>
<p>层叠样式表</p>
</section>
<section id="js">
<h2>JS</h2>
<p>客户端脚本语言</p>
</section>
<section id="vue">
<h2>VUE</h2>
<p>渐进式JavaScript框架</p>
</section>
<section id="react">
<h2>REACT</h2>
<p>用于构建web和原生交互界面的库</p>
</section>
</body>
</html>
4. 总结
最后总结一下,实现的关键在于通过animation-timeline: scroll(root)
将动画与页面滚动位置绑定,无需JavaScript监听滚动事件。
如有错误,请指正O^O!