Skip to content

Allt om WordPress, webbutveckling — och mer därtill

🖱 Mjuk skrollning till ankare: CSS, JavaScript och jQuery - tre fungerande metoder

🖱 Mjuk skrollning till ankare: CSS, JavaScript och jQuery - tre fungerande metoder

Användaren klickar på en länk med ett ankare, och sidan hoppar omedelbart till målplatsen. Ingen animation, ingen mjukhet, ingen förståelse för var man hamnade. Den hackiga övergången är desorienterande, särskilt på långa landningssidor och i dokumentation.

Att lägga till mjuk scroll till ankare tar 5 minuter. Men djävulen sitter i detaljerna: länken kan komma från en extern webbplats, URL:en har redan en hash, och det finns en fast header högst upp som täcker ankaret. Vanlig scroll-behavior: smooth löser inte dessa nyanser.

Här är tre fungerande tillvägagångssätt: ren CSS, native JavaScript, och jQuery. Var och en med kod du kan kopiera och klistra in i ditt projekt. Dessutom täcker vi separat externa övergångar så att scrollningen fungerar även när användaren kommer från en annan sida eller från sökresultat.

💡 Snabb översikt:

  • Aktivera mjuk scroll med en CSS-rad, ingen JavaScript alls
  • Lägg till offset för fast header med scroll-margin-top
  • Skriv native JS med scrollIntoView för externa övergångar och finjustering
  • Täck jQuery-varianten med animate() när du behöver anpassad hastighet och kontroll
  • Hantera extern hash: sidan laddad, ankare i URL:en, och mjuk scroll till målet

Varför mjuk scroll spelar roll

Ett abrupt hopp till ett ankare är desorienterande. Användaren tappar sammanhanget: var var jag, var hamnade jag, vad missade jag? Mjuk scrollning upprätthåller rumslig orientering och ger ögat något att följa medan sidan rör sig.

Ur ett uppfattningsperspektiv ser en webbplats med mjuk scroll polerad ut. Detta märks särskilt på långa sidor: landningssidor, dokumentation, FAQ-sektioner, innehållsförteckningar i artiklar. Användaren klickar på "Priser" i menyn, och sidan rycker inte till utan glider mjukt till prisblocket.

Tekniskt sett delas uppgiften i två: scroll vid klick på en intern länk (användaren är redan på sidan) och scroll vid extern övergång (URL:en innehåller redan #anchor). I det andra fallet hoppar webbläsaren som standard till ankaret omedelbart, även innan full laddning, och detta måste fångas upp.

CSS scroll-behavior, en rad istället för ett skript

Det enklaste och mest moderna tillvägagångssättet. Webbläsare lärde sig mjuk scroll native, det räcker med en CSS-regel:

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

Det är allt. Varje övergång via ankarlänk blir mjuk. Ingen JavaScript, inga bibliotek.

Stöd: alla moderna webbläsare sedan 2022: Chrome 61+, Firefox 36+, Safari 15.4+, Edge 79+. Det enda undantaget är IE11, men dess trafikandel närmar sig noll.

Fast header: scroll-margin-top

Om en fast header (sticky header) hänger ovanför innehållet kommer ankaret efter scrollning att hamna under den. Fixas med en rad:

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

Webbläsaren lägger automatiskt till offset när den scrollar till målelementet. Tidigare skrev folk hacks med padding-top och negativ margin, nu behövs det inte.

Rena CSS-begränsningar

CSS-metoden har ingen kontroll över animationshastighet och easing-funktion. Webbläsaren använder en inbyggd kurva, vanligtvis ease-in-out. Om du behöver anpassad hastighet eller icke-linjär animation, gå vidare till JavaScript.

Native JavaScript: scrollIntoView

När enbart CSS inte räcker kommer scrollIntoView()-metoden med alternativet behavior: 'smooth' till undsättning:

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});

Denna kod fångar upp klick på alla länkar med #, avbryter standardövergången och startar mjuk scroll. Fungerar utan jQuery och utan ytterligare bibliotek.

