Je veux faire défiler en douceur un élément sans utiliser jQuery - juste du javascript pur. Je voudrais qu'une fonction générique puisse faire défiler vers le bas et vers le haut en douceur jusqu'à une position spécifique dans le document.
Je sais que je peux utiliser les éléments suivants dans jQuery:
$('html, body').animate({
scrollTop: $('#myelementid').offset().top
}, 500);
Comment pourrais-je le faire avec du javascript?
C'est ce que j'essaie de faire:
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>
Dans jQuery je le ferais comme suit:
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: J'aimerais aussi pouvoir faire défiler en douceur jusqu'à une certaine position sur la page
EDIT: les solutions CSS sont également les bienvenues (bien que je préfère les solutions javascript)
Vous pouvez utiliser une boucle for
avec window.scrollTo
et setTimeout
pour faire défiler en douceur avec du Javascript simple. Pour faire défiler un élément spécifique, appelez simplement la fonction scrollToSmoothly
avec offsetTop comme premier argument.
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);
}
}
Démo:
<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>
window.requestAnimationFrame
peut être utilisé pour accéder à une position donnée dans un laps de temps précis. JSFiddle WebPage Demo: 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);
}
}
});
}
Démo:
<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>
Vous pouvez également utiliser window.scroll
qui fait défiler jusqu'à une position x et y spécifique et window.scrollBy
qui défile depuis la position actuelle:
// 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'
});
Démo:
<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>
Si vous avez seulement besoin de faire défiler jusqu'à un élément, pas une position spécifique dans le document, vous pouvez utiliser Element.scrollIntoView
avec behavior
défini sur smooth
.
document.getElementById("elemID").scrollIntoView({
behavior: 'smooth'
});
Démo:
<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>
Les navigateurs modernes supportent la propriété CSS scroll-behavior
, qui peut être utilisée pour rendre le défilement plus fluide dans le document (sans recourir à Javascript; les balises anchor peuvent être utilisées à cet effet en donnant à la balise ancre une href
de #
plus la id
de l'élément à faire défiler à). Vous pouvez également définir la propriété scroll-behavior
pour un élément spécifique, tel que div
, afin que son contenu défile de manière fluide.
Démo:
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>
La propriété CSS scroll-behavior
fonctionne également avec Javascript avec window.scrollTo
.
Démo:
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>
Pour vérifier si la propriété scroll-behavior
est prise en charge, vous pouvez vérifier si elle existe en tant que clé dans le style de l'élément HTML.
var scrollBehaviorSupported = 'scroll-behavior' in document.documentElement.style;
console.log('scroll-behavior supported:',scrollBehaviorSupported);
Comme je l’ai mentionné dans mon commentaire, scrollIntoView
est une bonne option à envisager - elle prend de plus en plus en charge les navigateurs - lorsque vous essayez de faire défiler jusqu’à un élément spécifié, comme ce que vous essayez apparemment de faire avec votre fonction scrollToSection
.
Pour faire défiler l'écran jusqu'au milieu de la page, définissez la propriété scrollTop
de l'élément body
et/ou html
sur la moitié de la différence entre scrollHeight
du corps et innerHeight
de la fenêtre. Coupler le calcul ci-dessus avec requestAnimationFrame
et vous êtes défini.
Voici comment vous pouvez intégrer les suggestions ci-dessus dans votre 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>
Pensez à utiliser Element.scrollIntoView()
.