JS14 平滑滚动

实现页面平滑滚动的几种方法。

scroll-behavior

使用CSS3的scroll-behavior: smooth属性可以轻松的实现平滑滚动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<head>
<style>
html, body {
scroll-behavior: smooth;
}
</style>
</head>
<body>
<div id="head">Head</div>
<div class="scroll-x"><img src="./default.png"></div>
<div class="scroll-x"><img src="./default.png"></div>
<div class="scroll-x"><img src="./default.png"></div>
<div class="scroll-x"><img src="./default.png"></div>
<div class="scroll-x"><img src="./default.png"></div>
<div class="scroll-x"><img src="./default.png"></div>
<a href="#head">Back to Top</a>
</body>

兼容性:

scroll-nap-type

scroll-nap-type属性可以在移动端实现平滑定位滚动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<head>
<style>
.scroll-x {
width: 300px;
scroll-snap-type: x mandatory;
white-space: nowrap;
overflow: auto;
}

.scroll-x img {
scroll-snap-align: start;
}
</style>
</head>

<body>
<div class="scroll-x">
<img src="./mm.jpg">
<img src="./mm2.jpg">
<img src="./mm3.jpg">
<img src="./mm4.jpg">
<img src="./mm5.jpg">
</div>
</body>

图片左边缘会和滚动容器的左边缘进行吸附,它的作用是让页面滚动停留在你希望用户关注的重点区域(要注意,在IOS浏览器下需要同时设置滚动容器-webkit-overflow-scrolling:touch

详细的属性介绍可以参考张鑫旭的文章

要注意的是,虽然Scroll Snap可以让网页容器滚动停止的时候,自动平滑定位到指定元素,但是它的真正的作用是元素定位增强,想要使用平滑滚动,还是应该使用上一个属性scroll-behavior

scrollIntoView

除了CSS属性,也可以使用JavaScript来实现平滑滚动。DOM元素的scrollIntoView()方法是一个支持IE6的原生API,它可以让当前的元素滚动到浏览器窗口的可视区域内。

1
2
3
element.scrollIntoView(); // 等同于element.scrollIntoView(true)
element.scrollIntoView(alignToTop); // Boolean型参数
element.scrollIntoView(scrollIntoViewOptions); // Object型参数

它可以接受一个布尔值alignToTop作为参数,如果为true(默认值),元素的顶端将和其所在的可视区域的顶端对齐,对应的scrollIntoViewOptions属性是{block: "start", inline: "nearest"};如果是false,元素的底端将和其所在滚动区的可视区域底端平齐,对应的scrollIntoViewOptions属性是{block: "end", inline: "nearest"}

如果参数是一个对象(有可能不被浏览器支持),那么可以取三个属性:

  • behavior,定义滚动效果
  • bloack,定义垂直对齐方向
  • inline,定义水平对齐方向
1
2
3
if (choice === 'exit') {
document.getElementById(`question${unmarkedIndex}`).scrollIntoView(true)
}

各个浏览器均支持scrollIntoView,而且兼容性也不错:

除此之外还有几个属性不是所有浏览器都实现的方法:

(1)scrollIntoViewIfNeeded(alignCenter)

只在当前元素在视窗的可见范围内不可见的情况下,才滚动浏览器窗口或容器元素,最终让当前元素可见。

如果当前元素在视窗中可见,这个方法不做任何处理。如果将可选参数alignCenter设置为true,则表示尽量将元素显示在视窗中部(垂直方向)

(2)scrollByLines(lineCount)

将元素的内容滚动指定的行数的高度,lineCount的值可以为正值或是负值。

(3)scrollByPages(pageCount)

将元素的内容滚动指定的页面的高度,具体高度由元素的高度决定。

scrollIntoView()scrollIntoVIewIfNeeded()作用的是元素的窗口,而scrollByLines()scrollByPages()影响元素自身。

可以看出来,只有scrollIntoView的兼容性比较广泛,其他几种方法都只有某几个浏览器实现了,所以不推荐使用。

向下兼容

如果不使用上述方法,也可以在requestAnimationFrame中手动修改scrollTop的值来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* @description 页面垂直平滑滚动到指定滚动高度
* @author 张鑫旭
*/
const scrollSmoothTo = function(position) {
// 当前滚动高度
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
// 滚动step方法
const step = function() {
// 距离目标滚动距离
const 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); // 网页平滑滚动到顶部

可以根据下面的代码对浏览器是否支持scrollBehavior

1
2
3
if (typeof window.getComputedStyle(document.body).scrollBehavior === 'undefined') {
// 传统的JS平滑滚动处理代码...
}

参考