Fördelen: du kan styra det programmatiskt: ändra hastighet via CSS scroll-behavior<html>, lägga till villkor (till exempel exkludera vissa länkar), kombinera med scroll-margin-top för headern.

Nackdelen: scrollIntoView låter dig inte ställa in animationshastighet direkt. För anpassad scrolltid (säg 800 ms istället för webbläsarens ~500 ms) behöver du antingen jQuery eller manuell requestAnimationFrame.

JQuery animate, full kontroll över animationen

Om projektet redan använder jQuery eller du behöver finjustering (hastighet, offset för header, länkfiltrering), här är det aktuella skriptet. Nedan finns en anpassad version av den klassiska metoden, omskriven för modern 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});

Vad som ändrats här jämfört med gamla versioner som flyter runt på bloggar:

  • .bind() ersatt med .on(), .bind() förklarades föråldrat i jQuery 3.0 och kommer att tas bort i jQuery 4.0.
  • Selektor 'a:not(.spu-clickable)[href*="#"]:not([href="#"])' förenklad, den specifika klassen .spu-clickable relaterad till en specifik plugin (Popups by OptinMonster) och behövs i allmänhet inte.
  • jQuery(window).bind("load", ...) borttagen, den andra delen av skriptet för extern hash ligger nu i $(document).ready() och kräver ingen separat load-händelse.
  • Tillagd fördröjning setTimeout(..., 100) så att DOM garanterat är renderat innan ankarets position beräknas (relevant för sidor med lazy loading av bilder och dynamiskt innehåll).

Var du ska infoga koden

Tre alternativ att välja mellan:

  • Via temafil. Lägg till skriptet i functions.php via wp_enqueue_script(), standardmetoden för ett barntema.
  • Plugin Code Snippets. Infoga koden som en ny snippet med auto-run, försvinner inte vid temauppdatering.
  • Anpassat JS-plugin. Om webbplatsen redan använder ett plugin för att infoga godtycklig JavaScript (till exempel WPCode), lägg till koden där.

Hantering av extern övergång med hash, detaljerad genomgång

Den mest knepiga delen av uppgiften. Användaren följer en länk https://site.com/page/#pricing från en annan webbplats eller från sök. Webbläsaren hoppar som standard omedelbart till #pricing så snart elementet dyker upp i DOM, utan animation och ofta innan sidan är fulladdad.

