JavaScript – window.scroll({ behavior: ‘smooth’ }) funktioniert nicht in Safari

Lesezeit: 10 Minuten

JavaScript windowscroll behavior smooth funktioniert nicht in Safari
Sorakthun Ly

Wie der Titel schon sagt, funktioniert es auf Chrome einwandfrei. Aber in Safari setzt es die Seite einfach auf die gewünschte obere und linke Position. Ist dies das erwartete Verhalten? Gibt es eine Möglichkeit, dass es gut funktioniert?

  • Ziemlich späte Antwort – aber Verhalten funktioniert nicht mit Safari oder Edge. Sie müssen Ihr eigenes System implementieren oder eine Bibliothek verwenden.

    – Georg Daniel

    26. September 18 um 15:50 Uhr

  • Dafür gibt es einen offiziellen Fehler im Safari-Bugtracker: bugs.webkit.org/show_bug.cgi?id=188043 und bugs.webkit.org/show_bug.cgi?id=189907

    – Jantimon

    29. August 19 um 14:18 Uhr


JavaScript windowscroll behavior smooth funktioniert nicht in Safari
Eugen Sunic

Benutzen Smoothscroll-Polyfill (Lösung für alle Browser), einfach anwendbar und leichtgewichtige Abhängigkeit:
https://github.com/iamdustan/smoothscroll

Sobald Sie es über npm oder Garn installiert haben, fügen Sie es zu Ihrer hinzu hauptsächlich .js, .ts Datei (eine, die zuerst ausgeführt wird)

import smoothscroll from 'smoothscroll-polyfill';
// or if linting/typescript complains
import * as smoothscroll from 'smoothscroll-polyfill';

// kick off the polyfill!
smoothscroll.polyfill();

  • Wohin damit, wenn es zu einer Reaktion kommt? es funktioniert nicht in app.js …

    – Richardson

    14. Dezember 21 um 1:15 Uhr

  • @Richardson es sollte dort funktionieren, welchen Fehler bekommst du?

    – Eugen Sunic

    14. Dezember 21 um 19:07 Uhr


  • es funktioniert nicht im Index oder in app.js wird es in React all getestet?

    – Richardson

    15. Dezember 21 um 0:20 Uhr

  • Das hat bei mir funktioniert, eingefügt index.js Datei. Ich denke immer, es ist am besten, diese Konfigurationen einzubauen index.jsda App.js eine Komponente ist.

    – thismarcoantonio

    28. Januar um 14:41 Uhr

  • Was auch immer, solange dieses Kriterium erfüllt ist, das in der Antwort enthalten ist: “einer, der zuerst ausgeführt wird”

    – Eugen Sunic

    28. Januar um 14:50 Uhr

1644318430 908 JavaScript windowscroll behavior smooth funktioniert nicht in Safari
Georg Daniel

Verhaltensoptionen werden in IE/Edge/Safari nicht vollständig unterstützt, daher müssten Sie selbst etwas implementieren. Ich glaube, jQuery hat bereits etwas, aber wenn Sie jQuery nicht verwenden, hier ist eine reine JavaScript-Implementierung:

function SmoothVerticalScrolling(e, time, where) {
    var eTop = e.getBoundingClientRect().top;
    var eAmt = eTop / 100;
    var curTime = 0;
    while (curTime <= time) {
        window.setTimeout(SVS_B, curTime, eAmt, where);
        curTime += time / 100;
    }
}

function SVS_B(eAmt, where) {
    if(where == "center" || where == "")
        window.scrollBy(0, eAmt / 2);
    if (where == "top")
        window.scrollBy(0, eAmt);
}

Und wenn Sie horizontales Scrollen benötigen:

function SmoothHorizontalScrolling(e, time, amount, start) {
    var eAmt = amount / 100;
    var curTime = 0;
    var scrollCounter = 0;
    while (curTime <= time) {
        window.setTimeout(SHS_B, curTime, e, scrollCounter, eAmt, start);
        curTime += time / 100;
        scrollCounter++;
    }
}

function SHS_B(e, sc, eAmt, start) {
    e.scrollLeft = (eAmt * sc) + start;
}

Und ein Beispielaufruf ist:

