Föreställ dig detta: du går med i ett nytt projekt, dyker in i kodbasen och inom de första timmarna upptäcker du något frustrerande bekant. Utspridda i stilmallarna hittar du flera @keyframes-definitioner för samma grundläggande animationer. Tre olika tona-in-effekter, två eller tre bildvarianter, en handfull zoomanimationer och minst två olika snurranimationer för, ja, varför inte? @keyframes puls { från { skala: 1; } till { skala: 1,1; } }
@keyframes bigger-pulse { 0 %, 20 %, 100 % { skala: 1; } 10 %, 40 % { skala: 1,2; } }
Om det här scenariot låter bekant är du inte ensam. Enligt min erfarenhet från olika projekt är en av de mest konsekventa snabba vinsterna jag kan leverera att konsolidera och standardisera nyckelbildrutor. Det har blivit ett så tillförlitligt mönster att jag nu ser fram emot den här rensningen som en av mina första uppgifter på någon ny kodbas. Logiken bakom kaoset Denna redundans är helt vettig när du tänker på det. Vi använder alla samma grundläggande animationer i vårt dagliga arbete: tonar, diabilder, zoomar, snurrar och andra vanliga effekter. Dessa animationer är ganska enkla, och det är lätt att skapa en snabb @keyframes-definition för att få jobbet gjort. Utan ett centraliserat animationssystem skriver utvecklare naturligtvis dessa nyckelbildrutor från början, omedvetna om att liknande animationer redan finns på andra ställen i kodbasen. Detta är särskilt vanligt när man arbetar i komponentbaserade arkitekturer (vilket de flesta av oss gör nuförtiden), eftersom team ofta arbetar parallellt över olika delar av applikationen. Resultatet? Animationskaos. Det lilla problemet De mest uppenbara problemen med duplicering av nyckelbildrutor är bortkastad utvecklingstid och onödig koduppsvällning. Flera nyckelbildsdefinitioner innebär flera ställen att uppdatera när kraven ändras. Behöver du justera tidpunkten för din toningsanimering? Du måste leta efter varje instans i din kodbas. Vill du standardisera lättnadsfunktioner? Lycka till med att hitta alla varianter. Denna multiplikation av underhållspunkter gör även enkla animeringsuppdateringar till en tidskrävande uppgift. Det större problemet Denna duplicering av nyckelbildrutor skapar ett mycket mer lömskt problem som lurar under ytan: den globala räckviddsfällan. Även när man arbetar med komponentbaserade arkitekturer, definieras CSS-nyckelramar alltid i det globala omfånget. Detta innebär att alla nyckelbilder gäller för alla komponenter. Alltid. Ja, din animering använder inte nödvändigtvis de nyckelrutor som du definierade i din komponent. Den använder de sista nyckelbildrutorna som matchar exakt samma namn som laddades in i det globala omfånget. Så länge alla dina nyckelbildrutor är identiska kan detta verka som ett mindre problem. Men i det ögonblick du vill anpassa en animation för ett specifikt användningsfall har du problem, eller ännu värre, du kommer att vara den som orsakar dem. Antingen kommer din animation inte att fungera eftersom en annan komponent som laddas efter din, skriver över dina nyckelbildrutor, eller så läses din komponent in sist och av misstag ändrar animationsbeteendet för alla andra komponenter som använder den nyckelbildrutans namn, och du kanske inte ens inser det. Här är ett enkelt exempel som visar problemet: .component-one { /* komponentstilar */ animation: puls 1s ease-in-out oändlig alternativ; }
/* denna @keyframes definition kommer inte att fungera */ @keyframes puls { från { skala: 1; } till { skala: 1,1; } }
/* senare i koden... */
.component-two { /* komponentstilar */ animation: puls 1s ease-in-out oändlig; }
/* denna nyckelbild kommer att gälla för båda komponenterna */ @keyframes puls { 0 %, 20 %, 100 % { skala: 1; } 10 %, 40 % { skala: 1,2; } }
Båda komponenterna använder samma animationsnamn, men den andra @keyframes-definitionen skriver över den första. Nu kommer både komponent-ett och komponent-två att använda de andra nyckelbildrutorna, oavsett vilken komponent som definierade vilka nyckelbildrutor. Se Pen Keyframes Tokens - Demo 1 [forked] av Amit Sheen. Den värsta delen? Detta fungerar ofta perfekt i lokal utveckling men bryter mystiskt i produktionen när byggprocesser ändrar laddningsordningen för dina stilmallar. Du får animationer som beter sig olika beroende på vilka komponenter som laddas och i vilken sekvens. Lösningen: Unified Keyframes Svaret på detta kaos är förvånansvärt enkelt: fördefinierade dynamiska nyckelrutor lagrade i en delad stilmall. Istället för att låta varje komponent definiera sina egna animationer skapar vi centraliserade nyckelbildrutor som är väldokumenterade, lätta attkan användas, underhållas och skräddarsys för ditt projekts specifika behov. Se det som keyframes-tokens. Precis som vi använder tokens för färger och mellanrum, och många av oss redan använder tokens för animeringsegenskaper, som varaktighet och easing-funktioner, varför inte använda tokens för keyframes också? Det här tillvägagångssättet kan integreras naturligt med alla aktuella designtokenarbetsflöden du använder, samtidigt som du löser både det lilla problemet (kodduplicering) och det större problemet (konflikter med global omfattning) på en gång. Tanken är okomplicerad: skapa en enda källa till sanning för alla våra vanliga animationer. Detta delade formatmall innehåller noggrant utformade nyckelrutor som täcker de animationsmönster som vårt projekt faktiskt använder. Sluta gissa om en toningsanimation redan finns någonstans i vår kodbas. Inga fler av misstag skriver över animationer från andra komponenter. Men här är nyckeln: det här är inte bara statiska copy-paste-animationer. De är designade för att vara dynamiska och anpassningsbara genom anpassade CSS-egenskaper, vilket gör att vi kan bibehålla konsistens samtidigt som vi har flexibiliteten att anpassa animationer till specifika användningsfall, som om du behöver en lite större "puls"-animation på ett ställe. Bygger det första nyckelbildspelet En av de första lågt hängande frukterna vi bör ta itu med är "fade-in"-animationen. I ett av mina senaste projekt hittade jag över ett dussin separata intoningsdefinitioner, och ja, alla animerade helt enkelt opaciteten från 0 till 1. Så låt oss skapa en ny stilmall, kalla den kf-tokens.css, importera den till vårt projekt och placera våra nyckelrutor med korrekta kommentarer inuti den. /* keyframes-tokens.css */
/* * Tona in - tona ingångsanimation * Användning: animation: kf-fade-in 0.3s lätta-out; */ @keyframes kf-fade-in { från { opacitet: 0; } till { opacitet: 1; } }
Denna enda @keyframes-deklaration ersätter alla de spridda intonade animationerna över vår kodbas. Ren, enkel och globalt användbar. Och nu när vi har denna token definierad kan vi använda den från vilken komponent som helst under hela vårt projekt: .modal { animation: kf-fade-in 0,3s lättnadsutlösning; }
.tooltip { animation: kf-fade-in 0,2s lätt-in-ut; }
.notification { animation: kf-fade-in 0,5s ease-out; }
Se Pen Keyframes Tokens - Demo 2 [forked] av Amit Sheen. Obs: Vi använder ett kf-prefix i alla våra @keyframes-namn. Detta prefix fungerar som ett namnutrymme som förhindrar namnkonflikter med befintliga animationer i projektet och gör det omedelbart klart att dessa nyckelbildrutor kommer från vår nyckelbildrute-token-fil. Göra en dynamisk bild Kf-fade-in-nyckelbilderna fungerar utmärkt eftersom det är enkelt och det finns lite utrymme att röra till saker och ting. I andra animationer måste vi dock vara mycket mer dynamiska, och här kan vi utnyttja den enorma kraften hos anpassade CSS-egenskaper. Det är här keyframes-tokens verkligen lyser jämfört med spridda statiska animationer. Låt oss ta ett vanligt scenario: "slide-in"-animationer. Men varifrån glida in? 100px från höger? 50% från vänster? Ska det komma in från toppen av skärmen? Eller kanske flyta in från botten? Så många möjligheter, men istället för att skapa separata nyckelbildrutor för varje riktning och varje variant, kan vi bygga en flexibel token som anpassar sig till alla scenarier: /* * Skjut in - riktad bildanimering * Använd --kf-slide-from för att styra riktningen * Standard: glider in från vänster (-100%) *Användning: * animation: kf-slide-in 0,3s lättnader; * --kf-slide-from: -100px 0; // skjut från vänster * --kf-slide-from: 100px 0; // glida från höger * --kf-slide-from: 0 -50px; // glida uppifrån */
@keyframes kf-slide-in { från { översätt: var(--kf-slide-from, -100% 0); } till { översätt: 0 0; } }
Nu kan vi använda denna enda @keyframes-token för vilken bildriktning som helst genom att helt enkelt ändra --kf-slide-from anpassad egenskap: .sidebar { animation: kf-slide-in 0,3s lättnader; /* Använder standardvärde: glider från vänster */ }
.notification { animation: kf-slide-in 0,4s lättnader; --kf-slide-from: 0 -50px; /* skjut uppifrån */ }
.modal { animation: kf-fade-in 0,5s, kf-slide-in 0,5s cubic-bezier(0,34, 1,56, 0,64, 1); --kf-slide-from: 50px 50px; /* glida från nedre höger */ }
Detta tillvägagångssätt ger oss otrolig flexibilitet samtidigt som vi behåller konsekvens. En nyckelbildsdeklaration, oändliga möjligheter. Se Pen Keyframes Tokens - Demo 3 [forked] av Amit Sheen. Och om vi vill göra våra animationer ännu mer flexibla och även möjliggöra "utskjutande" effekter, kan vilägg helt enkelt till en --kf-slide-to anpassad egenskap, liknande vad vi kommer att se i nästa avsnitt. Dubbelriktad zoom nyckelbildrutor En annan vanlig animation som dupliceras över projekt är "zoom"-effekter. Oavsett om det är en subtil uppskalning för toastmeddelanden, en dramatisk inzoomning för modaler eller en mild nedskalningseffekt för rubriker, finns zoomanimationer överallt. Istället för att skapa separata nyckelrutor för varje skalvärde, låt oss bygga en flexibel uppsättning kf-zoom-nyckelrutor:
/* * Zoom - skala animering * Använd --kf-zoom-from och --kf-zoom-to för att styra skalvärden * Standard: zoomar från 80 % till 100 % (0,8 till 1) *Användning: * animation: kf-zoom 0,2s lättnader; * --kf-zoom-från: 0,5; --kf-zoom-to: 1; // zooma från 50 % till 100 % * --kf-zoom-från: 1; --kf-zoom-to: 0; // zooma från 100 % till 0 % * --kf-zoom-från: 1; --kf-zoom-to: 1.1; // zooma från 100 % till 110 % */
@keyframes kf-zoom { från { skala: var(--kf-zoom-från, 0,8); } till { skala: var(--kf-zoom-to, 1); } }
Med en definition kan vi uppnå vilken zoomvariation vi behöver: .toast { animation: kf-slide-in 0,2s, kf-zoom 0,4s ease-out; --kf-slide-from: 0 100%; /* skjut uppifrån */ /* Använder standardzoom: skalar från 80 % till 100 % */ }
.modal { animation: kf-zoom 0,3s cubic-bezier(0,34, 1,56, 0,64, 1); --kf-zoom-från: 0; /* dramatisk zoom från 0 % till 100 % */ }
.heading { animation: kf-fade-in 2s, kf-zoom 2s lätta in; --kf-zoom-från: 1,2; --kf-zoom-to: 0,8; /* försiktig skala ner */ }
Standardvärdet på 0,8 (80%) fungerar perfekt för de flesta UI-element, som toast-meddelanden och kort, samtidigt som det är lätt att anpassa för speciella fall. Se Pen Keyframes Tokens - Demo 4 [forked] av Amit Sheen. Du kanske har märkt något intressant i de senaste exemplen: vi har kombinerat animationer. En av de viktigaste fördelarna med att arbeta med @keyframes-tokens är att de är designade för att integreras sömlöst med varandra. Denna mjuka sammansättning är avsiktlig, inte oavsiktlig. Vi kommer att diskutera animationskomposition mer i detalj senare, inklusive var de kan bli problematiska, men de flesta kombinationer är enkla och lätta att implementera. Notera: När jag skrev den här artikeln, och kanske på grund av att jag skrev den, kom jag på att jag tänkte om hela idén med entréanimationer. Med alla de senaste framstegen inom CSS, behöver vi fortfarande dem överhuvudtaget? Lyckligtvis utforskade Adam Argyle samma frågor och uttryckte dem briljant i sin blogg. Detta motsäger inte vad som skrivs här, men det presenterar ett tillvägagångssätt som är värt att överväga, särskilt om dina projekt är mycket beroende av entréanimationer. Kontinuerliga animationer Medan ingångsanimationer, som "fade", "slide" och "zoom" händer en gång och sedan slutar, slingrar kontinuerliga animationer oändligt för att dra uppmärksamhet eller indikera pågående aktivitet. De två vanligaste kontinuerliga animationerna jag stöter på är "spin" (för laddningsindikatorer) och "puls" (för att markera viktiga element). Dessa animationer erbjuder unika utmaningar när det gäller att skapa nyckelbildspel. Till skillnad från ingångsanimationer som vanligtvis går från ett tillstånd till ett annat, måste kontinuerliga animationer vara mycket anpassningsbara i sina beteendemönster. Spin Doctor Varje projekt verkar använda flera snurranimationer. Vissa snurrar medurs, andra moturs. Vissa gör en enda 360-graders rotation, andra gör flera varv för en snabbare effekt. Istället för att skapa separata nyckelrutor för varje variant, låt oss bygga ett flexibelt snurr som hanterar alla scenarier:
/* * Spin - rotationsanimering * Använd --kf-spin-from och --kf-spin-to för att styra rotationsområdet * Använd --kf-spin-turns för att kontrollera rotationsmängden * Standard: roterar från 0 grader till 360 grader (1 hel rotation) *Användning: * animation: kf-spin 1s linjär oändlig; * --kf-snurr: 2; // 2 hela varv * --kf-spin-från: 0deg; --kf-spin-to: 180deg; // halv rotation * --kf-spin-från: 0deg; --kf-spin-to: -360deg; // moturs */
@keyframes kf-spin { från { rotera: var(--kf-snurr-från, 0 grader); } till { rotera: calc(var(--kf-snurr-från, 0 grader) + var(--kf-snurr-till, 360 grader) * var(--kf-snurr, 1)); } }
Nu kan vi skapa vilken snurrvariation vi vill:
.loading-spinner { animation: kf-spin 1s linjär oändlig; /* Använder standard: roterar från 0deg till 360deg */ }
.fast-loader { animation: kf-spin 1.2s ease-in-out oändlig alternativ; --kf-snurr-vänder: 3; /* 3 hela varv för varje riktning per cykel*/ }
.steped-reverse { animation: kf-spin 1,5s steg(8) oändlig; --kf-spin-to: -360deg; /* moturs */ }
.subtle-wiggle { animation: kf-spin 2s ease-in-out oändlig alternativ; --kf-spin-från: -16 grader; --kf-spin-to: 32deg; /* vicka 36 grader: mellan -18 grader och +18 grader */ }
Se Pen Keyframes Tokens - Demo 5 [forked] av Amit Sheen. Det fina med detta tillvägagångssätt är att samma nyckelbildrutor fungerar för att ladda spinnare, roterande ikoner, vickningseffekter och till och med komplexa animeringar med flera varv. Pulsparadoxen Pulsanimationer är svårare eftersom de kan "pulsera" olika egenskaper. Vissa pulserar skalan, andra pulserar opaciteten och vissa pulserar färgegenskaper som ljusstyrka eller mättnad. Istället för att skapa separata nyckelrutor för varje egenskap, kan vi skapa nyckelrutor som fungerar med vilken CSS-egenskap som helst. Här är ett exempel på en pulsnyckelbildruta med alternativ för skala och opacitet:
/* * Puls - pulserande animation * Använd --kf-pulse-scale-from och --kf-pulse-scale-to för att styra skalomfånget * Använd --kf-pulse-opacity-from och --kf-pulse-opacity-to för att styra opacitetsområdet * Standard: ingen puls (alla värden 1) *Användning: * animation: kf-puls 2s ease-in-out oändlig alternativ; * --kf-pulsskala-från: 0,95; --kf-pulsskala-till: 1,05; // skala puls * --kf-pulsopacitet-från: 0,7; --kf-pulsopacitet-till: 1; // opacitetspuls */
@keyframes kf-puls { från { skala: var(--kf-pulsskala-från, 1); opacitet: var(--kf-puls-opacitet-från, 1); } till { skala: var(--kf-pulsskala-till, 1); opacitet: var(--kf-puls-opacitet-till, 1); } }
Detta skapar en flexibel puls som kan animera flera egenskaper: .call-to-action { animation: kf-puls 0,6s oändlig alternat; --kf-pulsopacitet-från: 0,5; /* opacitetspuls */ }
.notification-dot { animation: kf-puls 0.6s lätthet-in-ut oändlig alternativ; --kf-pulsskala-från: 0,9; --kf-pulsskala-till: 1,1; /* skalpuls */ }
.text-highlight { animation: kf-puls 1.5s ease-out oändlig; --kf-pulsskala-från: 0,8; --kf-pulsopacitet-från: 0,2; /* skala och opacitetspuls */ }
Se Pen Keyframes Tokens - Demo 6 [forked] av Amit Sheen. Denna enda kf-puls nyckelbild kan hantera allt från subtila uppmärksamhetsfång till dramatiska höjdpunkter, samtidigt som den är lätt att anpassa. Avancerad lättnad En av de fantastiska sakerna med att använda keyframes-tokens är hur lätt det är att utöka vårt animationsbibliotek och tillhandahålla effekter som de flesta utvecklare inte skulle bry sig om att skriva från början, som resår eller studs. Här är ett exempel på en enkel "bounce" nyckelbildstoken som använder en --kf-bounce-from anpassad egenskap för att styra hopphöjden. /* * Bounce - studsande entréanimation * Använd --kf-bounce-from för att kontrollera hopphöjden * Standard: hoppar från 100vh (från skärm) *Användning: * animation: kf-bounce 3s ease-in; * --kf-bounce-from: 200px; // hoppa från 200px höjd */
@keyframes kf-bounce { 0 % { translate: 0 calc(var(--kf-bounce-from, 100vh) * -1); }
34 % { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0.4); }
55 % { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0.2); }
72 % { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0.1); }
85 % { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0,05); }
94 % { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0,025); }
99 % { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0,0125); }
22 %, 45 %, 64 %, 79 %, 90 %, 97 %, 100 % { översätt: 0 0; animation-timing-funktion: ease-out; } }
Animationer som "elastic" är lite knepigare på grund av beräkningarna inuti nyckelbildrutorna. Vi måste definiera --kf-elastic-from-X och --kf-elastic-from-Y separat (båda är valfria), och tillsammans låter de oss skapa en elastisk ingång från vilken punkt som helst på skärmen.
/* * Elastic In - elastisk entréanimation * Använd --kf-elastic-from-X och --kf-elastic-from-Y för att styra startpositionen * Standard: går in från övre mitten (0, -100vh) *Användning: * animation: kf-elastic-in 2s ease-in-out båda; * --kf-elastic-from-X: -50px; * --kf-elastic-from-Y: -200px; // ange från (-50px, -200px) */
@keyframes kf-elastic-in { 0 % { translate: calc(var(--kf-elastic-from-X, -50vw) * 1) calc(var(--kf-elastic-from-Y, 0px) * 1); }
16 % { translate: calc(var(--kf-elastic-from-X, -50vw) * -0,3227) calc(var(--kf-elastic-from-Y, 0px) * -0,3227); }
28 % { översätt: calc(var(--kf-elastic-from-X, -50vw) * 0,1312)calc(var(--kf-elastic-from-Y, 0px) * 0,1312); }
44 % { translate: calc(var(--kf-elastic-from-X, -50vw) * -0,0463) calc(var(--kf-elastic-from-Y, 0px) * -0,0463); }
59 % { translate: calc(var(--kf-elastic-from-X, -50vw) * 0,0164) calc(var(--kf-elastic-from-Y, 0px) * 0,0164); }
73 % { translate: calc(var(--kf-elastic-from-X, -50vw) * -0,0058) calc(var(--kf-elastic-from-Y, 0px) * -0,0058); }
88 % { översätt: calc(var(--kf-elastic-from-X, -50vw) * 0,0020) calc(var(--kf-elastic-from-Y, 0px) * 0,0020); }
100 % { översätt: 0 0; } }
Detta tillvägagångssätt gör det enkelt att återanvända och anpassa avancerade nyckelbildrutor i hela vårt projekt, bara genom att ändra en enda anpassad egenskap.
.bounce-and-zoom { animation: kf-bounce 3s lätta in, kf-zoom 3s linjär; --kf-zoom-från: 0; }
.bounce-and-slide { animation-komposition: lägga till; /* Båda animationerna använder translate */ animation: kf-bounce 3s lätta in, kf-slide-in 3s ease-out; --kf-slide-from: -200px; }
.elastic-in { animation: kf-elastic-in 2s ease-in-out båda; }
Se Pen Keyframes Tokens - Demo 7 [forked] av Amit Sheen. Hittills har vi sett hur vi kan konsolidera nyckelbildrutor på ett smart och effektivt sätt. Of course, you might want to tweak things to better fit your project’s needs, but we’ve covered examples of several common animations and everyday use cases. And with these keyframes tokens in place, we now have powerful building blocks for creating consistent, maintainable animations across the entire project. Inga fler duplicerade nyckelbildrutor, inga fler globala räckviddskonflikter. Bara ett rent, bekvämt sätt att hantera alla våra animationsbehov. Men den verkliga frågan är: Hur komponerar vi dessa byggstenar tillsammans? Att sätta ihop allt Vi har sett att det är enkelt att kombinera grundläggande keyframes-tokens. Vi behöver inget speciellt än att definiera den första animationen, definiera den andra, ställa in variablerna efter behov, och det är allt. /* Tona in + skjut in */ .toast { animation: kf-fade-in 0,4s, kf-slide-in 0,4s cubic-bezier(0,34, 1,56, 0,64, 1); --kf-slide-from: 0 40px; }
/* Zooma in + tona in */ .modal { animation: kf-fade-in 0,3s, kf-zoom 0,3s cubic-bezier(0,34, 1,56, 0,64, 1); --kf-zoom-från: 0,7; --kf-zoom-to: 1; }
/* Skjut in + puls */ .notification { animation: kf-slide-in 0,5s, kf-puls 1.2s ease-in-out oändlig alternativ; --kf-slide-from: -100px 0; --kf-pulsskala-från: 0,95; --kf-pulsskala-till: 1,05; }
These combinations work beautifully because each animation targets a different property: opacity, transform (translate/scale), etc. But sometimes there are conflicts, and we need to know why and how to deal with them. When two animations try to animate the same property — for example, both animating scale or both animating opacity — the result will not be what you expect. Som standard tillämpas faktiskt bara en av animationerna på den egenskapen, vilket är den sista i animeringslistan. Detta är en begränsning av hur CSS hanterar flera animationer på samma egenskap. Detta kommer till exempel inte att fungera som avsett eftersom endast kf-pulsanimeringen kommer att gälla. .bad-combo { animation: kf-zoom 0,5s framåt, kf-puls 1.2s oändlig alternera; --kf-zoom-från: 0,5; --kf-zoom-to: 1,2; --kf-pulsskala-från: 0,8; --kf-pulsskala-till: 1,1; }
Animation tillägg Det enklaste och mest direkta sättet att hantera flera animationer som påverkar samma egenskap är att använda egenskapen animation-composition. In the last example above, the kf-pulse animation replaces the kf-zoom animation, so we will not see the initial zoom and will not get the expected scale to of 1.2. Genom att ställa in animationskompositionen som ska läggas till säger vi åt webbläsaren att kombinera båda animationerna. Detta ger oss det resultat vi vill ha. .component-two { animation-komposition: lägga till; }
Se Pen Keyframes Tokens - Demo 8 [forked] av Amit Sheen. Detta tillvägagångssätt fungerar bra för de flesta fall där vi vill kombinera effekter på samma fastighet. Det är också användbart när vi behöver kombinera animationer med statiska egenskapsvärden. For example, if we have an element that uses the translate property to position it exactly where we want, and then we want to animate it in with the kf-slide-in keyframes, we get a nasty visible jump without animation-composition. Se Pen Keyframes Tokens - Demo 9 [forked] av Amit Sheen. Med animation-komposition inställd att lägga till, kombineras animationen smidigt med det befintligatransformera, så att elementet stannar på plats och animeras som förväntat. Animation Stagger Ett annat sätt att hantera flera animeringar är att "förskjuta" dem - det vill säga starta den andra animeringen något efter att den första är klar. Det är inte en lösning som fungerar för alla fall, men det är användbart när vi har en ingångsanimation följt av en kontinuerlig animering. /* fade in + opacity pulse */ .notification { animation: kf-fade-in 2s ease-out, kf-pulse 0.5s 2s ease-in-out infinite alternate; --kf-pulse-opacity-to: 0.5; }
Se Pen Keyframes Tokens - Demo 10 [forked] av Amit Sheen. Ordningsfrågan En stor del av animationerna vi arbetar med använder transformegenskapen. In most cases, this is simply more convenient. Den har också en prestandafördel eftersom transformationsanimationer kan GPU-accelereras. Men om vi använder transformationer måste vi acceptera att ordningen i vilken vi utför våra transformationer spelar roll. Mycket. I våra nyckelbilder hittills har vi använt individuella transformationer. Enligt specifikationerna tillämpas dessa alltid i en fast ordning: först översätts elementet, roteras sedan och skalas sedan. This makes sense and is what most of us expect. Men om vi använder egenskapen transform är ordningen som funktionerna skrivs i den ordning som de tillämpas. I det här fallet, om vi flyttar något 100 pixlar på X-axeln och sedan roterar det 45 grader, är det inte samma sak som att först rotera det 45 grader och sedan flytta det 100 pixlar. /* Pink square: First translate, then rotate */ .example-one { transform: translateX(100px) rotate(45deg); }
/* Green square: First rotate, then translate */ .example-two { transform: rotate(45deg) translateX(100px); }
Se Pen Keyframes Tokens - Demo 11 [forked] av Amit Sheen. Men enligt transformationsordningen sker alla individuella transformeringar – allt vi har använt för nyckelbildrutornas tokens – innan transformationsfunktionerna. Det betyder att allt du ställer in i transform-egenskapen kommer att hända efter animeringarna. Men om du ställer in, till exempel, översätt tillsammans med kf-spin-nyckelrutorna, kommer översättningen att ske innan animeringen. Förvirrad ännu?! Detta leder till situationer där statiska värden kan orsaka olika resultat för samma animering, som i följande fall:
/* Common animation for both spinners */ .spinner { animation: kf-spin 1s linjär oändlig; }
/* Rosa spinner: översätt före rotation (individuell transformation) */ .spinner-pink { översätt: 100% 50%; }
/* Grön spinner: rotera och översätt sedan (funktionsordning) */ .spinner-green { transform: translate(100%, 50%); }
Se Pen Keyframes Tokens - Demo 12 [forked] av Amit Sheen. Du kan se att den första spinnaren (rosa) får en översättning som sker före rotationen av kf-spin, så den flyttar sig först till sin plats och snurrar sedan. Den andra spinnern (grön) får en translate() funktion som händer efter den individuella transformationen, så elementet snurrar först, sedan rör sig i förhållande till sin nuvarande vinkel, och vi får den där breda omloppseffekten. Nej, det här är ingen bugg. Det är bara en av de saker vi behöver veta om CSS och ha i åtanke när vi arbetar med flera animationer eller flera transformationer. Om det behövs kan du också skapa en extra uppsättning kf-spin-alt nyckelrutor som roterar element med hjälp av rotate()-funktionen. Minskad rörelse Och medan vi pratar om alternativa nyckelrutor kan vi inte ignorera alternativet "ingen animering". En av de största fördelarna med att använda keyframes-tokens är att tillgängligheten kan bakas in, och det är faktiskt ganska enkelt att göra. Genom att designa våra nyckelbildrutor med tillgänglighet i åtanke kan vi säkerställa att användare som föredrar reducerad rörelse får en smidigare, mindre distraherande upplevelse, utan extra arbete eller kodduplicering. Den exakta innebörden av "Reduced Motion" kan ändras lite från en animation till en annan, och från projekt till projekt, men här är några viktiga punkter att tänka på: Stänga av nyckelbildrutor Medan vissa animationer kan mjukas upp eller bromsas, finns det andra som borde försvinna helt när reducerad rörelse efterfrågas. Pulse animations are a good example. För att säkerställa att dessa animationer inte körs i reducerat rörelseläge kan vi helt enkelt slå in dem i lämplig mediafråga.
@media (prefers-reduced-motion: no-preference) { @keyfrmaes kf-pulse { från { skala: var(--kf-pulsskala-från, 1); opacitet: var(--kf-puls-opacitet-från, 1); } till { skala: var(--kf-pulsskala-till, 1); opacitet:var(--kf-pulsopacitet-till, 1); } } }
Detta säkerställer att användare som har ställt in preferens-reduced-motion för att reducera inte kommer att se animeringen och får en upplevelse som matchar deras preferenser. Instant In Det finns några nyckelrutor som vi inte bara kan ta bort, till exempel entréanimationer. Värdet måste förändras, måste animera; annars kommer elementet inte att ha de korrekta värdena. Men i reducerad rörelse bör denna övergång från initialvärdet vara omedelbar. För att uppnå detta kommer vi att definiera en extra uppsättning nyckelbildrutor där värdet hoppar direkt till sluttillståndet. Dessa blir våra standardnyckelrutor. Sedan lägger vi till de vanliga nyckelbildrutorna i en mediefråga för prefers-reduced-motion inställd på no-preference, precis som i föregående exempel. /* pop in omedelbart för minskad rörelse */ @keyframes kf-zoom { från, till { skala: var(--kf-zoom-to, 1); } }
@media (prefers-reduced-motion: no-preference) { /* Original zoomnyckelrutor */ @keyframes kf-zoom { från { skala: var(--kf-zoom-från, 0,8); } till { skala: var(--kf-zoom-to, 1); } } }
På så sätt kommer användare som föredrar reducerad rörelse att se elementet visas omedelbart i sitt slutliga tillstånd, medan alla andra får den animerade övergången. Det mjuka tillvägagångssättet Det finns fall där vi vill behålla lite rörelse, men mycket mjukare och lugnare än den ursprungliga animationen. Vi kan till exempel byta ut en studsande entré mot en skonsam fade-in.
@keyframes kf-bounce { /* Mjuk fade-in för minskad rörelse */ }
@media (prefers-reduced-motion: no-preference) { @keyframes kf-bounce { /* Original studsande nyckelbildrutor */ } }
Nu får användare med reducerad rörelse aktiverat fortfarande en känsla av utseende, men utan den intensiva rörelsen av en studs eller elastisk animering. Med byggstenarna på plats är nästa fråga hur man gör dem till en del av det faktiska arbetsflödet. Att skriva flexibla nyckelrutor är en sak, men att göra dem tillförlitliga i ett stort projekt kräver några strategier som jag var tvungen att lära mig den hårda vägen. Implementeringsstrategier och bästa praxis När vi väl har ett gediget bibliotek med nyckelbildspels-tokens är den verkliga utmaningen hur vi tar med dem i det dagliga arbetet.
Frestelsen är att släppa in alla nyckelbilder på en gång och förklara problemet löst, men i praktiken har jag funnit att de bästa resultaten kommer från en gradvis adoption. Börja med de vanligaste animationerna, som fade eller slide. Dessa är enkla vinster som visar omedelbart värde utan att kräva stora omskrivningar. Namngivning är en annan punkt som förtjänar uppmärksamhet. Ett konsekvent prefix eller namnutrymme gör det uppenbart vilka animationer som är tokens och vilka som är lokala engångsföreteelser. Det förhindrar också oavsiktliga kollisioner och hjälper nya teammedlemmar att känna igen det delade systemet med en blick. Dokumentation är lika viktig som själva koden. Även en kort kommentar ovanför varje nyckelbildstoken kan spara timmar av gissningar senare. En utvecklare bör kunna öppna token-filen, skanna efter den effekt de behöver och kopiera användningsmönstret rakt in i sin komponent. Flexibilitet är det som gör detta tillvägagångssätt värt ansträngningen. Genom att exponera förnuftiga anpassade egenskaper ger vi teamen utrymme att anpassa animeringen utan att bryta systemet. Försök samtidigt att inte överkomplicera. Tillhandahåll de rattar som betyder något och håll resten medvetna. Slutligen, kom ihåg tillgängligheten. Inte varje animation behöver ett alternativ med reducerad rörelse, men många gör det. Att baka in dessa justeringar tidigt innebär att vi aldrig behöver eftermontera dem senare, och det visar en nivå av omsorg som våra användare kommer att märka även om de aldrig nämner det.
Enligt min erfarenhet är det att behandla nyckelbildstoken som en del av vårt arbetsflöde för designtokens som får dem att fastna. När de väl är på plats slutar de kännas som specialeffekter och blir en del av formspråket, en naturlig förlängning av hur produkten rör sig och reagerar. Avslutning Animationer kan vara en av de roligaste delarna av att bygga gränssnitt, men utan struktur kan de också bli en av de största källorna till frustration. Genom att behandla nyckelbildrutor som tokens tar du något som vanligtvis är rörigt och svårt att hantera och gör det till ett tydligt, förutsägbart system. Det verkliga värdet ligger inte bara i att spara några rader kod. Det är i förtroendet att när du använder en toning, bild, zoom eller snurr, vet du exakt hur den kommer att bete sig i hela projektet. Det är i flexibiliteten som kommer från anpassade egenskaper utan kaoset av oändliga variationer. Och det är i tillgängligheten inbyggd i grunden snarare än läggs till somen eftertanke. Jag har sett dessa idéer fungera i olika team och olika kodbaser, och mönstret är alltid detsamma. När tokens väl är på plats slutar keyframes att vara en spridd samling tricks och blir en del av formspråket. De gör att produkten känns mer avsiktlig, mer konsekvent och mer levande. Om du tar en sak från den här artikeln, låt det vara detta: animationer förtjänar samma omsorg och struktur som vi redan ger till färger, typografi och avstånd. En liten investering i keyframes-tokens lönar sig varje gång ditt gränssnitt flyttas.