利用CSS的scroll-behavior和JS的scrollIntoView使页面滚动更加平滑
相信大家在浏览网页的时候都见过这样的例子,当我们将页面滚动到最底部时,会出现“返回顶部”这个文字链接的时候,点击一下页面就会“唰”地一声瞬间定位到浏览器顶部,速度之快,升势之猛,以至于你没有任何反应,就像暴风雨般的爱情,让你猝不及防,脑中不断回想:“我在哪里?我是谁?我刚刚做了什么?
所有这些反应的产生,归根结底在于我们这个滚动效果实在是太干巴巴了,机械生硬没有灵性不解风情。
人是有情感的动物,既然我们做的网页是给人用的,那自然充满情感,不要那么干巴巴,让滚动效果又湿又滑,用户体验就会好。
浏览器似乎也意识到这一点,从去年年底开始,已经开始支持浏览器的原生平滑滚动定位,CSS scroll-behavior 属性和 JS scrollIntoView()方法都可以。
CSS scroll-behavior 与平滑滚动
scroll-behavior:smooth 写在滚动容器元素上,可以让容器(非鼠标手势触发)的滚动变得平滑。
初始值是’auto’。
我们先看一个实际的案例。
利用锚点定位纯 CSS 实现选项卡切换的技术(本质上是触发滚动条滚动)。
实现后的效果参见下 GIF 截屏:
基本功能可以满足,但有两个问题,一是由于改变 location 的 hash 实现的定位,会触发浏览器原生滚动行为,体验不好;二是选项卡内容的切换“邦邦邦”过于生硬。
于是,后来,我发明了一种基于控件元素 focus 触发滚动重定位的特性实现的纯 CSS 选项卡切换效果。
也是纯 CSS 实现,没有任何 JavaScript 代码,相比直接利用<a>元素的 href 锚点跳转方法,此方法不会触发浏览器外部窗体的滚动,体验更上一层楼,但是还有一个问题,那就是选项卡内容切换的时候,还是“邦邦邦”这种干巴巴的效果,并没有滑来滑去那种湿湿的效果。
不要担心,现在有了 CSS scroll-behavior,则平滑滚动的问题也可以解决了。
具体实现代码如下,
HTML 代码:
<html> <head></head> <body> <div class="tab"> <label class="label" for="tab1">选项卡 1</label> <label class="label" for="tab2">选项卡 2</label> <label class="label" for="tab3">选项卡 3</label> </div> <div class="box"> <div class="content"> <input id="tab1" type="text" /> 我是选项卡 1 对应的美女 <img src="./mm1.jpg" /> </div> <div class="content"> <input id="tab2" type="text" /> 我是选项卡 2 对应的美女 <img src="./mm2.jpg" /> </div> <div class="content"> <input id="tab3" type="text" /> 我是选项卡 3 对应的美女 <img src="./mm3.jpg" /> </div> </div> </body> </html>
CSS 代码:
.label { width: 100px; margin-right: -1px; border: 1px solid #ccc; border-bottom: 0; padding-top: 5px; padding-bottom: 5px; background-color: #eee; text-align: center; float: left; } .box { height: 200px; border: 1px solid #ccc; scroll-behavior: smooth; overflow: hidden; } .content { height: 100%; padding: 0 20px; position: relative; overflow: hidden; } .box input { position: absolute; top: 0; height: 100%; width: 1px; border: 0; padding: 0; margin: 0; clip: rect(0 0 0 0); }
相比之前干巴巴的实现,就多了这么一句 CSS——scroll-behavior:smooth:
.box { scroll-behavior: smooth; overflow: hidden; }
结果一股如沐春风的交互效果扑面而来,参见下面视频截屏效果:
一行 CSS 就可以锦上添花。
更简单更实际的用途
其实 scroll-behavior 的使用没有那么多花头,你就记住这么一句话——
凡是需要滚动的地方都加一句 scroll-behavior:smooth 就好了!
你别管他用不用得到,也不用管浏览器兼容性如何,你都加上。这就像一个不要钱的免费抽奖,没有中奖,没关系,又没什么损失,中奖了自然好,锦上添花!scroll-behavior:smooth 就是这种尿性。
举个例子,在 PC 浏览器中,网页默认滚动是在<html>标签上的,移动端大多数在<body>标签上,于是,我加上这么一句:
html, body { scroll-behavior:smooth; }
此时,点击下面这个“返回顶部”链接,就会平滑滚动到顶部。
HTML 代码如下:
<a href="#">返回顶部</a>
从这一点来看,业界浏览器的 CSS reset 都可以加上这么一条规则:
html, body { scroll-behavior:smooth; }
JS scrollIntoView 与平滑滚动
DOM 元素的 scrollIntoView()方法是一个 IE6 浏览器也支持的原生 JS API,可以让元素进入视区,通过触发滚动容器的定位实现。
随着 Chrome 和 Firefox 浏览器开始支持 CSS scroll-behavior 属性,顺便对,scrollIntoView()方法进行了升级,使支持更多参数,其中一个参数就是可以使滚动平滑。
语法如下:
target.scrollIntoView({ behavior: "smooth" });
我们随便打开一个有链接的页面,把首个链接滚动到屏幕外,然后控制台输入类似下面代码,我们就可以看到页面平滑滚动定位了:
document.links[0].scrollIntoView({ behavior: "smooth" });
其它:
- scrollIntoView()升级后的方法,除了支持’behavior’,还有’block’和’inline’等参数,有兴趣可以参阅MDN 相关文档。
- 如果我们的网页已经通过 CSS 设置了 scroll-behavior:smooth 声明,则我们直接执行 target.scrollIntoView()方法就会有平滑滚动,无需再额外设置 behavior 参数。例如,如果你是在鑫空间原站浏览的此文章,打开控制台,执行下面代码,就可以看到平滑滚动效果了:
document.forms[0].scrollIntoView();
JS 平滑滚动向下兼容处理
JS 实现平滑滚动并不难,jQuery 中 animate()方法:
scrollContainer.animate({ scrollTop: 0 });
或者使用 requestAnimationFrame API 这类原生 JS 也能实现。例如下面这个我速写的个方法:
/** @description 页面垂直平滑滚动到指定滚动高度 @author gwei(mybj123.com) */ var scrollSmoothTo = function(position) { if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(callback, element) { return setTimeout(callback, 17); }; } // 当前滚动高度 var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; // 滚动 step 方法 var step = function() { // 距离目标滚动距离 var distance = position - scrollTop; // 目标滚动位置 scrollTop = scrollTop + distance / 5; if (Math.abs(distance) < 1) { window.scrollTo(0, position); } else { window.scrollTo(0, scrollTop); requestAnimationFrame(step); } }; step(); };
使用如下,例如,我们希望网页平滑滚动到顶部,直接:
scrollSmoothTo(0);
就可以了。
难的是如何支持平滑滚动的浏览器原生处理,不支持的浏览器还是使用老的 JS 方法处理。
我是这么处理的 JS 如下判断:
if (typeof window.getComputedStyle(document.body).scrollBehavior == 'undefined') { // 传统的 JS 平滑滚动处理代码... }
这样就可以无缝对接了。
码云笔记 » 利用CSS的scroll-behavior和JS的scrollIntoView使页面滚动更加平滑