Hoppa till innehållet

Animation

en förändring i en sidas utseende som spelas upp över tid

Vad det är

På webben är en animation oftast en CSS-animation: en namngiven följd av nyckelbilder (keyframes) som skrivs en gång i en @keyframes-regel och kopplas till ett element genom egenskaperna animation. W3C:s specifikation CSS Animations Level 1 beskriver mekanismen som ett sätt att animera värdena hos egenskaper i CSS över tid med hjälp av nyckelbilder. Animerade bilder, video och ritning på en canvas rör sig också, men den här artikeln följer den deklarativa sorten.

Varje nyckelbild anger egenskapernas värden vid en punkt i förloppet: from eller 0% i början, to eller 100% i slutet och valfria procenttal däremellan. Webbläsaren räknar fram värdena mellan dem. De övriga animationsegenskaperna styr hur länge ett varv varar, hur många gånger det upprepas, om vartannat varv spelas baklänges och om animationen körs eller är pausad. Antalet infinite betyder, med specifikationens ord, att animationen upprepas för evigt. animation-fill-mode avgör vad som syns utanför förloppet: med none har animationen ingen verkan då, backwards tillämpar den första nyckelbilden under en eventuell fördröjning, och forwards behåller värdena som den slutade på.

En övergång (transition) är den nära släktingen. Där ett ändrat egenskapsvärde annars skulle synas direkt sprider CSS Transitions ut ändringen över en angiven tid. CSS Animations drar gränsen mellan de två: övergångar utlöses underförstått när ett egenskapsvärde ändras, medan animationer körs uttryckligen när animationsegenskaperna tillämpas. En länk som tonar sin färg när pekaren hålls över den är en övergång. En laddningssnurra som snurrar vare sig något har ändrats eller inte är en animation.

En nyare specifikation, Scroll-driven Animations, byter ut klockan mot själva sidan. En animation som är kopplad till en tidslinje för rullningsförlopp (scroll progress timeline) går framåt när en rullningsbehållare rullas, från 0 % i början av det rullbara intervallet till 100 % i slutet. När de två lägena sammanfaller, eftersom det inte finns något att rulla, kallar specifikationen tidslinjen inaktiv.

Varför det spelar roll

Rörelse drar till sig uppmärksamhet, och det är både skälet att använda den och problemet med den.

För en del läsare är den fysiskt obehaglig. Förklaringsdokumentet (Understanding) till framgångskriteriet 2.3.3 i WCAG 2.2 beskriver hur element som rör sig när en sida rullas kan utlösa reaktioner hos personer med vestibulära störningar, alltså besvär från balansorganet i innerörat: yrsel, illamående och huvudvärk. Dokumentet nämner parallaxrullning, där bakgrunden rör sig i en annan takt än förgrunden, som en animation som ofta inte är nödvändig, och påpekar att besvären kan bli så svåra att den drabbade behöver sängvila för att återhämta sig.

Läsaren kan säga ifrån, och sidan kan fråga. Media Queries Level 5 definierar prefers-reduced-motion, en mediefunktion med två värden. reduce betyder att läsaren har bett systemet om ett gränssnitt som tar bort eller ersätter de typer av rörelsebaserad animation som orsakar obehag för personer med vestibulär rörelsekänslighet eller distraherar personer med uppmärksamhetsstörningar. no-preference betyder att ingen preferens är känd, och värdet räknas som falskt när funktionen testas ensam.

Två framgångskriterier täcker det. 2.2.2 Pause, Stop, Hide, på nivå A, gäller innehåll som rör sig, blinkar eller rullar, som startar automatiskt, varar längre än fem sekunder och visas tillsammans med annat innehåll: läsaren behöver ett sätt att pausa, stoppa eller dölja det, om inte rörelsen är nödvändig. Kriteriet gäller allt på sidan, och en animation som stannar bara medan fokus vilar på den räknas inte som en paus. 2.3.3 Animation from Interactions, på nivå AAA, kräver att rörelseanimation som utlöses av en interaktion går att stänga av, om den inte är nödvändig. Förklaringsdokumentet nämner webbläsarens eller operativsystemets inställning för minskad rörelse som ett sätt att uppfylla kriteriet.

Rörelse är en snävare kategori än förändring. WCAG definierar rörelseanimation som steg som läggs till mellan två tillstånd för att skapa en illusion av rörelse eller en känsla av mjuk övergång. Ett element som glider på plats eller ändrar storlek när det visas är animerat. Ett som dyker upp direkt är det inte. En ändring av färg eller opacitet som lämnar elementets upplevda storlek, form och läge i fred faller utanför definitionen, och därför betyder minskad rörelse inte att varje toning ska frysas.

