Se for deg dette: du blir med i et nytt prosjekt, dykker ned i kodebasen, og i løpet av de første timene oppdager du noe frustrerende kjent. Spredt over stilarkene finner du flere @keyframes-definisjoner for de samme grunnleggende animasjonene. Tre forskjellige inntoningseffekter, to eller tre lysbildevarianter, en håndfull zoom-animasjoner og minst to forskjellige spinn-animasjoner fordi, vel, hvorfor ikke? @keyframes puls { fra { skala: 1; } til { skala: 1,1; } }
@keyframes bigger-pulse { 0 %, 20 %, 100 % { skala: 1; } 10 %, 40 % { skala: 1,2; } }
Hvis dette scenariet høres kjent ut, er du ikke alene. Etter min erfaring på tvers av ulike prosjekter, er en av de mest konsistente raske gevinstene jeg kan levere konsolidering og standardisering av nøkkelbilder. Det har blitt et så pålitelig mønster at jeg nå ser frem til denne oppryddingen som en av mine første oppgaver på en ny kodebase. Logikken bak kaoset Denne redundansen gir perfekt mening når du tenker på det. Vi bruker alle de samme grunnleggende animasjonene i vårt daglige arbeid: toner, lysbilder, zoomer, spinn og andre vanlige effekter. Disse animasjonene er ganske enkle, og det er enkelt å lage en rask @keyframes-definisjon for å få jobben gjort. Uten et sentralisert animasjonssystem skriver utviklere disse nøkkelbildene fra bunnen av, uvitende om at lignende animasjoner allerede finnes andre steder i kodebasen. Dette er spesielt vanlig når man jobber i komponentbaserte arkitekturer (som de fleste av oss gjør i disse dager), da team ofte jobber parallelt på tvers av ulike deler av applikasjonen. Resultatet? Animasjonskaos. Det lille problemet De mest åpenbare problemene med duplisering av nøkkelbilder er bortkastet utviklingstid og unødvendig kodeoppblåsthet. Flere nøkkelbildedefinisjoner betyr flere steder å oppdatere når kravene endres. Trenger du å justere tidspunktet for fade-animasjonen? Du må jakte på alle forekomster på tvers av kodebasen din. Vil du standardisere lettelsesfunksjoner? Lykke til med å finne alle variantene. Denne multiplikasjonen av vedlikeholdspunkter gjør selv enkle animasjonsoppdateringer til en tidkrevende oppgave. Det større problemet Denne dupliseringen av nøkkelbilder skaper et mye mer lumsk problem som lurer under overflaten: den globale scope-fellen. Selv når du arbeider med komponentbaserte arkitekturer, er CSS-nøkkelrammer alltid definert i det globale omfanget. Dette betyr at alle nøkkelbilder gjelder for alle komponenter. Alltid. Ja, animasjonen din bruker ikke nødvendigvis nøkkelbildene du definerte i komponenten. Den bruker de siste nøkkelbildene som samsvarer med det samme navnet som ble lastet inn i det globale omfanget. Så lenge alle nøkkelbildene dine er identiske, kan dette virke som et mindre problem. Men i det øyeblikket du vil tilpasse en animasjon for et spesifikt brukstilfelle, er du i trøbbel, eller enda verre, du er den som forårsaker dem. Enten vil ikke animasjonen din fungere fordi en annen komponent lastet inn etter din, overskriver nøkkelbildene dine, eller komponenten din lastes inn sist og ved et uhell endrer animasjonsatferden for hver annen komponent som bruker den nøkkelrammens navn, og du er kanskje ikke engang klar over det. Her er et enkelt eksempel som viser problemet: .component-one { /* komponentstiler */ animasjon: puls 1s ease-in-out uendelig alternativ; }
/* denne @keyframes-definisjonen vil ikke fungere */ @keyframes puls { fra { skala: 1; } til { skala: 1,1; } }
/* senere i koden... */
.component-two { /* komponentstiler */ animasjon: puls 1s ease-in-out uendelig; }
/* disse nøkkelbildene vil gjelde for begge komponentene */ @keyframes puls { 0 %, 20 %, 100 % { skala: 1; } 10 %, 40 % { skala: 1,2; } }
Begge komponentene bruker samme animasjonsnavn, men den andre @keyframes-definisjonen overskriver den første. Nå vil både komponent-en og komponent-to bruke de andre nøkkelbildene, uavhengig av hvilken komponent som definerte hvilke nøkkelbilder. Se Pen Keyframes Tokens - Demo 1 [forked] av Amit Sheen. Den verste delen? Dette fungerer ofte perfekt i lokal utvikling, men bryter på mystisk vis i produksjonen når byggeprosesser endrer innlastingsrekkefølgen til stilarkene dine. Du ender opp med animasjoner som oppfører seg forskjellig avhengig av hvilke komponenter som er lastet inn og i hvilken rekkefølge. Løsningen: Unified Keyframes Svaret på dette kaoset er overraskende enkelt: forhåndsdefinerte dynamiske nøkkelrammer lagret i et delt stilark. I stedet for å la hver komponent definere sine egne animasjoner, lager vi sentraliserte nøkkelrammer som er godt dokumenterte, enkle åbruk, vedlikeholdbar og skreddersydd til de spesifikke behovene til prosjektet ditt. Tenk på det som keyframes-tokens. Akkurat som vi bruker tokens for farger og mellomrom, og mange av oss allerede bruker tokens for animasjonsegenskaper, som varighet og lettelsesfunksjoner, hvorfor ikke bruke tokens for keyframes også? Denne tilnærmingen kan integreres naturlig med hvilken som helst gjeldende designtoken-arbeidsflyt du bruker, samtidig som den løser både det lille problemet (kodeduplisering) og det større problemet (konflikter med globalt omfang) på én gang. Ideen er grei: lag en enkelt kilde til sannhet for alle våre vanlige animasjoner. Dette delte stilarket inneholder nøye utformede nøkkelrammer som dekker animasjonsmønstrene prosjektet vårt faktisk bruker. Ikke mer å gjette om en fade-animasjon allerede eksisterer et sted i kodebasen vår. Ikke mer utilsiktet overskriving av animasjoner fra andre komponenter. Men her er nøkkelen: dette er ikke bare statiske copy-paste-animasjoner. De er designet for å være dynamiske og kan tilpasses gjennom egendefinerte CSS-egenskaper, slik at vi kan opprettholde konsistens samtidig som vi har fleksibiliteten til å tilpasse animasjoner til spesifikke brukstilfeller, for eksempel hvis du trenger en litt større "puls"-animasjon på ett sted. Bygger det første nøkkelbilde-tokenet En av de første lavthengende fruktene vi bør takle er "fade-in"-animasjonen. I et av mine siste prosjekter fant jeg over et dusin separate inntoningsdefinisjoner, og ja, de animerte alle ganske enkelt opasiteten fra 0 til 1. Så, la oss lage et nytt stilark, kalle det kf-tokens.css, importere det inn i prosjektet vårt, og plassere nøkkelrammer med riktige kommentarer i den. /* keyframes-tokens.css */
/* * Fade In - fade inngangsanimasjon * Bruk: animasjon: kf-fade-in 0.3s ease-out; */ @keyframes kf-fade-in { fra { opasitet: 0; } til { opasitet: 1; } }
Denne enkle @keyframes-erklæringen erstatter alle de spredte fade-in-animasjonene over kodebasen vår. Rent, enkelt og globalt anvendelig. Og nå som vi har dette tokenet definert, kan vi bruke det fra hvilken som helst komponent gjennom hele prosjektet vårt: .modal { animasjon: kf-fade-in 0.3s ease-out; }
.tooltip { animasjon: kf-fade-in 0,2s ease-in-out; }
.notification { animasjon: kf-fade-in 0,5s ease-out; }
Se Pen Keyframes Tokens - Demo 2 [forked] av Amit Sheen. Merk: Vi bruker et kf-prefiks i alle @keyframes-navnene våre. Dette prefikset fungerer som et navneområde som forhindrer navnekonflikter med eksisterende animasjoner i prosjektet og gjør det umiddelbart klart at disse nøkkelbildene kommer fra nøkkelbilde-token-filen vår. Lage et dynamisk lysbilde Kf-fade-in keyframes fungerer utmerket fordi det er enkelt og det er lite plass til å rote til ting. I andre animasjoner må vi imidlertid være mye mer dynamiske, og her kan vi utnytte den enorme kraften til egendefinerte CSS-egenskaper. Det er her keyframes-tokens virkelig skinner sammenlignet med spredte statiske animasjoner. La oss ta et vanlig scenario: «slide-in»-animasjoner. Men skli inn fra hvor? 100px fra høyre? 50 % fra venstre? Skal det komme inn fra toppen av skjermen? Eller kanskje flyte inn fra bunnen? Så mange muligheter, men i stedet for å lage separate nøkkelrammer for hver retning og hver variant, kan vi bygge ett fleksibelt token som tilpasser seg alle scenarier: /* * Skyv inn - retningsbestemt lysbildeanimasjon * Bruk --kf-slide-fra for å kontrollere retning * Standard: glir inn fra venstre (-100 %) * Bruk: * animasjon: kf-slide-in 0,3s ease-out; * --kf-slide-from: -100px 0; // skyv fra venstre * --kf-slide-from: 100px 0; // skyv fra høyre * --kf-slide-from: 0 -50px; // skyv fra toppen */
@keyframes kf-slide-in { fra { oversett: var(--kf-lysbilde-fra, -100% 0); } til { oversett: 0 0; } }
Nå kan vi bruke dette enkle @keyframes-tokenet for en hvilken som helst lysbilderetning ganske enkelt ved å endre --kf-slide-from egendefinert egenskap: .sidebar { animasjon: kf-slide-in 0,3s ease-out; /* Bruker standardverdi: lysbilder fra venstre */ }
.notification { animasjon: kf-slide-in 0,4s ease-out; --kf-slide-from: 0 -50px; /* skyv fra toppen */ }
.modal { animasjon: kf-fade-in 0,5s, kf-slide-in 0,5s cubic-bezier(0,34, 1,56, 0,64, 1); --kf-slide-from: 50px 50px; /* skyv fra nederst til høyre */ }
Denne tilnærmingen gir oss utrolig fleksibilitet samtidig som vi opprettholder konsistensen. Én keyframe-erklæring, uendelige muligheter. Se Pen Keyframes Tokens - Demo 3 [forked] av Amit Sheen. Og hvis vi ønsker å gjøre animasjonene våre enda mer fleksible, og tillate "glide-out"-effekter, kan vibare legg til en --kf-slide-to egendefinert egenskap, lik det vi vil se i neste avsnitt. Toveis zoom nøkkelrammer En annen vanlig animasjon som blir duplisert på tvers av prosjekter er "zoom"-effekter. Enten det er en subtil oppskalering for toast-meldinger, en dramatisk zoom-inn for modaler eller en mild nedskaleringseffekt for overskrifter, zoom-animasjoner er overalt. I stedet for å lage separate nøkkelrammer for hver skalaverdi, la oss bygge ett fleksibelt sett med kf-zoom nøkkelrammer:
/* * Zoom - skala animasjon * Bruk --kf-zoom-from og --kf-zoom-to for å kontrollere skalaverdier * Standard: zoomer fra 80 % til 100 % (0,8 til 1) * Bruk: * animasjon: kf-zoom 0.2s ease-out; * --kf-zoom-fra: 0,5; --kf-zoom-to: 1; // zoom fra 50 % til 100 % * --kf-zoom-fra: 1; --kf-zoom-to: 0; // zoom fra 100 % til 0 % * --kf-zoom-fra: 1; --kf-zoom-to: 1.1; // zoom fra 100 % til 110 % */
@keyframes kf-zoom { fra { skala: var(--kf-zoom-fra, 0,8); } til { skala: var(--kf-zoom-to, 1); } }
Med én definisjon kan vi oppnå hvilken som helst zoomvariasjon vi trenger: .toast { animasjon: kf-slide-in 0,2s, kf-zoom 0,4s ease-out; --kf-slide-fra: 0 100%; /* skyv fra toppen */ /* Bruker standard zoom: skalerer fra 80 % til 100 % */ }
.modal { animasjon: kf-zoom 0,3s cubic-bezier(0,34, 1,56, 0,64, 1); --kf-zoom-fra: 0; /* dramatisk zoom fra 0 % til 100 % */ }
.heading { animasjon: kf-fade-in 2s, kf-zoom 2s lette inn; --kf-zoom-fra: 1,2; --kf-zoom-to: 0,8; /* forsiktig nedskalering */ }
Standarden på 0,8 (80 %) fungerer perfekt for de fleste UI-elementer, som toast-meldinger og kort, samtidig som den er enkel å tilpasse for spesielle tilfeller. Se Pen Keyframes Tokens - Demo 4 [forked] av Amit Sheen. Du har kanskje lagt merke til noe interessant i de siste eksemplene: vi har kombinert animasjoner. En av de viktigste fordelene ved å jobbe med @keyframes-tokens er at de er designet for å integrere sømløst med hverandre. Denne glatte sammensetningen er tilsiktet, ikke tilfeldig. Vi vil diskutere animasjonskomposisjon mer detaljert senere, inkludert hvor de kan bli problematiske, men de fleste kombinasjoner er enkle og enkle å implementere. Merk: Mens jeg skrev denne artikkelen, og kanskje på grunn av å skrive den, fant jeg meg selv i å revurdere hele ideen om inngangsanimasjoner. Med alle de siste fremskrittene innen CSS, trenger vi dem fortsatt i det hele tatt? Heldigvis utforsket Adam Argyle de samme spørsmålene og uttrykte dem briljant i bloggen sin. Dette motsier ikke det som er skrevet her, men det presenterer en tilnærming som er verdt å vurdere, spesielt hvis prosjektene dine er avhengige av inngangsanimasjoner. Kontinuerlige animasjoner Mens inngangsanimasjoner, som "fade", "slide" og "zoom" skjer én gang og deretter stopper, sløyfes kontinuerlige animasjoner på ubestemt tid for å tiltrekke oppmerksomhet eller indikere pågående aktivitet. De to vanligste kontinuerlige animasjonene jeg møter er "spin" (for belastningsindikatorer) og "puls" (for å fremheve viktige elementer). Disse animasjonene byr på unike utfordringer når det gjelder å lage keyframes-tokens. I motsetning til inngangsanimasjoner som vanligvis går fra en tilstand til en annen, må kontinuerlige animasjoner være svært tilpassbare i atferdsmønstrene deres. Spin Doctor Hvert prosjekt ser ut til å bruke flere spinn-animasjoner. Noen spinner med klokken, andre mot klokken. Noen gjør en enkelt 360-graders rotasjon, andre gjør flere svinger for en raskere effekt. I stedet for å lage separate nøkkelrammer for hver variant, la oss bygge ett fleksibelt spinn som håndterer alle scenarier:
/* * Spin - rotasjonsanimasjon * Bruk --kf-spin-from og --kf-spin-to for å kontrollere rotasjonsområdet * Bruk --kf-spin-turns for å kontrollere rotasjonsmengden * Standard: roterer fra 0 grader til 360 grader (1 full rotasjon) * Bruk: * animasjon: kf-spin 1s lineær uendelig; * --kf-spinn-svinger: 2; // 2 hele rotasjoner * --kf-spinn-fra: 0 grader; --kf-spin-to: 180 grader; // halv rotasjon * --kf-spinn-fra: 0 grader; --kf-spin-to: -360 grader; // mot klokken */
@keyframes kf-spin { fra { roter: var(--kf-spinn-fra, 0grader); } til { roter: calc(var(--kf-spin-from, 0deg) + var(--kf-spin-to, 360deg) * var(--kf-spin-turns, 1)); } }
Nå kan vi lage hvilken som helst spinnvariasjon vi liker:
.loading-spinner { animasjon: kf-spin 1s lineær uendelig; /* Bruker standard: roterer fra 0deg til 360deg */ }
.fast-loader { animasjon: kf-spin 1.2s ease-in-out uendelig alternativ; --kf-spinn-svinger: 3; /* 3 hele rotasjoner for hver retning per syklus*/ }
.steped-reverse { animasjon: kf-spin 1,5s trinn(8) uendelig; --kf-spin-to: -360 grader; /* mot klokken */ }
.subtle-wiggle { animasjon: kf-spin 2s ease-in-out uendelig alternativ; --kf-spinn-fra: -16 grader; --kf-spinn-til: 32 grader; /* vrikke 36 grader: mellom -18 grader og +18 grader */ }
Se Pen Keyframes Tokens - Demo 5 [forked] av Amit Sheen. Det fine med denne tilnærmingen er at de samme nøkkelbildene fungerer for lasting av spinnere, roterende ikoner, slingringseffekter og til og med komplekse multi-turn animasjoner. Pulsparadokset Pulsanimasjoner er vanskeligere fordi de kan "pulsere" forskjellige egenskaper. Noen pulserer skalaen, andre pulserer opasiteten, og noen pulserer fargeegenskaper som lysstyrke eller metning. I stedet for å lage separate nøkkelrammer for hver eiendom, kan vi lage nøkkelrammer som fungerer med en hvilken som helst CSS-eiendom. Her er et eksempel på en pulsnøkkelramme med skala- og opasitetsalternativer:
/* * Pulse - pulserende animasjon * Bruk --kf-pulse-scale-from og --kf-pulse-scale-to for å kontrollere skalaområdet * Bruk --kf-pulse-opacity-from og --kf-pulse-opacity-to for å kontrollere opasitetsområde * Standard: ingen puls (alle verdier 1) * Bruk: * animasjon: kf-puls 2s ease-in-out uendelig alternativ; * --kf-pulsskala-fra: 0,95; --kf-puls-skala-til: 1,05; // skala puls * --kf-puls-opasitet-fra: 0,7; --kf-puls-opasitet-til: 1; // opasitetspuls */
@keyframes kf-puls { fra { skala: var(--kf-puls-skala-fra, 1); opasitet: var(--kf-puls-opasitet-fra, 1); } til { skala: var(--kf-puls-skala-til, 1); opasitet: var(--kf-puls-opasitet-til, 1); } }
Dette skaper en fleksibel puls som kan animere flere egenskaper: .call-to-action { animasjon: kf-puls 0,6s uendelig alternativ; --kf-puls-opasitet-fra: 0,5; /* opasitetspuls */ }
.notification-dot { animasjon: kf-puls 0.6s ease-in-out uendelig alternativ; --kf-pulsskala-fra: 0,9; --kf-puls-skala-til: 1,1; /* skala puls */ }
.text-highlight { animasjon: kf-puls 1.5s ease-out uendelig; --kf-pulsskala-fra: 0,8; --kf-puls-opasitet-fra: 0,2; /* skala og opasitetspuls */ }
Se Pen Keyframes Tokens - Demo 6 [forked] av Amit Sheen. Denne enkle kf-puls nøkkelrammen kan håndtere alt fra subtile oppmerksomhetsfang til dramatiske høydepunkter, samtidig som den er enkel å tilpasse. Avansert lettelse En av de flotte tingene med å bruke keyframes-tokens er hvor enkelt det er å utvide animasjonsbiblioteket vårt og gi effekter som de fleste utviklere ikke ville bry seg om å skrive fra bunnen av, som strikk eller sprett. Her er et eksempel på et enkelt "bounce" keyframes-token som bruker en egendefinert --kf-bounce-from-egenskap for å kontrollere hopphøyden. /* * Bounce - spretter inngangsanimasjon * Bruk --kf-bounce-from for å kontrollere hopphøyden * Standard: hopper fra 100vh (utenfor skjermen) * Bruk: * animasjon: kf-bounce 3s ease-in; * --kf-sprett-fra: 200px; // hopp fra 200px høyde */
@keyframes kf-bounce { 0 % { oversett: 0 calc(var(--kf-sprett-fra, 100vh) * -1); }
34 % { oversett: 0 calc(var(--kf-sprett-fra, 100vh) * -0,4); }
55 % { oversett: 0 calc(var(--kf-sprett-fra, 100vh) * -0,2); }
72 % { oversett: 0 calc(var(--kf-sprett-fra, 100vh) * -0.1); }
85 % { oversett: 0 calc(var(--kf-sprett-fra, 100vh) * -0,05); }
94 % { oversett: 0 calc(var(--kf-sprett-fra, 100vh) * -0,025); }
99 % { oversett: 0 calc(var(--kf-sprett-fra, 100vh) * -0,0125); }
22 %, 45 %, 64 %, 79 %, 90 %, 97 %, 100 % { oversett: 0 0; animasjon-timing-funksjon: ease-out; } }
Animasjoner som "elastisk" er litt vanskeligere på grunn av beregningene inne i nøkkelbildene. Vi må definere --kf-elastic-from-X og --kf-elastic-from-Y separat (begge er valgfrie), og sammen lar de oss lage en elastisk inngang fra et hvilket som helst punkt på skjermen.
/* * Elastic In - elastisk inngangsanimasjon * Bruk --kf-elastic-from-X og --kf-elastic-from-Y for å kontrollere startposisjonen * Standard: går inn fra øverste senter (0, -100vh) * Bruk: * animasjon: kf-elastic-in 2s ease-in-out begge; * --kf-elastisk-fra-X: -50px; * --kf-elastic-from-Y: -200px; // enter from (-50px, -200px) */
@keyframes kf-elastic-in { 0 % { oversett: calc(var(--kf-elastisk-fra-X, -50vw) * 1) calc(var(--kf-elastisk-fra-Y, 0px) * 1); }
16 % { oversett: calc(var(--kf-elastisk-fra-X, -50vw) * -0,3227) calc(var(--kf-elastisk-fra-Y, 0px) * -0,3227); }
28 % { oversett: calc(var(--kf-elastisk-fra-X, -50vw) * 0,1312)calc(var(--kf-elastisk-fra-Y, 0px) * 0,1312); }
44 % { oversett: calc(var(--kf-elastisk-fra-X, -50vw) * -0,0463) calc(var(--kf-elastisk-fra-Y, 0px) * -0,0463); }
59 % { oversett: calc(var(--kf-elastisk-fra-X, -50vw) * 0,0164) calc(var(--kf-elastisk-fra-Y, 0px) * 0,0164); }
73 % { oversett: calc(var(--kf-elastisk-fra-X, -50vw) * -0,0058) calc(var(--kf-elastisk-fra-Y, 0px) * -0,0058); }
88 % { oversett: calc(var(--kf-elastisk-fra-X, -50vw) * 0,0020) calc(var(--kf-elastisk-fra-Y, 0px) * 0,0020); }
100 % { oversett: 0 0; } }
Denne tilnærmingen gjør det enkelt å gjenbruke og tilpasse avanserte nøkkelbilder på tvers av prosjektet vårt, bare ved å endre en enkelt tilpasset egenskap.
.bounce-and-zoom { animasjon: kf-bounce 3s ease-in, kf-zoom 3s lineær; --kf-zoom-fra: 0; }
.bounce-and-slide { animasjon-komposisjon: legge til; /* Begge animasjonene bruker translate */ animasjon: kf-bounce 3s ease-in, kf-slide-in 3s ease-out; --kf-slide-fra: -200px; }
.elastic-in { animasjon: kf-elastic-in 2s ease-in-out begge; }
Se Pen Keyframes Tokens - Demo 7 [forked] av Amit Sheen. Fram til dette punktet har vi sett hvordan vi kan konsolidere nøkkelbilder på en smart og effektiv måte. Selvfølgelig vil du kanskje finpusse ting for å passe bedre til prosjektets behov, men vi har dekket eksempler på flere vanlige animasjoner og hverdagsbruk. Og med disse keyframes-tokenene på plass, har vi nå kraftige byggeklosser for å lage konsistente, vedlikeholdbare animasjoner på tvers av hele prosjektet. Ingen flere dupliserte nøkkelbilder, ingen flere globale omfangskonflikter. Bare en ren og praktisk måte å håndtere alle våre animasjonsbehov. Men det virkelige spørsmålet er: Hvordan komponerer vi disse byggesteinene sammen? Setter alt sammen Vi har sett at det er enkelt å kombinere grunnleggende keyframes-tokens. Vi trenger ikke noe spesielt enn å definere den første animasjonen, definere den andre, angi variablene etter behov, og det er det. /* Fade inn + skyv inn */ .toast { animasjon: kf-fade-in 0,4s, kf-slide-in 0,4s cubic-bezier(0,34, 1,56, 0,64, 1); --kf-slide-from: 0 40px; }
/* Zoom inn + fade inn */ .modal { animasjon: kf-fade-in 0,3s, kf-zoom 0,3s kubikk-bezier(0,34, 1,56, 0,64, 1); --kf-zoom-fra: 0,7; --kf-zoom-to: 1; }
/* Skyv inn + puls */ .notification { animasjon: kf-slide-in 0,5s, kf-puls 1.2s ease-in-out uendelig alternativ; --kf-slide-from: -100px 0; --kf-pulsskala-fra: 0,95; --kf-puls-skala-til: 1,05; }
Disse kombinasjonene fungerer vakkert fordi hver animasjon retter seg mot en annen egenskap: opasitet, transformasjon (oversette/skalere) osv. Men noen ganger er det konflikter, og vi må vite hvorfor og hvordan vi skal håndtere dem. Når to animasjoner prøver å animere den samme egenskapen – for eksempel begge animasjonsskalaer eller begge animerende opasitet – blir ikke resultatet det du forventer. Som standard blir bare én av animasjonene faktisk brukt på den egenskapen, som er den siste i animasjonslisten. Dette er en begrensning på hvordan CSS håndterer flere animasjoner på samme eiendom. Dette vil for eksempel ikke fungere etter hensikten fordi kun kf-puls-animasjonen vil gjelde. .bad-combo { animasjon: kf-zoom 0,5s fremover, kf-puls 1.2s uendelig vekselvis; --kf-zoom-fra: 0,5; --kf-zoom-to: 1,2; --kf-pulsskala-fra: 0,8; --kf-puls-skala-til: 1,1; }
Animasjon tillegg Den enkleste og mest direkte måten å håndtere flere animasjoner som påvirker den samme egenskapen, er å bruke egenskapen animasjon-komposisjon. I det siste eksemplet ovenfor erstatter kf-puls-animasjonen kf-zoom-animasjonen, så vi vil ikke se den første zoomen og vil ikke få den forventede skalaen til 1,2. Ved å angi animasjonssammensetningen som skal legges til, ber vi nettleseren om å kombinere begge animasjonene. Dette gir oss det resultatet vi ønsker. .component-two { animasjon-komposisjon: legge til; }
Se Pen Keyframes Tokens - Demo 8 [forked] av Amit Sheen. Denne tilnærmingen fungerer godt for de fleste tilfeller der vi ønsker å kombinere effekter på samme eiendom. Det er også nyttig når vi skal kombinere animasjoner med statiske egenskapsverdier. For eksempel, hvis vi har et element som bruker translate-egenskapen for å plassere det akkurat der vi vil, og så vil vi animere det inn med kf-slide-in keyframes, får vi et ekkelt synlig hopp uten animasjonskomposisjon. Se Pen Keyframes Tokens - Demo 9 [forked] av Amit Sheen. Med animasjonskomposisjon satt til å legge til, kombineres animasjonen jevnt med det eksisterendetransformere, slik at elementet forblir på plass og animerer som forventet. Animasjon Stagger En annen måte å håndtere flere animasjoner på er å "stagge" dem - det vil si å starte den andre animasjonen litt etter at den første er ferdig. Det er ikke en løsning som fungerer for alle tilfeller, men den er nyttig når vi har en inngangsanimasjon etterfulgt av en kontinuerlig animasjon. /* fade in + opasitetspuls */ .notification { animasjon: kf-fade-in 2s ease-out, kf-puls 0,5s 2s lette-inn-ut uendelig vekselvis; --kf-puls-opasitet-til: 0,5; }
Se Pen Keyframes Tokens - Demo 10 [forked] av Amit Sheen. Bestilling er viktig En stor del av animasjonene vi jobber med bruker transform-egenskapen. I de fleste tilfeller er dette rett og slett mer praktisk. Den har også en ytelsesfordel siden transformasjonsanimasjoner kan GPU-akselereres. Men hvis vi bruker transformasjoner, må vi akseptere at rekkefølgen vi utfører transformasjonene i betyr noe. Mye. I våre nøkkelbilder så langt har vi brukt individuelle transformasjoner. I henhold til spesifikasjonene blir disse alltid brukt i en fast rekkefølge: først blir elementet oversatt, deretter rotert og deretter skalert. Dette gir mening og er det de fleste av oss forventer. Men hvis vi bruker transform-egenskapen, er rekkefølgen funksjonene skrives i rekkefølgen de brukes i. I dette tilfellet, hvis vi flytter noe 100 piksler på X-aksen og deretter roterer det 45 grader, er det ikke det samme som å først rotere det 45 grader og deretter flytte det 100 piksler. /* Rosa firkant: Oversett først, så roter */ .example-one { transform: translateX(100px) rotate(45deg); }
/* Grønn firkant: Roter først, og oversett deretter */ .example-two { transform: rotate(45deg) translateX(100px); }
Se Pen Keyframes Tokens - Demo 11 [forked] av Amit Sheen. Men i henhold til transformasjonsrekkefølgen, skjer alle individuelle transformasjoner - alt vi har brukt for nøkkelbilde-tokenene - før transformasjonen fungerer. Det betyr at alt du angir i transform-egenskapen vil skje etter animasjonene. Men hvis du for eksempel setter oversett sammen med kf-spin keyframes, vil oversettelsen skje før animasjonen. Fortsatt forvirret?! Dette fører til situasjoner der statiske verdier kan forårsake forskjellige resultater for samme animasjon, som i følgende tilfelle:
/* Felles animasjon for begge spinnere */ .spinner { animasjon: kf-spin 1s lineær uendelig; }
/* Rosa spinner: oversett før rotering (individuell transformasjon) */ .spinner-pink { oversett: 100 % 50 %; }
/* Grønn spinner: roter og oversett (funksjonsrekkefølge) */ .spinner-green { transform: translate(100%, 50%); }
Se Pen Keyframes Tokens - Demo 12 [forked] av Amit Sheen. Du kan se at den første spinneren (rosa) får en translate som skjer før rotasjonen av kf-spinn, så den flytter seg først til sin plass og spinner deretter. Den andre spinneren (grønn) får en translate()-funksjon som skjer etter den individuelle transformasjonen, så elementet spinner først, deretter beveger seg i forhold til sin nåværende vinkel, og vi får den brede baneeffekten. Nei, dette er ikke en feil. Det er bare en av de tingene vi trenger å vite om CSS og huske på når vi jobber med flere animasjoner eller flere transformasjoner. Om nødvendig kan du også lage et ekstra sett med kf-spin-alt nøkkelrammer som roterer elementer ved å bruke rotate()-funksjonen. Redusert bevegelse Og mens vi snakker om alternative nøkkelbilder, kan vi ikke ignorere alternativet "ingen animasjon". En av de største fordelene med å bruke keyframes-tokens er at tilgjengelighet kan bakes inn, og det er faktisk ganske enkelt å gjøre. Ved å designe nøkkelrammer med tilgjengelighet i tankene, kan vi sikre at brukere som foretrekker redusert bevegelse får en jevnere, mindre distraherende opplevelse, uten ekstra arbeid eller kodeduplisering. Den nøyaktige betydningen av "Reduced Motion" kan endre seg litt fra en animasjon til en annen, og fra prosjekt til prosjekt, men her er noen viktige punkter å huske på: Dempe nøkkelbilder Mens noen animasjoner kan mykeres eller bremses, er det andre som bør forsvinne helt når redusert bevegelse er forespurt. Pulsanimasjoner er et godt eksempel. For å sikre at disse animasjonene ikke kjører i redusert bevegelsesmodus, kan vi ganske enkelt pakke dem inn i den aktuelle mediespørringen.
@media (prefers-reduced-motion: no-preference) { @keyfrmaes kf-pulse { fra { skala: var(--kf-puls-skala-fra, 1); opasitet: var(--kf-puls-opasitet-fra, 1); } til { skala: var(--kf-puls-skala-til, 1); opasitet:var(--kf-puls-opasitet-til, 1); } } }
Dette sikrer at brukere som har satt foretrekker-redusert-bevegelse til å redusere, ikke vil se animasjonen og vil få en opplevelse som samsvarer med deres preferanser. Øyeblikkelig inn Det er noen keyframes vi ikke bare kan fjerne, for eksempel inngangsanimasjoner. Verdien må endres, må animere; ellers vil ikke elementet ha de riktige verdiene. Men i redusert bevegelse bør denne overgangen fra startverdien være øyeblikkelig. For å oppnå dette vil vi definere et ekstra sett med nøkkelbilder der verdien hopper umiddelbart til slutttilstanden. Disse blir våre standard nøkkelbilder. Deretter legger vi til de vanlige nøkkelbildene i en mediespørring for prefers-reduced-motion satt til no-preferanse, akkurat som i forrige eksempel. /* pop inn umiddelbart for redusert bevegelse */ @keyframes kf-zoom { fra, til { skala: var(--kf-zoom-to, 1); } }
@media (prefers-reduced-motion: no-preference) { /* Original zoom keyframes */ @keyframes kf-zoom { fra { skala: var(--kf-zoom-fra, 0,8); } til { skala: var(--kf-zoom-to, 1); } } }
På denne måten vil brukere som foretrekker redusert bevegelse se elementet vises umiddelbart i sin endelige tilstand, mens alle andre får den animerte overgangen. Den myke tilnærmingen Det er tilfeller der vi ønsker å holde litt bevegelse, men mye mykere og roligere enn den originale animasjonen. For eksempel kan vi erstatte en sprettinngang med en skånsom inntoning.
@keyframes kf-bounce { /* Myk fade-in for redusert bevegelse */ }
@media (prefers-reduced-motion: no-preference) { @keyframes kf-bounce { /* Originale returtaster */ } }
Nå får brukere med redusert bevegelse aktivert fortsatt en følelse av utseende, men uten den intense bevegelsen til en sprett eller elastisk animasjon. Med byggeklossene på plass, er neste spørsmål hvordan du kan gjøre dem til en del av selve arbeidsflyten. Å skrive fleksible nøkkelrammer er én ting, men å gjøre dem pålitelige på tvers av et stort prosjekt krever noen få strategier som jeg måtte lære på den harde måten. Implementeringsstrategier og beste praksis Når vi først har et solid bibliotek med keyframes-tokens, er den virkelige utfordringen hvordan vi tar dem inn i det daglige arbeidet.
Fristelsen er å slippe alle nøkkelbilder på en gang og erklære problemet løst, men i praksis har jeg funnet ut at de beste resultatene kommer fra gradvis adopsjon. Start med de vanligste animasjonene, for eksempel fade eller slide. Dette er enkle gevinster som viser umiddelbar verdi uten å kreve store omskrivninger. Navngivning er et annet punkt som fortjener oppmerksomhet. Et konsekvent prefiks eller navneområde gjør det åpenbart hvilke animasjoner som er tokens og hvilke som er lokale engangseffekter. Det forhindrer også utilsiktede kollisjoner og hjelper nye teammedlemmer å gjenkjenne det delte systemet med et øyeblikk. Dokumentasjon er like viktig som selve koden. Selv en kort kommentar over hvert keyframe-token kan spare timer med gjetting senere. En utvikler skal kunne åpne tokens-filen, skanne etter effekten de trenger, og kopiere bruksmønsteret rett inn i komponenten deres. Fleksibilitet er det som gjør denne tilnærmingen verdt innsatsen. Ved å eksponere fornuftige tilpassede egenskaper gir vi teamene rom til å tilpasse animasjonen uten å ødelegge systemet. Prøv samtidig å ikke overkomplisere. Sørg for knottene som betyr noe, og hold resten oppriktig. Til slutt, husk tilgjengelighet. Ikke alle animasjoner trenger et alternativ med redusert bevegelse, men mange gjør det. Å bake inn disse justeringene tidlig betyr at vi aldri trenger å ettermontere dem senere, og det viser et nivå av omsorg som brukerne våre vil legge merke til selv om de aldri nevner det.
Etter min erfaring er det å behandle keyframes-tokens som en del av arbeidsflyten vår for designtokens det som får dem til å feste seg. Når de først er på plass, slutter de å føle seg som spesialeffekter og blir en del av designspråket, en naturlig forlengelse av hvordan produktet beveger seg og reagerer. Innpakning Animasjoner kan være en av de mest gledelige delene av å bygge grensesnitt, men uten struktur kan de også bli en av de største kildene til frustrasjon. Ved å behandle nøkkelbilder som tokens tar du noe som vanligvis er rotete og vanskelig å administrere og gjør det til et klart, forutsigbart system. Den virkelige verdien er ikke bare å lagre noen få linjer med kode. Det er i tillit til at når du bruker en fade, lysbilde, zoom eller spinn, vet du nøyaktig hvordan den vil oppføre seg på tvers av prosjektet. Det er i fleksibiliteten som kommer fra tilpassede egenskaper uten kaoset av endeløse variasjoner. Og det er i tilgjengeligheten innebygd i grunnlaget snarere enn lagt somen ettertanke. Jeg har sett disse ideene fungere i forskjellige team og forskjellige kodebaser, og mønsteret er alltid det samme. Når tokenene er på plass, slutter keyframes å være en spredt samling av triks og blir en del av designspråket. De får produktet til å føles mer tilsiktet, mer konsistent og mer levende. Hvis du tar én ting fra denne artikkelen, la det være dette: animasjoner fortjener samme omsorg og struktur som vi allerede gir til farger, typografi og avstand. En liten investering i keyframes-tokens lønner seg hver gang grensesnittet ditt beveger seg.