SmoothVerticalScrolling(myelement, 275, "center");

  • @George Daniel, Kudos für die native JS-Lösung, obwohl Sie Ihre Antwort verbessern könnten, indem Sie dem Code einige Inline-Kommentare hinzufügen.

    – Oksana Romaniv

    15. Oktober 19 um 7:43 Uhr

  • Window.requestAnimationFrame() sollte wegen der Performance-Optimierung anstelle von Timeouts verwendet werden und es läuft nur wenn es sichtbar ist.. etc.. blog.teamtreehouse.com/…

    – Luckylooke

    25. Oktober 19 um 8:54 Uhr

  • Vielen Dank dafür @George Daniel, ich habe einen kleinen Stift gemacht, der versucht, den Prozess Ihrer Funktion mit Kommentaren hier zu beschreiben codepen.io/gfcf14/pen/qBEMWJe

    – gfcf14

    16. Januar 20 um 15:53 ​​Uhr

  • @Mathi Was versuchst du zu tun? Stellen Sie einen Codepen von dem auf, was nicht funktioniert. Dies ist eine ziemlich alte Lösung, sollte aber immer noch funktionieren.

    – Georg Daniel

    16. September 2020 um 22:05 Uhr

  • @GeorgeDaniel Ich mache dasselbe, aber es funktioniert nicht. Ich bekomme keine Antwort

    – Ulvi

    17. März 21 um 16:51 Uhr

1644318430 365 JavaScript windowscroll behavior smooth funktioniert nicht in Safari
Ungemindert

Eine umfassendere Liste von Methoden für reibungsloses Scrollen finden Sie in meiner Antwort hier.


window.requestAnimationFrame kann verwendet werden, um reibungsloses Scrollen in einer genauen Zeitspanne durchzuführen.

Für reibungsloses vertikales Scrollen kann die folgende Funktion verwendet werden. Beachten Sie, dass das horizontale Scrollen auf die gleiche Weise erfolgen kann.

/*
   @param time: the exact amount of time the scrolling will take (in milliseconds)
   @param pos: the y-position to scroll to (in pixels)
*/
function scrollToSmoothly(pos, time) {
    var currentPos = window.pageYOffset;
    var start = null;
    if(time == null) time = 500;
    pos = +pos, time = +time;
    window.requestAnimationFrame(function step(currentTime) {
        start = !start ? currentTime : start;
        var progress = currentTime - start;
        if (currentPos < pos) {
            window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
        } else {
            window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
        }
        if (progress < time) {
            window.requestAnimationFrame(step);
        } else {
            window.scrollTo(0, pos);
        }
    });
}

Demo:

/*
   @param time: the exact amount of time the scrolling will take (in milliseconds)
   @param pos: the y-position to scroll to (in pixels)
*/
function scrollToSmoothly(pos, time) {
    var currentPos = window.pageYOffset;
    var start = null;
    if(time == null) time = 500;
    pos = +pos, time = +time;
    window.requestAnimationFrame(function step(currentTime) {
        start = !start ? currentTime : start;
        var progress = currentTime - start;
        if (currentPos < pos) {
            window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
        } else {
            window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
        }
        if (progress < time) {
            window.requestAnimationFrame(step);
        } else {
            window.scrollTo(0, pos);
        }
    });
}

document.querySelector('button').addEventListener('click', function(e){
  scrollToSmoothly(500, 1500);
});
html, body {
  height: 1000px;
}
<button>Scroll to y-position 500px in 1500ms</button>

Für komplexere Fälle ist die SmoothScroll.js-Bibliothek kann verwendet werden, die reibungsloses Scrollen sowohl vertikal als auch horizontal, Scrollen innerhalb anderer Containerelemente, unterschiedliche Beschleunigungsverhalten, Scrollen relativ von der aktuellen Position und mehr handhabt. Es unterstützt auch die meisten Browser, die kein natives Smooth-Scrolling haben.

var easings = document.getElementById("easings");
for(var key in smoothScroll.easing){
    if(smoothScroll.easing.hasOwnProperty(key)){
        var option = document.createElement('option');
        option.text = option.value = key;
        easings.add(option);
    }
}
document.getElementById('to-bottom').addEventListener('click', function(e){
    smoothScroll({yPos: 'end', easing: easings.value, duration: 2000});
});
document.getElementById('to-top').addEventListener('click', function(e){
    smoothScroll({yPos: 'start', easing: easings.value, duration: 2000});
});
<script src="https://cdn.jsdelivr.net/gh/LieutenantPeacock/[email protected]/src/smoothscroll.min.js" integrity="sha384-UdJHYJK9eDBy7vML0TvJGlCpvrJhCuOPGTc7tHbA+jHEgCgjWpPbmMvmd/2bzdXU" crossorigin="anonymous"></script>
<!-- Taken from one of the library examples -->
Easing: <select id="easings"></select>
<button id="to-bottom">Scroll To Bottom</button>
<br>
<button id="to-top" style="margin-top: 5000px;">Scroll To Top</button>

  • Danke. Besteht die Möglichkeit, auch Lockerungen hinzuzufügen?

    – FredK

    1. Juni 21 um 12:36 Uhr


  • @FredK Entschuldigung für die späte Antwort, aber ich habe meine Antwort aktualisiert.

    – Uneingeschränkt

    3. August 21 um 16:08 Uhr

