Scroll Indicator称之为滚动指示器,是Web中常见的一种效果。用户滚动垂直滚动内容时,页面顶部有一个类似进度条的效果,当内容滚动到页面最低端,进度条效果填满整个进度条。感觉描述得有点绕,还是录制一个动效图,用图来说明这种效果,毕竟一图胜过千言万语:
以前实现这种效果都需要借助于JavaScript,或者说是采用jQuery的插件。网上有关于这方面的介绍的文章也很多,比如:
- @PANKAJ PARASHAR的《Reading Position Indicator》
- @Jonathan Cutrell的《How to Build a Page Scroll Progress Indicator With jQuery and SVG》
但今天咱们要说的是使用纯CSS制作Scroll Indicator效果。说到这里,大家或许会问,这样的效果用CSS实现,吹了吧。其实使用纯CSS实现一点也没有问题。如果你感兴趣,欢迎接着往下阅读。
Scroll Indicator几个关键点
先来看JavaScript的做法:
看代码变化就清楚,通过JavaScript改变容器scroll-line
的width
值。也就是在滚动内容的时候,width
值从0%
变化到100%
。其中最重要的是要知道滚动条位置的计算。在整个计算中,要知道两个重要的参数:
document height
:文档的高度$(document).height()
window height
: 视窗高度$(window).height()
如下图所示:
文档高度和视窗高度有一个差值max
,其实这个差值就是需要滚动的值,简单的理解就是scroll-line
宽度为100%
时候的宽度值。这样一来,咱们就知道了全宽的width
值,另外还需要知道的另一个关键值是滚动条的位置的值$(window).scrollTop()
。有了这两个值,通过($(window).scrollTop() / ($(document).height() - $(window).height())) * 100%
就知道进度条的当前值。
最终效果可以看看@Derek Palladino在CodePen写的一个示例:
另外再看一个@Dan Eden写的一个示例:
有关于JavaScript实现方案相关介绍,可以仔细阅读上面的两篇文章。
CSS实现方案
纯CSS实现Scroll Indicator效果最难的是不知道滚动条距顶部的距离,而且也不知道文档高度和视窗高度的差值。要按前面的方案实现,是不太可能。不过我们可以通过别的方案来模拟。
同样的需要两个容器:
<div class="scroll-process">
<div class="scroll-line"></div>
</div>
其中scroll-process
是全屏宽,也就是相当于($(document).height() - $(window).height())
,里面scroll-line
的宽度就是($(window).scrollTop() / ($(document).height() - $(window).height())) * 100%
。如下图所示:
上图蓝色区域是scroll-line
,灰色区域是scroll-process
。
原理是一样,只是实现我们不能借助JavaScript实现,而是需要使用CSS来模拟JavaScript效果。
仔细思考一下,在Web中,自带滚动功能的是body
元素,或者说某个限制大小尺寸,设置了overflow
属性为scroll
值也会出现滚动条效果。另外,要随着滚动条滚动,scroll-line
要出现类似进度条的效果。
上图简单的模拟出来进度条的效果了,而实现上现的效果,在CSS中是很容易的,我们只需要在容器中使用CSS的line-gradient
属性。比如说在body
中使用:
background: linear-gradient(to right top, #0089f2 50%, #DDD 50%);
这样的效果还不能满足我们的需求:
上面示例演示的是100vh
的高度,也就是视窗高度,按上面的方式,先看下面的动图:
这个效果才是我们想要的。当然并不是完美。不过先忽略这一点。如果要实现上图的效果,还要做一下处理。在CSS中有一个background-size
属性,这个属性可以帮助我们控制背景图大小,也就是渐变图的大小。而对于background-size
需要的是其y
轴的值。那问题又来了,y
轴的值怎么确定。
在CSS中要得到视窗高度,也就是前面所说的$(window).height()
。它就是100vh
。而我们进度的值是($(window).scrollTop() / ($(document).height() - $(window).height())) * 100%
。要对于background-size
的y
与其一样,那么可以通过100%-100vh
。要得到100% - 100vh
的值还需要使用CSS中的calc()
:
body{
background: linear-gradient(to right top, #0089f2 50%, #DDD 50%);
background-size: 100% calc(100% - 100vh);
}
离需要的效果越来越近了:
最近需要一个蒙层,让进度条看上去更美一些。
body:before {
content: '';
position: fixed;
top: 5px;
bottom: 0;
width: 100%;
z-index: -1;
background: white;
}