Skip to content

Alt om WordPress, webutvikling — og mer til

🖱 Jevn rulling til anker: CSS, JavaScript og jQuery - tre fungerende tilnærminger

🖱 Jevn rulling til anker: CSS, JavaScript og jQuery - tre fungerende tilnærminger

Brukeren klikker på en lenke med et anker, og siden hopper øyeblikkelig til målstedet. Ingen animasjon, ingen mykhet, ingen forståelse av hvor du havnet. Den rykkete overgangen er desorienterende, spesielt på lange landingssider og i dokumentasjon.

Å legge til myk skrolling til ankere tar 5 minutter. Men djevelen ligger i detaljene: lenken kan komme fra et eksternt nettsted, URL-en har allerede en hash, og det er en fast topptekst som dekker ankeret. Vanlig scroll-behavior: smooth løser ikke disse nyansene.

Nedenfor finner du tre fungerende tilnærminger: ren CSS, native JavaScript og jQuery. Hver med kode du kan kopiere og lime inn i prosjektet ditt. I tillegg dekker vi eksterne overganger separat, slik at skrolling fungerer selv når brukeren kommer fra en annen side eller fra søkeresultater.

💡 Rask oversikt:

  • Aktiver myk skrolling med én CSS-linje, helt uten JavaScript
  • Legg til offset for fast topptekst ved hjelp av scroll-margin-top
  • Skriv native JS med scrollIntoView for eksterne overganger og finjustering
  • Dekk jQuery-varianten med animate() når du trenger tilpasset hastighet og kontroll
  • Håndter ekstern hash: siden lastet, anker i URL, og myk skrolling til målet

Hvorfor myk skrolling er viktig

Brå hopping til et anker er desorienterende. Brukeren mister kontekst: hvor var jeg, hvor havnet jeg, hva gikk jeg glipp av? Myk skrolling opprettholder romlig orientering og gir øyet noe å følge mens siden beveger seg.

Fra et oppfatningssynspunkt ser et nettsted med myk skrolling polert ut. Dette er spesielt merkbart på lange sider: landingssider, dokumentasjon, FAQ-seksjoner, innholdsfortegnelser i artikler. Brukeren klikker på «Priser» i menyen, og siden rykker ikke, men glir forsiktig til prisblokken.

