纯CSS技术实现Scroll Indicator滚动指示器效果
最近在读阮一峰老师的的《ECMAScript 6 入门》,发现每个章节的页面顶部都有一个类似进度条的东西,这是个什么东东,好奇心强的我上网查了一下,这个东西叫 Scroll Indicator。
Scroll Indicator:滚动指示器。是 Web 中常见的一种效果。用户滚动垂直滚动内容时,页面顶部有一个类似进度条的效果,当内容滚动到页面最低端,进度条效果填满整个进度条。通俗来说,就是当前可视区域距离页面顶部的占比,感觉描述得有点绕,还是录制一个动效图,用图来说明这种效果,毕竟一图胜过千言万语:

JavaScript 实现
在还没有捞源码之前,自己先大致想了一下实现思路:
- 页面加载完成之后,获取到页面文档高度(DH)、当前可视区域高度(VH)、可视区域距离页面顶部的高度 scrollTop(TH);
- (DH-VH)就是需要滚动的值;
- 监听页面 scroll 事件,(TH/(DH-VH))*100%,便是当前的占比;
- 当然,需要考虑节流、防抖。推荐阅读《第 6 题:什么是防抖和节流 有什么区别 如何实现》
HTML 代码:
<body> <div class="scroll-indicator j-scroll-indicator"></div> </body>
css 代码:
body {
margin: 0;
paddingL 0;
height: 5000px;
}
.scroll-indicator {
position: fixed;
height: 8px;
top: 0;
left: 0;
background: #369;
}
核心代码:
(function() {
var dh = $(document).height();
var vh = $(window).height();
var sHeight = dh - vh;
$(window).scroll(function () {
var perc = $(window).scrollTop() / (dh - vh);
$('.j-scroll-indicator').css({width: perc * 100 + '%'});
});
}());
效果如下:

然后去捞了一下阮老师 es6 官网的源码:
(function() {
var $w = $(window);
var $prog2 = $('.progress-indicator-2');
var wh = $w.height();
var h = $('body').height();
var sHeight = h - wh;
$w.on('scroll', function() {
window.requestAnimationFrame(function(){
var perc = Math.max(0, Math.min(1, $w.scrollTop() / sHeight));
updateProgress(perc);
});
});
function updateProgress(perc) {
$prog2.css({width: perc * 100 + '%'});
ditto.save_progress && store.set('page-progress', perc);
}
}());
不出所料,做法是一样的。
然后,就开始瞎琢磨,之前用 css 搞过瀑布流,那可以用 css 搞滚动指示器吗?
答案当然是可以的。

我想到的更好的实现
我想到的这个技术实现区别就在于对角线性渐变不是写在 body 标签上的,而是一个普通的 div 元素上。
具体操作如下:
1、在
标签内插入指示器元素:<div class="indicator"></div>
2、粘贴如下所示的 CSS 代码:
body {
position: relative;
}
.indicator {
position: absolute;
top: 0; right: 0; left: 0; bottom: 0;
background: linear-gradient(to right top, teal 50%, transparent 50%) no-repeat;
background-size: 100% calc(100% - 100vh);
z-index: 1;
pointer-events: none;
mix-blend-mode: darken;
}
.indicator::after {
content: '';
position: fixed;
top: 5px; bottom: 0; right: 0; left: 0;
background: #fff;
z-index: 1;
}
一个更好的 CSS 滚动指示器效果就实现了
原理说明
传统 CSS 滚动指示器为了防止对角渐变(也就是滚动进度条)的覆盖页面上的元素内容,因此写在了最底层的 body 元素上,这就导致如果 body 元素内的普通元素内容有背景色,或者背景图之类的,就会覆盖进度条,产生致命缺陷。
我的优化方法是把对角渐变(也就是滚动进度条)连同里面的白色覆盖层写在了普通元素的上面,这样避开被覆盖的致命缺陷。但是这样实现带来另外一个问题,页面的内容都被白色图层覆盖了,那页面内容岂不是都看不见了?不要担心,有 CSS 声明可以让白色的图层变成透明,那就是 mix-blend-mode:darken,也就是 darken 混合模式。darken 混合模式的混合方式很好理解,两个颜色进行混合,哪个颜色深就使用哪个颜色?
要知道所有的颜色里面最浅的就是白色,于是我们只要把我们的白色覆盖层的混合模式设置为 darken,那必然最终呈现出来的颜色一定是覆盖层下面元素内容的颜色,换句话说我们的白色透明覆盖层变透明了。

CSS 滚动指示器要想效果良好,需要注意两点:
- 进度条的颜色尽量取深色,因为本身包含 darken 混合模式,如果颜色过浅,很容易被底部的内容颜色给混合。
- CSS 滚动指示器需要在页面滚动高度超过一屏的时候才出现。原因有两方面:一是如果滚动高度过小,没有必要使用滚动指示器;二是滚动指示器本质上是一个渐变,如果滚动高度不足,则进度条的边缘会过于倾斜而导致显示效果不完美。

网友的方法也不错
使用 CSS 来实现滚动指示器,难点在于:如何实时去获取当前可视区域在文档流中的位置。
上述问题,如何去考虑呢?我们从分解滚动指示器的动作中来找答案:
- 黑色表色进度条
- 红色表示文档高度
- 绿、蓝、橙表示视窗滚动

也就是说:(TH/(DH-VH))公式中的 TH 可以不用知道,只需要 DH-VH 的高度,即直角三角形的高度便 OK。
现在问题转化为:如何求出 VH,这时候该 vh 这个长度单位登场了,vh 是基于视窗单位的排版计量。vh 可以获取当前视窗的高度。嗯,现在看来,应该是可以一写了。
HTML 代码:
<body>
<div class="main">
<h1>滚动鼠标</h1>
</div>
</body>
CSS 代码:
.main {
margin: 0;
padding: 0;
display: block;
height: 30000px;
text-align: center;
line-height: 100px;
}
body {
margin: 0;
padding: 0;
background: linear-gradient(to right top, #369 50%, #fff 50%);
background-size: 100% calc(100% - 99vh);
}
body:before {
content: '';
position: fixed;
top: 4px;
bottom: 0;
width: 100%;
z-index: -1;
background: #fff;
}
大致实现是没有问题的,但是有下面几个缺点:
- 文档内容太少(高度太小)的话,进度条呈箭头形,不美观(可考虑加毛玻璃效果来弱化)
- background-size:100%calc(100%-99vh);中的 99vh 是相对值,若是视窗高度比较小,进度条会填不满进度条槽(可考虑加 min-height 来弱化)

结束语
其实这只是非常牛逼的渐变非常小的一个技巧,更多精彩 CSS 技术文章敬请关注码云笔记,持续更细。
好了,本文到此结束,希望对你有帮助,如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
以上关于纯CSS技术实现Scroll Indicator滚动指示器效果的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » 纯CSS技术实现Scroll Indicator滚动指示器效果
微信
支付宝