Så ser det ut i praktiken

Den tydligaste lärdomen börjar med en regel som såg färdig ut. Webbplatsen respekterade inställningen för minskad rörelse med en enda universell regel som stängde av alla övergångar. Den såg fullständig ut och passerade lintern, men under en emulerad inställning animerades fortfarande elva selektorer. Arbetet som gjorde inställningen för minskad rörelse ärlig spårade orsaken till specificitet: en universell selektor förlorar mot varje regel som bär en klass, och det är varje genomtänkt animation på sidan. Allt som rör sig ligger nu i en del av stilmallen som kommer sent, och en linter underkänner en transform med övergång var som helst annars. Gränsen som regeln drar är minska rörelse, inte färg, så en färgtoning godkänns och en övergång på rörelse gör det inte. Rörelse uttrycks också som en övergång snarare än som en keyframe-animation, eftersom den förra är trivial att avbryta och den senare inte är det. Som sidan uttrycker det: en regel som förlorar på specificitet fallerar i tysthet.

Rullningsstyrd rörelse har ett eget felläge. Bland de 11 tillgänglighetsbrister som webbläsaren rapporterade som felfria fanns en rullningsstyrd animation, inaktiv på en sida som var för kort för att rullas, som permanent hade skurit bort sidfoten på tre sidor. Webbplatsen klarade sina automatiska tillgänglighetsregler ändå, eftersom felet låg i hur sidan renderades och inte i vad uppmärkningen sade.

En linter kan göra kontrollen omöjlig att hoppa över. Ett designsystem med fyrtioåtta tokens, byggt på plattformens eget glasmaterial, har rörelse som en av sina sex grupper av tokens, och dess lintverktyg avvisar en animation som deklareras utan att respektera inställningen för minskad rörelse. Sidan anger skälet: en animation läggs till i ett ögonblick av finputsning, kontrollen av inställningen är den del som hoppas över, och därför gör regeln det omöjligt att skriva animationen utan den.

Den här webbplatsens stilmallar visar samma vanor på andra ställen. De två kugghjulen i sidhuvudet snurrar ett varv på 60 respektive 96 sekunder, och båda får animation: none under reduce. Deras rullningskopplade parallax är spärrad två gånger, inuti prefers-reduced-motion: no-preference och inuti ett @supports-test för animation-timeline: scroll(). I en webbläsare som saknar funktionen står kugghjulen kvar där de är, och kommentaren i koden kallar den reservlösningen för själva designen. I sidfoten får rutan med upphovsrätten sitt dolda läge från animationens bakåtfyllnad (backwards) i stället för från en deklarerad opacity: 0. Kommentaren förklarar varför: en inaktiv tidslinje tillämpar ingenting alls, och den gamla opacity: 0 hade dolt upphovsrätten på varje kort sida.

Var det går fel

  • Avstängningen förlorar kaskaden. En generell transition: none på den universella selektorn har nästan ingen specificitet, så varje regel med en klass fortsätter att röra sig, och ingenting rapporterar det. Ett block som placeras efter reglerna det måste slå, och som namnger de rörliga selektorerna, låter det stilla läget vinna.
  • Inställningen läggs till senare, eller aldrig. En animation i grundstilen rör sig för alla tills någon kommer ihåg att stänga av den. Den som deklarerar animationen inuti @media (prefers-reduced-motion: no-preference) gör stillhet till standardläget.
  • En rullningstidslinje möter en sida där det inte finns något att rulla. Tidslinjen är inaktiv och animationen gör ingenting, så ett startläge som skrivits in i grundstilen, t.ex. en opacity: 0 som väntar på att animeras bort, ligger kvar. Ett startläge som kommer från bakåtfyllnaden försvinner tillsammans med animationen.
  • Ett värde som webbläsaren avvisar i en nyckelbild faller bort i tysthet. Specifikationen säger att en egenskap som anges men är ogiltig i en nyckelbild animeras som om den nyckelbilden inte fanns. Ett felstavat värde hoppar över ett steg utan något felmeddelande.
  • En dekorativ loop snurrar utan något sätt att stoppa den. En infinite-animation som startar när sidan laddas, bredvid texten, faller under 2.2.2 så fort den passerar fem sekunder. En pausknapp, eller ett slut inom fem sekunder, uppfyller kriteriet.
  • ”Minska” läses som ”ta bort allt”. Den som stryker varje tillståndsändring kan ta bort information tillsammans med rörelsen. Att visa det nya läget direkt, eller med en toning, behåller informationen och tar bort rörelsen.

Läs mer

Ordlista