Die Lösung mit der reibungslosesten Leistung, insbesondere wenn Sie Easing integrieren möchten, ist die Verwendung von requestAnimationFrame:

const requestAnimationFrame = window.requestAnimationFrame ||
          window.mozRequestAnimationFrame ||
          window.webkitRequestAnimationFrame ||
          window.msRequestAnimationFrame;

const step = (timestamp) => {
  window.scrollBy(
    0,
    1, // or whatever INTEGER you want (this controls the speed)
  );

  requestAnimationFrame(step);
};


requestAnimationFrame(step);

Wenn Sie den Bildlauf später abbrechen möchten, müssen Sie einen Verweis auf Ihren RequestAnimationFrame haben (tun Sie dies überall dort, wo Sie RequestAnimationFrame(step) verwenden):

this.myRequestAnimationFrame = requestAnimationFrame(step);

const cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
cancelAnimationFrame(this.myRequestAnimationFrame);

Was nun, wenn Sie beim Scrollen die Beschleunigung verwenden und zwischen den Scroll-Aktionen Timeouts einlegen möchten?

Erstellen Sie ein Array aus 60 Elementen (requestAnimationFrame ruft normalerweise 60 Mal pro Sekunde auf. Technisch gesehen ist es unabhängig von der Aktualisierungsrate des Browsers, aber 60 ist die häufigste Zahl.) Wir werden dieses Array nicht linear füllen und dann diese Zahlen verwenden Steuern Sie, wie viel bei jedem Schritt von requestAnimationFrame gescrollt werden soll:

let easingPoints = new Array(60).fill(0)

Wählen Sie eine Beschleunigungsfunktion. Nehmen wir an, wir führen ein kubisches Ease-out durch:

function easeCubicOut
    return --t * t * t + 1;
}