jQuery-skriptet ovan löser detta i två steg:

  • Upptäcker hash-närvaro via window.location.hash. Om hash finns, läser dess värde (utan #).
  • Hittar mål och scrollar. $('#' + hash) hittar elementet, setTimeout ger sidan tid att renderas, animate() leder till målet med 80 pixlars offset.

Fördröjningen på 100 millisekunder är empirisk. På snabba sidor räcker 50 ms, på tunga (landningssidor med bakgrundsvideo, kartor, diagram) är det bättre att öka till 200-300 ms. Alternativ: vänta på window.load-händelsen istället för document.ready, men då sker scrollning först efter att alla bilder laddats, vilket kan ta ett tag.

Vad du ska göra om ankare inte hittar mål

Ibland pekar hashen i URL:en på ett icke-existerande element. Till exempel gjorde användaren ett stavfel eller sidan ändrades. I detta fall kommer varken CSS- eller JS-metoden att misslyckas med ett fel, helt enkelt kommer ingenting att hända. Webbläsaren ignorerar det icke-existerande ankaret. Mjuk scroll kommer också att fungera tyst (villkoret if (target.length) låter det inte fortsätta).

Jämförelse av tre tillvägagångssätt

Kriterium

CSS scroll-behavior

JS scrollIntoView

jQuery animate

Implementeringskomplexitet

1 rad CSS

10-15 rader JS

25-30 rader JS + jQuery

Hastighetskontroll

Nej

Nej (webbläsarens standard)

Ja (ms)

Extern hash

Ja, native

Kräver extra kod

Kräver extra kod

Header-offset

scroll-margin-top

scroll-margin-top

Manuell i offset().top

Beroenden

Inga

Inga

jQuery 3.x

Webbläsarstöd

96%+

96%+

99%+ (med jQuery)

För de flesta moderna projekt är CSS-metoden optimal: en rad, noll beroenden, native prestanda. Om du behöver offset för header, lägg till scroll-margin-top. Om du behöver anpassad hastighet eller stöd för uråldriga webbläsare, jQuery med animate().

Nedan finns en video med livedemonstration av alla tre tillvägagångssätt, från CSS till jQuery:

⁉️🤔 Vanliga frågor

Varför fungerar inte mjuk scroll på mobila enheter?

I iOS Safari före version 15.4 stöddes inte scroll-behavior: smooth. Nu finns stöd (Safari 15.4+, mars 2022). Om scroll inte fungerar på gamla iPhones, lägg till en JavaScript-fallback med scrollIntoView eller requestAnimationFrame. Kontrollera också att scroll inte blockeras av overflow: hiddenbody, vissa mobila menyer sätter det när de öppnas. I juni 2026 är det globala stödet för scroll-behavior 96,3% av webbläsarna (Can I Use data).

Hur gör man mjuk scroll inte till ett ankare utan till ett godtyckligt element vid knappklick?

Ge elementet ett id och använd samma JavaScript, men bundet till en knapp istället för en ankarlänk. Till exempel "Tillbaka till toppen"-knapp: document.querySelector('#back-to-top').addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' })). För jQuery-varianten: $('#back-to-top').on('click', () => $('html, body').animate({ scrollTop: 0 }, 600)). Inga ankare behövs, scroll till koordinater.

Är det nödvändigt att inkludera jQuery bara för mjuk scroll år 2026?

Nej. jQuery väger cirka 87 KB i min-version (30 KB gzip). Om jQuery inte används någon annanstans på webbplatsen är det irrationellt att inkludera det för en scroll. Ta CSS-metoden med scroll-behavior: smooth eller native scrollIntoView. jQuery är motiverat endast om webbplatsen redan är byggd på det (jQuery-teman, äldre projekt) och du vill lägga till scroll till den befintliga kodbasen.

Kan man animera scroll med olika hastighet, snabbt först, sedan långsamt?

Ja, genom $.animate() med jQuery UI eller genom requestAnimationFrame med en easing-funktion. Standard jQuery animate() använder linjär eller swing-funktion. För icke-standardkurvor, inkludera jquery.easing eller skriv din egen loop på requestAnimationFrame med en anpassad easing-funktion, till exempel easeInOutQuad. Detta ger full kontroll över hastighet, bana och kräver inga externa bibliotek.

Hur verifierar man att scroll fungerar vid extern övergång med hash?

Öppna en ny flik, klistra in URL med ankare (till exempel https://yoursite.com/page/#contacts) och tryck Enter. Sidan ska laddas och mjukt scrolla till blocket. Andra alternativet: i webbläsarkonsolen på den öppna sidan, kör location.hash = '#contacts'. Om scroll är mjuk fungerar skriptet. Om sidan ryckte till omedelbart är den externa hash-hanteraren inte konfigurerad.

Vilket tillvägagångssätt du ska välja för din uppgift

Om webbplatsen är modern, utan jQuery, täcker CSS scroll-behavior: smooth de allra flesta scenarier. En rad, omedelbart resultat. Lägg till scroll-margin-top för headern, och du är klar.

Om webbplatsen är på WordPress med jQuery i temat, jQuery-skript med animate(). Ger kontroll över hastighet och offset, hanterar externa övergångar, krockar inte med andra plugins.

Om du skriver från grunden och inte vill dra in ett bibliotek, native scrollIntoView() med extern hash-hanterare. Den gyllene medelvägen: ren, snabb, inga beroenden.

Ta koden från artikeln, klistra in den i ditt projekt och kontrollera extern övergång, detta är det enda fall som är lätt att missa under testning.