Teknisk sett deles oppgaven i to: skrolling ved klikk på en intern lenke (brukeren er allerede på siden) og skrolling ved ekstern overgang (URL inneholder allerede #anchor). I det andre tilfellet hopper nettleseren som standard til ankeret øyeblikkelig, selv før full lasting, og dette må fanges opp.

CSS scroll-behavior, én linje i stedet for et skript

Den enkleste og mest moderne tilnærmingen. Nettlesere lærte myk skrolling naturlig, bare én CSS-regel er nok:

1html {
2 scroll-behavior: smooth;
3}

Det er alt. Enhver overgang via ankerlenke blir myk. Ingen JavaScript, ingen biblioteker.

Støtte: alle moderne nettlesere siden 2022: Chrome 61+, Firefox 36+, Safari 15.4+, Edge 79+. Eneste unntak er IE11, men trafikkandelen nærmer seg null.

Fast topptekst: scroll-margin-top

Hvis en fast topptekst (sticky header) henger over innholdet, vil ankeret etter skrolling havne under den. Løses med én linje:

1h2, h3, [id] {
2 scroll-margin-top: 80px; /* header height + offset */
3}

Nettleseren vil automatisk legge til offset når det skrolles til målelementet. Tidligere skrev man hack med padding-top og negativ margin, nå er det ikke nødvendig.

Begrensninger med ren CSS

CSS-tilnærmingen har ingen kontroll over animasjonshastighet og easing-funksjon. Nettleseren bruker en innebygd kurve, vanligvis ease-in-out. Hvis du trenger tilpasset hastighet eller ikke-lineær animasjon, gå videre til JavaScript.

Native JavaScript: scrollIntoView

Når CSS alene ikke er nok, kommer scrollIntoView()-metoden med behavior: 'smooth'-alternativet til unnsetning:

1document.querySelectorAll('a[href^="#"]').forEach(anchor => {
2 anchor.addEventListener('click', function(e) {
3 e.preventDefault();
4 const target = document.querySelector(this.getAttribute('href'));
5 if (target) {
6 target.scrollIntoView({
7 behavior: 'smooth',
8 block: 'start'
9 });
10 }
11 });
12});

Denne koden fanger opp klikk på alle lenker med #, avbryter standardovergangen og starter myk skrolling. Fungerer uten jQuery og uten ekstra biblioteker.

Fordelen: du kan kontrollere det programmatisk: endre hastighet via CSS scroll-behavior<html>, legge til betingelser (for eksempel ekskludere visse lenker), kombinere med scroll-margin-top for toppteksten.

Ulempen: scrollIntoView lar deg ikke angi animasjonshastighet direkte. For tilpasset skrolletid (for eksempel 800 ms i stedet for nettleserens ~500 ms) trenger du enten jQuery eller manuell requestAnimationFrame.

JQuery animate, full kontroll over animasjon

Hvis prosjektet allerede bruker jQuery eller du trenger finjustering (hastighet, offset for topptekst, lenkefiltrering), her er det aktuelle skriptet. Nedenfor er en tilpasset versjon av den klassiske tilnærmingen, omskrevet for moderne jQuery:

1jQuery(document).ready(function($) {
2 // Smooth scroll on anchor link click
3 $('a[href*="#"]:not([href="#"])').on('click', function() {
4 if (
5 location.pathname.replace(/^\//, '') === this.pathname.replace(/^\//, '')
6 && location.hostname === this.hostname
7 ) {
8 var target = $(this.hash);
9 target = target.length ? target : $('[name="' + this.hash.slice(1) + '"]');
10 if (target.length) {
11 $('html, body').animate({
12 scrollTop: target.offset().top - 80
13 }, 800);
14 return false;
15 }
16 }
17 });
18
19 // Scroll on external transition with hash in URL
20 if (window.location.hash) {
21 var hash = window.location.hash.substring(1);
22 var $target = $('#' + hash);
23 if ($target.length) {
24 setTimeout(function() {
25 $('html, body').animate({
26 scrollTop: $target.offset().top - 80
27 }, 800);
28 }, 100);
29 }
30 }
31});

Hva som er endret her sammenlignet med gamle versjoner som flyter rundt på blogger:

  • .bind() erstattet med .on(), .bind() ble erklært utdatert i jQuery 3.0 og vil bli fjernet i jQuery 4.0.
  • Selektor 'a:not(.spu-clickable)[href*="#"]:not([href="#"])' forenklet, den spesifikke klassen .spu-clickable relatert til en spesifikk plugin (Popups by OptinMonster) og er generelt ikke nødvendig.
  • jQuery(window).bind("load", ...) fjernet, den andre delen av skriptet for ekstern hash ligger nå i $(document).ready() og krever ikke en separat load-hendelse.
  • Lagt til forsinkelse setTimeout(..., 100) slik at DOM-en garantert er rendret før beregning av ankerposisjon (relevant for sider med lat lasting av bilder og dynamisk innhold).

Hvor du setter inn koden

Tre alternativer å velge mellom:

  • Via temafil. Legg til skriptet i functions.php via wp_enqueue_script(), standardmetoden for et child theme.
  • Plugin Code Snippets. Sett inn koden som en ny snippet med automatisk kjøring, går ikke tapt ved temaoppdatering.
  • Tilpasset JS-plugin. Hvis nettstedet allerede bruker en plugin for å sette inn vilkårlig JavaScript (for eksempel WPCode), legg til koden der.

Håndtering av ekstern overgang med hash, detaljert gjennomgang

Den vanskeligste delen av oppgaven. Brukeren følger en lenke https://site.com/page/#pricing fra et annet nettsted eller fra søk. Nettleseren hopper som standard øyeblikkelig til #pricing så snart elementet vises i DOM-en, uten animasjon og ofte før siden er fullstendig lastet.

jQuery-skriptet ovenfor løser dette i to trinn:

  • Oppdager hash-tilstedeværelse via window.location.hash. Hvis hash finnes, les verdien (uten #).
  • Finner mål og skroller. $('#' + hash) finner elementet, setTimeout gir siden tid til å rendres, animate() fører til målet med 80 piksler offset.

Forsinkelsen på 100 millisekunder er empirisk. På raske sider er 50 ms nok, på tunge (landingssider med bakgrunnsvideo, kart, diagrammer) er det bedre å øke til 200-300 ms. Alternativ: vent på window.load-hendelsen i stedet for document.ready, men da vil skrolling først skje etter at alle bilder er lastet, noe som kan ta en stund.

Hva du gjør hvis ankeret ikke finner målet

Noen ganger peker hashen i URL-en til et ikke-eksisterende element. For eksempel har brukeren skrevet feil eller siden er endret. I dette tilfellet vil verken CSS- eller JS-tilnærmingen feile med en feil, det vil rett og slett ikke skje noe. Nettleseren vil ignorere det ikke-eksisterende ankeret. Myk skrolling vil også fungere lydløst (betingelsen if (target.length) vil ikke la den fortsette).

Sammenligning av tre tilnærminger

Kriterium

CSS scroll-behavior

JS scrollIntoView

jQuery animate

Implementeringskompleksitet

1 linje CSS

10-15 linjer JS

25-30 linjer JS + jQuery

Hastighetskontroll

Nei

Nei (nettleserstandard)

Ja (ms)

Ekstern hash

Ja, naturlig

Krever ekstra kode

Krever ekstra kode

Topptekst-offset

scroll-margin-top

scroll-margin-top

Manuelt i offset().top

Avhengigheter

Ingen

Ingen

jQuery 3.x

Nettleserstøtte

96%+

96%+

99%+ (med jQuery)

For de fleste moderne prosjekter er CSS-tilnærmingen optimal: én linje, null avhengigheter, naturlig ytelse. Hvis du trenger offset for topptekst, legg til scroll-margin-top. Hvis du trenger tilpasset hastighet eller støtte for eldre nettlesere, jQuery med animate().

Nedenfor er en video med live demonstrasjon av alle tre tilnærminger, fra CSS til jQuery:

⁉️🤔 Ofte stilte spørsmål

Hvorfor fungerer ikke myk skrolling på mobile enheter?

I iOS Safari før versjon 15.4 var scroll-behavior: smooth ikke støttet. Nå finnes støtte (Safari 15.4+, mars 2022). Hvis skrolling ikke fungerer på gamle iPhones, legg til et JavaScript-fallback med scrollIntoView eller requestAnimationFrame. Sjekk også at skrolling ikke er blokkert av overflow: hiddenbody, noen mobilmenyer setter dette ved åpning. Per juni 2026 er global støtte for scroll-behavior 96,3% av nettlesere (Can I Use-data).

Hvordan lage myk skrolling ikke til et anker, men til et vilkårlig element ved knappeklikk?

Gi elementet en id og bruk samme JavaScript, men bundet til en knapp i stedet for en ankerlenke. For eksempel «Tilbake til toppen»-knapp: document.querySelector('#back-to-top').addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' })). For jQuery-varianten: $('#back-to-top').on('click', () => $('html, body').animate({ scrollTop: 0 }, 600)). Ingen ankere nødvendig, skroll til koordinater.

Er det nødvendig å inkludere jQuery bare for myk skrolling i 2026?

Nei. jQuery veier omtrent 87 KB i minifisert versjon (30 KB gzip). Hvis jQuery ikke brukes andre steder på nettstedet, er det irrasjonelt å inkludere det for én skrolling. Bruk CSS-tilnærmingen med scroll-behavior: smooth eller native scrollIntoView. jQuery er kun berettiget hvis nettstedet allerede er bygget på det (jQuery-temaer, eldre prosjekter) og du ønsker å legge til skrolling i den eksisterende kodebasen.

Kan du animere skrolling med forskjellig hastighet, raskt først, deretter sakte?

Ja, via $.animate() med jQuery UI eller via requestAnimationFrame med en easing-funksjon. Standard jQuery animate() bruker lineær eller swing-funksjon. For ikke-standard kurver, inkluder jquery.easing eller skriv din egen løkke på requestAnimationFrame med en tilpasset easing-funksjon, for eksempel easeInOutQuad. Dette gir full kontroll over hastighet, bane og krever ikke eksterne biblioteker.

Hvordan bekrefte at skrolling fungerer ved ekstern overgang med hash?

Åpne en ny fane, lim inn URL med anker (for eksempel https://yoursite.com/page/#contacts) og trykk Enter. Siden skal lastes og mykt skrolle til blokken. Andre alternativ: i nettleserkonsollen på den åpne siden, utfør location.hash = '#contacts'. Hvis skrolling er myk, fungerer skriptet. Hvis siden rykket øyeblikkelig, er ikke den eksterne hash-håndtereren konfigurert.

Hvilken tilnærming du bør velge for din oppgave

Hvis nettstedet er moderne, uten jQuery, dekker CSS scroll-behavior: smooth de aller fleste scenarier. Én linje, øyeblikkelig resultat. Legg til scroll-margin-top for toppteksten, så er du ferdig.

Hvis nettstedet er på WordPress med jQuery i temaet, jQuery-skript med animate(). Gir kontroll over hastighet og offset, håndterer eksterne overganger, kommer ikke i konflikt med andre plugins.

Hvis du skriver fra bunnen av og ikke vil dra inn et bibliotek, native scrollIntoView() med ekstern hash-håndterer. Den gylne middelvei: rent, raskt, ingen avhengigheter.

Ta koden fra artikkelen, lim den inn i prosjektet ditt og sjekk ekstern overgang, dette er det eneste tilfellet som er lett å overse under testing.