
🔧 JQuery: mjuk skrollning till ankare vid navigering från en annan sida
Du har lagt till ett ankare på sidan, skrivit #section i URL:en och förväntar dig en fin mjuk scroll. Användaren klickar från en annan sida, webbläsaren applicerar lydigt hashen... och rycker abrupt till målet. Ingen scroll. Bara ett omedelbart hopp.
Problemet är att webbläsare hanterar hashen direkt som standard, innan DOM:en är helt klar och skript hinner fånga upp händelsen. När en användare kommer via en extern länk aktiveras din click-hanterare aldrig: det fanns ingen klickhändelse, bara en direkt URL-navigering.
Vi har sammanställt två beprövade jQuery-lösningar: ett grundläggande skript för enkla fall och en avancerad version med klickhantering, stöd för sidladdning och konfliktundvikande. Båda är testade i skarpa projekt och fungerar med aktuella jQuery-versioner.
💡 Snabb översikt:
- Spara hashen från URL:en i en temporär variabel
- Rensa
location.hashså att webbläsaren inte hoppar abrupt - Scrolla till ankaret via
animate()med önskad offset - Återställ hashen för en korrekt URL i adressfältet
Varför mjuk ankarlänksscrollning är viktigt
När en besökare följer en länk som site.com/page/#pricing förväntar de sig att se prisblocket, inte sidans topp. Ett abrupt hopp är desorienterande: användaren förstår inte var de hamnade eller vad som kom innan. Mjuk scrollning ger sammanhang: ögonen fångar mellanliggande sektioner, och hjärnan kartlägger vägen från ursprung till destination.
Med den inbyggda CSS-egenskapen scroll-behavior: smooth är det enkelt: lägg till den i din stilmall, så scrollar webbläsaren till ankaret automatiskt. Men den metoden fallerar så fort du behöver en anpassad offset för en fast header. En 110-pixel offset hindrar blocket från att glida under header och placerar det exakt där användaren förväntar sig. jQuery-lösningen ger dig den kontrollen.
Det finns också kompatibilitet mellan webbläsare. scroll-behavior: smooth fungerar inte i Internet Explorer (ja, sådana projekt finns fortfarande), medan jQuerys animate()-metod beter sig identiskt överallt.
Grundläggande skript: minimal kod, maximal nytta
Det första alternativet är kompakt, bara 10 rader. Det löser exakt ett problem: att mjukt scrolla till ett ankare när användaren kommer från en annan sida eller via en direktlänk med en hash.
1 jQuery(document).ready(function ($) { 2 var myHash = location.hash; // save the hash 3 location.hash = ''; // clear it — browser stops jerking 4 if (myHash[1] != undefined) { // hash not empty? 5 $('html, body').animate( 6 { scrollTop: $(myHash).offset().top - 110 }, 7 700 // duration in milliseconds 8 ); 9 location.hash = myHash; // restore the hash 10 } 11 });
Steg-för-steg-genomgång, för tre rader gör magi, men att förstå mekaniken är viktigt:
var myHash = location.hash: läs hashen från adressfältet (till exempel#pricing). Vid det här laget har webbläsaren inte scrollat än.location.hash = '': det avgörande tricket. Genom att rensa hashen tappar webbläsaren sitt mål för det omedelbara hoppet. Utan den här raden skulle skriptet "slåss" mot webbläsarens inbyggda beteende och förlora.$(myHash).offset().top - 110: beräkna ankarets position från dokumentets topp och subtrahera 110 pixlar. Detta är din offset för en fast header. Om din header ärposition: fixedoch 80px hög, använd 80 (eller 90 för lite andrum). Om det inte finns någon header, ta bort subtraktionen helt.$('html, body').animate(...): scrolla mjukt under 700 millisekunder. Selektor'html, body'är inte ett infall: olika webbläsare scrollar antingenhtmlellerbody, så vi anger båda för tillförlitlighet.location.hash = myHash: återställ hashen. Nu visar adressfältet#pricingigen, och sidan är redan snyggt parkerad vid målblocket.
Infoga skriptet i ditt temas functions.php, en anpassad JS-fil eller via ett tillägg som Code Snippets. Det viktigaste kravet är att det måste ligga inuti ett jQuery(document).ready()-block.
Avancerad version: klickhantering, sidladdning och konfliktskydd
Det grundläggande skriptet täcker de flesta scenarier, men ibland fungerar inte location.hash = '' i tid: webbläsaren hoppar innan hashen rensas. I de fallen, använd den andra versionen. Den är tyngre men mer tillförlitlig.
1 jQuery(document).ready(function () { 2 jQuery(window).bind('load', function () { 3 jQuery('a:not(.spu-clickable)[href*="#"]:not([href="#"])').click(function () { 4 if ( 5 location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') || 6 location.hostname == this.hostname 7 ) { 8 var target = jQuery(this.hash); 9 target = target.length ? target : jQuery('[name=' + this.hash.slice(1) + ']'); 10 if (target.length) { 11 jQuery('html, body').animate( 12 { scrollTop: target.offset().top - 37 }, 13 1000 14 ); 15 return false; 16 } 17 } 18 }); 19 }); 20 }); 21 22 jQuery(window).load(function () { 23 function goToByScroll(id) { 24 jQuery('html, body').animate( 25 { scrollTop: jQuery('#' + id).offset().top - 38 }, 26 1000 27 ); 28 } 29 if (window.location.hash != '') { 30 goToByScroll(window.location.hash.substr(1)); 31 } 32 });
Här är vad som händer, block för block:
Block ett: en klickhanterare för interna ankarlänkar. jQuery(window).bind('load', ...) säkerställer att alla sidelement (inklusive bilder och iframes) är laddade innan hanteraren binds. Filtret a:not(.spu-clickable) exkluderar länkar som redan hanteras av ett popup-tillägg (SPU, WordPress PopUp), vilket förhindrar animeringskonflikter. Lägg till dina egna exkluderingsklasser enligt samma mönster.
Block två: hantering av navigering från en extern sida. jQuery(window).load() körs senare än document.ready och garanterar att alla element, inklusive ankaret, finns i DOM:en. Funktionen goToByScroll(id) gör exakt vad det grundläggande skriptet gör, men anropas först efter att fönstret har laddats helt. substr(1) tar bort #-tecknet från hashen.
Viktig notering: jQuery(window).load() har varit föråldrad sedan jQuery 3.0. Om ditt projekt använder en aktuell jQuery-version, ersätt den med:
1 jQuery(window).on('load', function () { 2 // code here 3 });
Syntaxen skiljer sig, men beteendet är identiskt.
Finjustering: offset, selektorer och fallgropar
Skriptet fungerar, men varje layout är unik. Här är tre vanliga justeringar som räddade skarpa projekt.
Problem ett: offset().top returnerar felaktiga koordinater. Detta händer när föräldraelement har CSS-egenskaperna transform, filter eller will-change, vilket skapar en ny positioneringskontext. offset() beräknar då relativt till den kontexten istället för dokumentet. Lösning: använd offset({top: -0}):
1 jQuery('html, body').animate( 2 { scrollTop: jQuery('#' + id).offset({ top: -0 }).top }, 3 1000 4 );
Parametern {top: -0} tvingar jQuery att räkna om positionen från dokumentets gränser och ignorerar mellanliggande kontexter. Det ser ut som magi, men det fungerar.
Problem två: selektorn 'html, body' scrollar fel element. I vissa teman är scrollbehållaren inte html eller body utan ett specifikt block, till exempel body.home för hemsidan eller .main-content för inre sidor. Identifiera din behållare via DevTools (fliken Elements → sök efter overflow: scroll eller overflow: auto) och ersätt den i selektorn:
1 jQuery('body.home').animate( 2 { scrollTop: target.offset().top - 37 }, 3 1000 4 );
Problem tre: hashen innehåller kyrilliska tecken eller specialtecken. location.hash returnerar en URL-kodad sekvens istället för en läsbar sträng, och jQuery-selektorn $(myHash) hittar inte elementet. Lösning: avkoda hashen med decodeURIComponent() innan du använder den i selektorn.
Video: liveexempel på scrollning från en extern länk
En kort demo från John Smith: mjuk ankarlänksscrollning via jQuery animate() på en riktig sida med fast header och extern navigering.
⁉️🤔 Vanliga frågor
Skriptet fungerar på samma sida men inte vid navigering från en annan URL. Varför?
För att
click-hanteraren aldrig aktiveras: det fanns inget klick. Användaren följde en direktlänk, och webbläsaren bearbetade hashen innan din JS kördes. Lösningen är sekvensenlocation.hash = ''+animate()+location.hash = myHash. Att rensa hashen avbryter det inbyggda hoppet, animeringen scrollar mjukt, och att återställa hashen bevarar den korrekta URL:en i adressfältet.
Vilken offset ska jag använda för en fast header?
Exakt headerhöjd plus några pixlars andrum. Öppna DevTools (F12), välj din sajts
header-element och kontrollera dessheighti fliken Computed. Om headern till exempel är 80px, använd 90 i din kod. Om mobilversionen har en annan headerhöjd, lägg till en media query med en dynamisk offsetberäkning.
Är jQuery fortfarande relevant 2026?
Ja, särskilt inom WordPress-ekosystemet. jQuery finns kvar i WP:s kärna, många tillägg och teman är beroende av det, och att migrera hela ekosystemet till ren JS kommer att ta år. För nya projekt i vanlig JavaScript görs mjuk scrollning via
element.scrollIntoView({ behavior: 'smooth' })ellerscroll-behavior: smoothi CSS, med betydligt färre kodrader. Men om du modifierar en befintlig WP-sajt är jQuery-lösningen fortfarande pålitlig och lämplig.
Kan jag undvika jQuery helt?
Det kan och bör du, om projektet är nytt. Den inbyggda motsvarigheten till det grundläggande skriptet:
1 document.addEventListener('DOMContentLoaded', () => { 2 const hash = window.location.hash; 3 if (hash) { 4 window.location.hash = ''; 5 const target = document.querySelector(hash); 6 if (target) { 7 window.scrollTo({ 8 top: target.getBoundingClientRect().top + window.pageYOffset - 110, 9 behavior: 'smooth' 10 }); 11 } 12 window.location.hash = hash; 13 } 14 });
Samma princip: spara hashen, rensa den, scrolla, återställ den. Skillnaden är att
behavior: 'smooth'använder webbläsarens inbyggda CSS-motor snarare än en jQuery-timer. Du kan inte konfigurera hastigheten, men koden är 30 KB lättare (vikten av jQuery).
Varför $('html, body') istället för bara $('html')?
Firefox scrollar
html, Chrome använderbody, och Safari beror på versionen. Att ange båda selektorerna ianimate()garanterar att det fungerar i alla webbläsare: jQuery skickar animeringen till det element som faktiskt tillämpar den.
Är jQuery värt att använda bara för mjuk scrollning 2026
Om du har en WordPress-sajt eller ett äldre projekt där jQuery redan är laddat, ta skriptet från den här artikeln och överkomplicera inte saker. Tio rader kod som fungerar överallt, i alla webbläsare, utan polyfills. För nya byggen i ren JavaScript, använd inbyggd scroll-behavior: smooth eller scrollIntoView(). Båda tillvägagångssätten producerar mjuk scrollning, men jQuery-metoden ger dig kontroll över hastighet, offset och scrollbehållarens selektor. Inbyggda implementationer kräver separata kontroller för att uppnå samma sak.
Huvudregeln vi har lärt oss från dussintals projekt: rensa alltid hashen innan scrollning. Utan det tricket kan ingen hanterare besegra webbläsarens inbyggda beteende, och användare kommer fortsätta att uppleva abrupta hopp.