Erstellen Sie ein Dummy-Array und füllen Sie es mit Daten, die durch die Beschleunigungsfunktion geleitet werden. Sie werden gleich sehen, warum wir das brauchen:

    // easing function will take care of decrementing t at each call (too lazy to test it at the moment. If it doesn't, just pass it a decrementing value at each call)
    let t = 60;
    const dummyPoints = new Array(60).fill(0).map(()=> easeCubicOut
    const dummyPointsSum = dummyPoints.reduce((a, el) => {
                                a += el;
                               return a;
                           }, 0);

Bilden Sie EasingPoints mit Hilfe des Verhältnisses von DummyPoint zu DummyPointsSum ab:

    easingPoints = easingPoints.map((el, i) => {
        return Math.round(MY_SCROLL_DISTANCE * dummyPoints[i] / dummyPointsSum);
    });

In Ihrer Bildlauffunktion nehmen wir einige Anpassungen vor:

     const requestAnimationFrame = window.requestAnimationFrame ||
              window.mozRequestAnimationFrame ||
              window.webkitRequestAnimationFrame ||
              window.msRequestAnimationFrame;

     let i = 0;
     const step = (timestamp) => {
       window.scrollBy(
         0,
         easingPoints[i],
       );


        if (++i === 60) {
                i = 0;
                return setTimeout(() => {
                  this.myRequestAnimationFrame = requestAnimationFrame(step);
                }, YOUR_TIMEOUT_HERE);
        }
      };


      this.myRequestAnimationFrame = requestAnimationFrame(step);

JavaScript windowscroll behavior smooth funktioniert nicht in Safari
Terrymorse

Die Workarounds machen vor allem die fehlende Safari-Unterstützung für Behaviors wett.

Es ist immer noch notwendig zu erkennen, wann eine Problemumgehung erforderlich ist.

Diese kleine Funktion erkennt, ob Smooth Scrolling vom Browser unterstützt wird. Bei Safari wird false zurückgegeben, bei Chrome und Firefox true:

// returns true if browser supports smooth scrolling
const supportsSmoothScrolling = () => {
  const body = document.body;
  const scrollSave = body.style.scrollBehavior;
  body.style.scrollBehavior="smooth";
  const hasSmooth = getComputedStyle(body).scrollBehavior === 'smooth';
  body.style.scrollBehavior = scrollSave;
  return hasSmooth;
};

const pre = document.querySelector('pre');

// returns true if browser supports smooth scrolling
const supportsSmoothScrolling = () => {
  const body = document.body;
  const scrollSave = body.style.scrollBehavior;
  body.style.scrollBehavior="smooth";
  const hasSmooth = getComputedStyle(body).scrollBehavior === 'smooth';
  body.style.scrollBehavior = scrollSave;
  return hasSmooth;
};

const supported = supportsSmoothScrolling();

pre.innerHTML = `supported:  ${ (supported) ? 'true' : 'false'}`;
<h3>
Testing if 'scrollBehavior smooth' is supported
</h3>
<pre></pre>

Aktualisieren

Test von Safari Technology Preview, Release 139 (Safari 15.4) zeigt Unterstützung für scrollBehavior smoothalso können wir erwarten, Unterstützung in 15.4 zu sehen.

1644318431 598 JavaScript windowscroll behavior smooth funktioniert nicht in Safari
Connor Cowling

Ein einfacher jQuery-Fix, der für Safari funktioniert:

$('a[href*="#"]').not('[href="#"]').not('[href="#0"]').click(function 
    if (location.pathname.replace(/^//, "") == this.pathname.replace(/^//, "") && location.hostname == this.hostname) {
        var e = $(this.hash);
        e = e.length ? e : $("[name=" + this.hash.slice(1) + "]"), e.length && (t.preventDefault(), $("html, body").animate({
            scrollTop: e.offset().top
        }, 600, function () {
            var t = $(e);
            if (t.focus(), t.is(":focus")) return !1;
            t.attr("tabindex", "-1"), t.focus()
        }))
    }
});

Durch die Kombination der Antworten von George Daniel und Terrymorse kann das Folgende für die gesamte Unterstützung des Browsers mit nativem JavaScript verwendet werden.

Da Chrome, Firefox CSS unterstützt, scroll-behavior: smooth; für die Browser, die diese Eigenschaft nicht unterstützen, können wir unten hinzufügen.

HTML:

<a onclick="scrollToSection(event)" href="#section">
    Redirect On section
</a>
  
<section id="section">
  Section Content
</section>

CSS:

body {
  scroll-behavior: smooth;
}

Javascript:

function scrollToSection(event) {
  if (supportsSmoothScrolling()) {
    return;
  }
  event.preventDefault();
  const scrollToElem = document.getElementById("section");
  SmoothVerticalScrolling(scrollToElem, 300, "top");
}

function supportsSmoothScrolling() {
  const body = document.body;
  const scrollSave = body.style.scrollBehavior;
  body.style.scrollBehavior="smooth";
  const hasSmooth = getComputedStyle(body).scrollBehavior === 'smooth';
  body.style.scrollBehavior = scrollSave;
  return hasSmooth;
};
 
function SmoothVerticalScrolling(element, time, position) {
  var eTop = element.getBoundingClientRect().top;
  var eAmt = eTop / 100;
  var curTime = 0;
  while (curTime <= time) {
    window.setTimeout(SVS_B, curTime, eAmt, position);
    curTime += time / 100;
  }
}

function SVS_B(eAmt, position) {
  if (position == "center" || position == "")
  window.scrollBy(0, eAmt / 2);
  if (position == "top")
  window.scrollBy(0, eAmt);
}

  • Wie alle anderen Antworten funktioniert dies nicht unter Safari 14.1.2 (MacOS 11.5.1)

    – BSUK

    8. August 21 um 22:04 Uhr

  • @BSUK: Es funktioniert gut mit Safari 14.0.2 (MacOS 11.1).

    – Aniruddha Shevle

    9. August 21 um 4:23 Uhr

  • Ich erhalte diesen Fehler, wenn ich auf einen Link klicke: TypeError: null is not an object (evaluating ‘element.getBoundingClientRect’)

    – BSUK

    10. August 21 um 14:41 Uhr

  • @BSUK: Das vermute ich hier const scrollToElem = document.getElementById("section");, scrollToElem ist in Ihrem Fall null. Bitte stellen Sie sicher, dass Sie ein Element mit id=”section” haben, zu dem wir scrollen möchten. ODER stellen Sie sicher, dass Sie einen geeigneten ID-Selektor hinzufügen, damit scrollToElem nicht null ist.

    – Aniruddha Shevle

    11. August 21 um 2:11 Uhr

  • Vielen Dank für deine Hilfe! Es funktioniert jetzt, wenn ich die Element-ID fest codiere, aber natürlich muss es dynamisch funktionieren, basierend auf dem Ankerlink, auf den geklickt wird (wie das standardmäßige Smooth-Scrolling-Verhalten). Ich denke, ich muss mein Javascript auffrischen und diese Funktion ein wenig entwickeln. Super ärgerlich, dass Safari dieses CSS-Verhalten nicht einfach von Haus aus unterstützt.

    – BSUK

    11. August 21 um 12:07 Uhr


.

821850cookie-checkJavaScript – window.scroll({ behavior: ‘smooth’ }) funktioniert nicht in Safari

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy