30/09/2023
iOS Momentum Scrolling: En Dybdegående Guide til Udviklere
Momentum scrolling, også kendt som "flydende scrolling", er en standardfunktion på iOS-enheder, der giver en glidende og intuitiv scrolleoplevelse. Når du bruger visse CSS-egenskaber som overflow: scroll på elementer med en fast højde og bredde, dukker scrollbars op, som tillader brugerne at navigere gennem skjult indhold. På iOS-enheder er denne funktion dog ofte deaktiveret som standard for websider med scrollbars. Denne artikel dykker ned i, hvordan du kan aktivere og styre momentum scrolling på iOS-enheder, herunder håndtering af komplekse scenarier som nested containere og undgåelse af uønsket baggrunds-scrolling.

Grundlæggende Aktivering af Momentum Scrolling
Den mest basale måde at aktivere momentum scrolling på i iOS-enheder er ved at tilføje en simpel CSS-regel til dit scrollbare element. Dette er især nyttigt, hvis du oplever, at din standard scrolling føles hakkende eller ufleksibel på mobile Safari-browsere.
Her er den essentielle CSS-kode, du skal bruge:
.scrollable-element { width: 300px; height: 200px; overflow-y: scroll; /* Vigtigt: Skal være 'scroll', ikke 'auto' */ -webkit-overflow-scrolling: touch; /* Aktiverer momentum scrolling på WebKit-browsere */ } Ved at tilføje -webkit-overflow-scrolling: touch; til det element, du ønsker at anvende momentum scrolling på, fortæller du browseren, at den skal bruge den native, hardware-accelererede scrolle-mekanisme på iOS. Dette resulterer i en markant mere flydende og responsiv scrolleoplevelse for brugerne.
Udfordringen med Nested Scrollable Containere
En af de mest frustrerende udfordringer for udviklere, der arbejder med scrollbare elementer på iOS, opstår, når man har flere scrollbare containere indlejret i hinanden. I sådanne scenarier kan scrolling i et indre element utilsigtet udløse scrolling i et ydre element eller endda i selve baggrunden, hvilket skaber en kaotisk brugeroplevelse. Dette problem er ikke begrænset til Safari på mobilen, men gælder for alle iOS-browsere.
Heldigvis er der udviklet strategier til at håndtere dette. Processen kan opdeles i flere niveauer:
Niveau 1: Forhindring af baggrunds-scrolling i de fleste browsere
Før vi dykker ned i iOS-specifikke løsninger, er det godt at have en generel strategi for at forhindre baggrunds-scrolling. To almindelige CSS-metoder kan anvendes:
- CSS-klasse med
overflow: hidden;.is-scrollLocked { overflow: hidden; }Denne metode tilføjer klassen
.is-scrollLockedtil et element (typiskbody) for at deaktivere scrolling i det pågældende element. - CSS-klasse med
position: fixed;.is-scrollLocked { position: fixed; top: 0; left: 0; right: 0; bottom: 0; }Denne metode låser elementet fast på skærmen og forhindrer scrolling. Igen tilføjes klassen typisk til
bodyelementet ved hjælp af JavaScript, f.eks.:document.body.classList.add('is-scrollLocked');.
Niveau 2: Aktivering af iOS Momentum Scrolling i Nested Containere
Som nævnt tidligere er -webkit-overflow-scrolling: touch; nøglen til at aktivere momentum scrolling. Denne CSS-regel kan anvendes på ethvert scrollbart element, herunder den indlejrede container.
.nested-scrollable { -webkit-overflow-scrolling: touch; } Du kan anvende denne klasse på dine indlejrede scrollbare elementer for at sikre, at de drager fordel af den flydende scrolling.
Niveau 3: Forhindring af baggrunds-scrolling specifikt på iOS Mobile
Den CSS-løsning fra Niveau 1 er ikke altid tilstrækkelig på iOS mobile enheder, især når det kommer til nested scrollable elementer. Her bliver JavaScript nødvendigt for at håndtere touchmove-events korrekt.
Du skal forhindre, at touchmove-events bobler op og udløser utilsigtet scrolling. Dette gøres ved at tilføje en event listener til window med parameteren { passive: false }. Denne parameter er afgørende, da den signalerer til browseren, at event listeneren potentielt kan kalde preventDefault().
const preventDefaultHandler = e => e.preventDefault(); // Når du aktiverer scrolling-blokering window.addEventListener('touchmove', preventDefaultHandler, { passive: false }); // Husk at fjerne listeneren, når den ikke længere er nødvendig // window.removeEventListener('touchmove', preventDefaultHandler); Ved at bruge passive: false kan du effektivt blokere scrolling, når det er nødvendigt, og dermed forhindre baggrundselementer i at blive scrollet.
Niveau 4: Aktivering af Momentum Scrolling uden Uønsket Baggrunds-scrolling (Bounce Effect)
Et kendt fænomen på iOS er "bounce"-effekten. Når du forsøger at scrolle forbi toppen eller bunden af et scrollbart område, bliver hele siden trukket væk og hopper derefter tilbage til kanten. Denne animation udløser en scroll-event på dokumentniveau, uanset hvor den oprindeligt stammer fra, og kan ikke forhindres med standardmetoder.

