如何在纯 javascript 中平滑滚动到元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/51689653/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to smoothly scroll to an element in pure javascript
提问by hev1
I want to smoothly scroll to an element without using jQuery – just pure javascript. I would like a generic function to be able to both scroll down and scroll up smoothly to a specific position in the document.
我想在不使用 jQuery 的情况下顺利滚动到一个元素——只是纯 javascript。我想要一个通用函数,既能够向下滚动,也能够平滑地向上滚动到文档中的特定位置。
I know I can use the following in jQuery:
我知道我可以在 jQuery 中使用以下内容:
$('html, body').animate({
scrollTop: $('#myelementid').offset().top
}, 500);
How would I do it with just javascript?
我将如何只用 javascript 做到这一点?
This is what I am trying to do:
这就是我想要做的:
function scrollToHalf(){
//what do I do?
}
function scrollToSection(){
//What should I do here?
}
<input type="button" onClick="scrollToHalf()" value="Scroll To 50% of Page">
<br>
<input type="button" onClick="scrollToSection()" value="Scroll To Section1">
<section style="margin-top: 1000px;" id="section1">
This is a section
</section>
In jquery I would do it like so:
在 jquery 中,我会这样做:
html, body{
height: 3000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="button" onClick="scrollToHalf()" value="Scroll To 50% of Page">
<br>
<input type="button" onClick="scrollToSection()" value="Scroll To Section1">
<section style="margin-top: 1000px;" id="section1">
This is a section
</section>
<script>
function scrollToHalf(){
var height = $('body').height();
$('html, body').animate({
scrollTop: height/2
}, 500);
}
function scrollToSection(){
$('html, body').animate({
scrollTop: $('#section1').offset().top
}, 500);
}
</script>
EDIT: I would also like to be able to smooth scroll to a certain position on the page
编辑:我还希望能够平滑滚动到页面上的某个位置
EDIT: CSS solutions are also welcome (although I would prefer javascript solutions)
编辑:也欢迎使用 CSS 解决方案(尽管我更喜欢 javascript 解决方案)
回答by hev1
You can use a forloop with window.scrollToand setTimeoutto scroll smoothly with plain Javascript. To scroll to a specific element, just call the scrollToSmoothlyfunction with the element's offsetTop as the first argument.
您可以使用for循环和window.scrollTo和setTimeout使用纯 Javascript 平滑滚动。要滚动到特定元素,只需scrollToSmoothly使用元素的 offsetTop 作为第一个参数调用该函数。
function scrollToSmoothly(pos, time) {
/*Time is only applicable for scrolling upwards*/
/*Code written by hev1*/
/*pos is the y-position to scroll to (in pixels)*/
if (isNaN(pos)) {
throw "Position must be a number";
}
if (pos < 0) {
throw "Position can not be negative";
}
var currentPos = window.scrollY || window.screenTop;
if (currentPos < pos) {
var t = 10;
for (let i = currentPos; i <= pos; i += 10) {
t += 10;
setTimeout(function() {
window.scrollTo(0, i);
}, t / 2);
}
} else {
time = time || 2;
var i = currentPos;
var x;
x = setInterval(function() {
window.scrollTo(0, i);
i -= 10;
if (i <= pos) {
clearInterval(x);
}
}, time);
}
}
Demo:
演示:
<button onClick="scrollToDiv()">Scroll To Element</button>
<div style="margin: 1000px 0px; text-align: center;">Div element<p/>
<button onClick="scrollToSmoothly(Number(0))">Scroll back to top</button>
<p/>
<button onClick="scrollToSmoothly(document.body.offsetHeight)">
Scroll To Bottom
</button>
</div>
<button onClick="scrollToSmoothly(Number(500))">
Scroll to y-position 500px
</button>
<script>
function scrollToSmoothly(pos, time){
/*Time is only applicable for scrolling upwards*/
/*Code written by hev1*/
/*pos is the y-position to scroll to (in pixels)*/
if(isNaN(pos)){
throw "Position must be a number";
}
if(pos<0){
throw "Position can not be negative";
}
var currentPos = window.scrollY||window.screenTop;
if(currentPos<pos){
if(time){
var x;
var i = currentPos;
x = setInterval(function(){
window.scrollTo(0, i);
i += 10;
if(i>=pos){
clearInterval(x);
}
}, time);
} else {
var t = 10;
for(let i = currentPos; i <= pos; i+=10){
t+=10;
setTimeout(function(){
window.scrollTo(0, i);
}, t/2);
}
}
} else {
time = time || 2;
var i = currentPos;
var x;
x = setInterval(function(){
window.scrollTo(0, i);
i -= 10;
if(i<=pos){
clearInterval(x);
}
}, time);
}
}
function scrollToDiv(){
var elem = document.querySelector("div");
scrollToSmoothly(elem.offsetTop);
}
</script>
To scroll to a certain position in an exact amount of time, window.requestAnimationFramecan be put to use. JSFiddle WebPage Demo: http://jsfiddle.net/4xwnzgj5/embedded/result
要在精确的时间内滚动到某个位置,window.requestAnimationFrame就可以使用了。JSFiddle网页演示:http: //jsfiddle.net/4xwnzgj5/embedded/result
function scrollToSmoothly(pos, time){
/*Time is exact amount of time the scrolling will take (in milliseconds)*/
/*Pos is the y-position to scroll to (in pixels)*/
/*Code written by hev1*/
if(typeof pos!== "number"){
pos = parseFloat(pos);
}
if(isNaN(pos)){
console.warn("Position must be a number or a numeric String.");
throw "Position must be a number";
}
if(pos<0||time<0){
return;
}
var currentPos = window.scrollY || window.screenTop;
var start = null;
time = time || 500;
window.requestAnimationFrame(function step(currentTime){
start = !start? currentTime: start;
if(currentPos<pos){
var progress = currentTime - start;
window.scrollTo(0, ((pos-currentPos)*progress/time)+currentPos);
if(progress < time){
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
} else {
var progress = currentTime - start;
window.scrollTo(0, currentPos-((currentPos-pos)*progress/time));
if(progress < time){
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
}
});
}
Demo:
演示:
<button onClick="scrollToSmoothly(Number(document.querySelector('div').offsetTop), Number(300))">
Scroll To Div (300ms)
</button>
<button onClick="scrollToSmoothly(Number(document.querySelector('div').offsetTop), Number(200))">
Scroll To Div (200ms)
</button>
<button onClick="scrollToSmoothly(Number(document.querySelector('div').offsetTop), Number(100))">
Scroll To Div (100ms)
</button>
<button onClick="scrollToSmoothly(Number(document.querySelector('div').offsetTop), 50)">
Scroll To Div (50ms)
</button>
<button onClick="scrollToSmoothly(Number(document.querySelector('div').offsetTop), Number(1000))">
Scroll To Div (1000ms)
</button>
<div style="margin: 500px 0px;">
DIV<p/>
<button onClick="scrollToSmoothly(0, 500)">
Back To Top
</button>
<button onClick="scrollToSmoothly(document.body.scrollHeight)">
Scroll To Bottom
</button>
</div>
<div style="margin: 500px 0px;">
</div>
<button style="margin-top: 100px;" onClick="scrollToSmoothly(500, 3000)">
Scroll To y-position 500px (3000ms)
</button>
<script>
function scrollToSmoothly(pos, time){
/*Time is exact amount of time the scrolling will take (in milliseconds)*/
/*Pos is the y-position to scroll to (in pixels)*/
/*Code written by hev1*/
if(typeof pos!== "number"){
pos = parseFloat(pos);
}
if(isNaN(pos)){
console.warn("Position must be a number or a numeric String.");
throw "Position must be a number";
}
if(pos<0||time<0){
return;
}
var currentPos = window.scrollY || window.screenTop;
var start = null;
time = time || 500;
window.requestAnimationFrame(function step(currentTime){
start = !start? currentTime: start;
if(currentPos<pos){
var progress = currentTime - start;
window.scrollTo(0, ((pos-currentPos)*progress/time)+currentPos);
if(progress < time){
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
} else {
var progress = currentTime - start;
window.scrollTo(0, currentPos-((currentPos-pos)*progress/time));
if(progress < time){
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
}
});
}
</script>
Alternatively, you can use window.scrollwhich scrolls to a specific x and y position and window.scrollBywhich scrolls from the current position:
或者,您可以使用window.scroll哪个滚动到特定的 x 和 y 位置,window.scrollBy哪个从当前位置滚动:
// Scroll to specific values
// scrollTo is the same
window.scroll({
top: 2500,
left: 0,
behavior: 'smooth'
});
// Scroll certain amounts from current position
window.scrollBy({
top: 100, // could be negative value
left: 0,
behavior: 'smooth'
});
Demo:
演示:
<button onClick="scrollToDiv()">Scroll To Element</button>
<div style="margin: 500px 0px;">Div</div>
<script>
function scrollToDiv(){
var elem = document.querySelector("div");
window.scroll({
top: elem.offsetTop,
left: 0,
behavior: 'smooth'
});
}
</script>
If you only need to scroll to an element, not a specific position in the document, you can use Element.scrollIntoViewwith behaviorset to smooth.
如果您只需要滚动到一个元素,而不是文档中的特定位置,则可以使用Element.scrollIntoViewwith behaviorset to smooth。
document.getElementById("elemID").scrollIntoView({
behavior: 'smooth'
});
Demo:
演示:
<button onClick="scrollToDiv()">Scroll To Element</button>
<div id="myDiv" style="margin: 500px 0px;">Div</div>
<script>
function scrollToDiv(){
document.getElementById("myDiv").scrollIntoView({
behavior: 'smooth'
});
}
</script>
Modern browsers support the scroll-behaviorCSS property, which can be used to make scrolling in the document smooth (without the need for Javascript; anchor tags can be used for this by giving the anchor tag a hrefof #plus the idof the Element to scroll to). You can also set the scroll-behaviorproperty for a specific element like a divto make its contents scroll smoothly.
现代浏览器支持scroll-behaviorCSS 属性,该属性可用于使文档中的滚动平滑(无需 Javascript;可以通过给锚标记 a hrefof#加上id要滚动到的元素来使用锚标记)。您还可以为scroll-behavior特定元素设置属性,例如 adiv以使其内容平滑滚动。
Demo:
演示:
html, body{
scroll-behavior: smooth;
}
a, a:visited{
color: initial;
}
<a href="#elem">Scroll To Element</a>
<div id="elem" style="margin: 500px 0px;">Div</div>
The CSS scroll-behaviorproperty works with Javascript as well when using window.scrollTo.
scroll-behavior使用 .css 时,CSS属性也适用于 Javascript window.scrollTo。
Demo:
演示:
html, body{
scroll-behavior: smooth;
}
<button onClick="scrollToDiv()">Scroll To Element</button>
<div style="margin: 500px 0px;">Div</div>
<script>
function scrollToDiv(){
var elem = document.querySelector("div");
window.scrollTo(0, elem.offsetTop);
}
</script>
To check if the scroll-behaviorproperty is supported, you can check if it exists as a key in the style of the HTML element.
要检查该scroll-behavior属性是否受支持,您可以检查它是否作为 HTML 元素样式中的键存在。
var scrollBehaviorSupported = 'scroll-behavior' in document.documentElement.style;
console.log('scroll-behavior supported:',scrollBehaviorSupported);
回答by Kosh
Consider using Element.scrollIntoView().
回答by Angel Politis
As I mentioned in my comment, scrollIntoViewis a good option to consider – that gets greater and greater browser support – when you try to scroll to a specified element such as what you are apparently trying to do with your scrollToSectionfunction.
正如我在我的评论中提到的,scrollIntoView当您尝试滚动到指定元素(例如您显然试图用您的scrollToSection函数执行的操作)时,这是一个值得考虑的不错选择——它获得越来越多的浏览器支持。
To scroll to the middle of the page you can set the scrollTopproperty of the bodyand/or the htmlelement to half the difference of the scrollHeightof the body and the innerHeightof the window. Couple the above calculation with requestAnimationFrameand you are set.
要滚动到页面中间,您可以将和/或元素的scrollTop属性设置为主体和窗口的差异的一半。结合上面的计算,你就设置好了。bodyhtmlscrollHeightinnerHeightrequestAnimationFrame
Here's how you can incorporate the above suggestions in your code:
以下是将上述建议合并到代码中的方法:
function scrollToHalf(duration) {
var
heightDiff = document.body.scrollHeight - window.innerHeight,
endValue = heightDiff / 2,
start = null;
/* Set a default for the duration, in case it's not given. */
duration = duration || 300;
/* Start the animation. */
window.requestAnimationFrame(function step (now) {
/* Normalise the start date and calculate the current progress. */
start = !start ? now : start;
var progress = now - start;
/* Increment by a calculate step the value of the scroll top. */
document.documentElement.scrollTop = endValue * progress / duration;
document.body.scrollTop = endValue * progress / duration;
/* Check whether the current progress is less than the given duration. */
if (progress < duration) {
/* Execute the function recursively. */
window.requestAnimationFrame(step);
}
else {
/* Set the scroll top to the end value. */
document.documentElement.scrollTop = endValue;
document.body.scrollTop = endValue;
}
});
}
function scrollToSection(element) {
/* Scroll until the button's next sibling comes into view. */
element.nextElementSibling.scrollIntoView({block: "start", behavior: "smooth"});
}
#section1 {
margin: 1000px 0;
border: 1px solid red
}
<input type="button" onClick="scrollToHalf()" value="Scroll To 50% of Page">
<br>
<input type="button" onClick="scrollToSection(this)" value="Scroll To Section1">
<section id="section1">
This is a section
</section>