Dette kan føre til "uønsket scrolling", hvor scrolling inde i et modalvindue eksempelvis får baggrundslisten til også at scrolle. Løsningen er at forhindre denne bounce-effekt helt.
Metoden involverer at forhindre scrollingen i at nå det absolut første eller sidste pixel af scroll-højden. Dette skal ske, førtouchmove-events får mulighed for at boble op, hvilket betyder, at vi skal lytte til touchstart-events.
function preventBounce(element) { const { scrollTop, offsetHeight, scrollHeight } = element; // Hvis vi er ved toppen, skub 1 pixel ned if (scrollTop <= 0) { element.scrollTo(0, 1); return; } // Hvis vi er ved bunden, skub 1 pixel op if (scrollTop + offsetHeight >= scrollHeight) { element.scrollTo(0, scrollHeight - offsetHeight - 1); } } // Ved rendering af elementet: // element.addEventListener('touchstart', () => preventBounce(element)); // Ved fjernelse af elementet: // element.removeEventListener('touchstart', () => preventBounce(element)); Ved at implementere denne funktion på touchstart-events for dine scrollbare elementer, kan du effektivt eliminere bounce-effekten og forhindre uønsket baggrunds-scrolling.
Niveau 5: Centraliseret Scroll Management med React Context
For mere komplekse layouts, hvor du har mange scrollbare og ikke-scrollbare elementer, kan det være fordelagtigt at centralisere scroll-styringen. Hvis du bruger React, er Context API en ideel løsning.
Idéen er at have en enkelt kontekst, der holder styr på, hvilke elementer der må scrolle, og hvilke der skal have deres scrolling blokeret. Dette gøres ved at registrere alle scrollbare og ikke-scrollbare elementer ét sted og binde en enkelt event listener til at håndtere touchmove.
Komponenter og Context
IosMobileScrollContext: En React Context til at administrere scroll-tilstand.IosMobileScrollContextProvider: Provider-komponenten, der omslutter applikationen og indeholder logikken til at registrere elementer.- Binder en global
touchmoveevent listener medpassive: false. - Tjekker, om et touch-event sker inden for et scrollbart eller ikke-scrollbart element.
- Kalder
preventDefault()ogstopPropagation()for ikke-scrollbare elementer, der ikke må udløse baggrunds-scrolling.
- Binder en global
NestedDiv: En komponent, der registrerer et element som "ikke-scrollbart" i konteksten.NestedScrollableDiv: En komponent, der registrerer et element som "scrollbart" og implementererpreventBounce-logikken fortouchstart-events.
Denne centraliserede tilgang sikrer en mere robust og vedligeholdelsesvenlig løsning til styring af scrolling på tværs af komplekse iOS-applikationer.
Niveau 6: Begrænset Browserområde i iOS Safari
En særlig udfordring ved Safari på iOS er et "begrænset browserområde" (ca. 44px højt) nederst på skærmen. Dette område er ankeret til bunden, og touchmove-events i dette område kan udløse en dokument-scrolling, som ikke kan kontrolleres via DOM.
Dette betyder, at selv med de tidligere nævnte løsninger, kan baggrunden stadig scrolle, hvis brugeren scroller meget tæt på bunden af skærmen.
Den eneste kendte workaround for dette problem involverer at gemme den aktuelle scrollposition, når et nyt scrollbart element åbnes. Når der sker en dokument-scroll, sammenlignes den aktuelle baggrunds-scrollposition med den gemte. Hvis de afviger, gendannes den tidligere gemte position.
Dette er en mere avanceret teknik, der kræver omhyggelig implementering for at undgå uønskede sideeffekter.
Opsummering og Nøglebudskaber
At mestre momentum scrolling på iOS kræver en forståelse af både CSS og JavaScript, især når man håndterer komplekse layouts med indlejrede elementer. De vigtigste punkter at huske er:
- Brug
-webkit-overflow-scrolling: touch;for at aktivere den native momentum scrolling. - Vær opmærksom på
touchmove-events og brug{ passive: false }, når du skal forhindre baggrunds-scrolling. - Implementer
preventBounce-logikken for at undgå uønsket scrolling ved kanten af scrollbare områder. - Overvej en centraliseret løsning som React Context for komplekse applikationer.
- Vær opmærksom på iOS Safaris begrænsede browserområde og den potentielle baggrunds-scrolling, der følger med.
Ved at følge disse retningslinjer kan du skabe en ensartet og positiv scrolleoplevelse for dine brugere på tværs af alle iOS-enheder.
Ofte Stillede Spørgsmål (FAQ)
- Hvad er momentum scrolling?
- Momentum scrolling er en funktion på touch-enheder, der giver en glidende og fortsat scrolling, selv efter at brugeren har fjernet fingeren fra skærmen.
- Hvordan aktiverer jeg momentum scrolling på iOS?
- Tilføj
-webkit-overflow-scrolling: touch;til dit scrollbare element i CSS. - Hvorfor scroller min baggrund, når jeg scroller i et modalvindue på iOS?
- Dette skyldes sandsynligvis "bounce"-effekten eller at
touchmove-events bobler op. BrugpreventBounce-logikken og/eller en centraliserettouchmove-handler for at forhindre dette. - Kan jeg deaktivere momentum scrolling på iOS?
- Ja, ved simpelthen at fjerne
-webkit-overflow-scrolling: touch;fra dit CSS. Standard scrolling-adfærd vil da gælde. - Hvad er problemet med det begrænsede browserområde i Safari?
- Det er et 44px højt område nederst på skærmen, hvor scrolling kan udløse baggrunds-scrolling, som er sværere at kontrollere direkte via DOM.
Hvis du vil læse andre artikler, der ligner iOS Scrollbar: Få styr på momentum scrolling, kan du besøge kategorien Mobil.
