Hur man animerar festliga SVG-ikoner med CSS

"Tis säsongen, så i denna handledning går jag igenom att skapa några CSS animerade, semester-tema, SVG ikoner. Det finns några bra ikoner på Iconmelon, en webbplats som är värd för många gratis vektorikonsatser för att du ska sänka dina tänder i. Ikonerna jag använder är artighet av designern Sam Jones. Så tag dig en kopp eggnog, dra din bärbara dator upp till yule loggen, och låt oss komma igång!

SVG och webben

Om du är intresserad av att använda SVG på webben, är ikoner ett bra ställe att börja. SVGs är flexibla, upplösningsoberoende och lättviktiga, så ikoner låter sig naturligtvis till vektorformatet. Plus, precis som HTML, kan SVGs enkelt utformas med CSS, vilket inkluderar CSS3-animering. Lägga till ett streck av interaktivitet med animering till dina ikoner kan hjälpa till att skapa en härlig upplevelse för dina användare och även lägga till sammanhang om vad en ikon representerar.

För en introduktion på SVG och på webben, ta en titt på SVG-filer: Från Illustrator till webben.

Notera: Följande demos använder avancerad teknik som från och med det här skrivandet inte stöds i vissa webbläsare som Internet Explorer. Om du följer med handledningen är det bäst om du använder Chrome eller Safari. Mozilla support är fullt möjligt med lämpliga egendom prefix. Du kan säkert förvänta dig stöd för dessa tekniker för att förbättra i framtiden.

Dessutom: I den här artikeln har jag utelämnat några nödvändiga webbläsarprefix från vissa CSS-egenskaper för koncision och läsbarhet. Kolla in prefixfree-biblioteket av Lea Verou om du vill skriva prefixfri CSS enkelt. Du kan också försöka skapa dina demo på Codepen, som enkelt kan konfigureras för att använda prefixfree.


Förbereder SVG-kod för redigering

En av de största banorna på SVG är att koden är svår att hantera. SVG-koden som exporteras av Illustrator, valfri vektorgrafikredigerare, är ganska oläslig vid första anblicken. Inkscape gör faktiskt ett bättre jobb med att exportera SVG i detta avseende, men jag har funnit att förenkling och formatering av koden kan gå långt för att göra koden lättare att läsa och arbeta med.

Här är SVG-koden för det första animationsexemplet jag ska visa, ett blinkande julljus.

        

Koden exporterades från mitt vektorredigeringsverktyg, Adobe Illustrator. Det är nästan oläsligt vid första anblicken. Här är samma förhandsgranskning förenklad:

     

Jag har väsentligt förenklat denna xml genom att ta bort mycket av den extra markup som programmet utmatar som standard. Mitt bas SVG-element innehåller följande:

  • En klass: svg-ljus. Jag har använt svg- prefix för att enkelt rikta in element i en specifik SVG.
  • De viewbox fast egendom. Värdet av viewbox egenskapen definierar dokumentets bildförhållande och motsvarar storleken på tavlan i Illustrator.
  • De xmnls fast egendom. Den här egenskapen definierar XML-namnrymden för SVG och hjälper vissa användare att förstå markeringen.

Till de element som ligger inuti SVG som definierar de former som utgör bilden, t.ex. banorcirklar och rättar, Jag har tillämpat klasser inline med sin öppnings tagg. Alla elementets inlineegenskaper, till exempel deras koordinater, har jag brutit till nya rader. Dessutom har jag inryckt alla inre element under SVG-bastaggen.

Allt detta arbete är av en anledning. Först och främst gör det koden mycket lättare att läsa. För det andra kan jag i min kodredigerare, Sublime Text 3, enkelt vikla enskilda SVG-element eller hela SVG medan klassnamnen fortfarande hjälper till att behålla kontext om vad dessa element är.


Kodviktning av SVG i Sublime Text 3

Julbelysning

Okej, låt oss komma in i semesterandan och animera ett blinkande julljus! Här är vad vi ska se för att uppnå:

Se penna ljuset av Noah Blon (@noahblon) på CodePen

Vad jag vill göra är att animera banelementet som jag har givit en klass av Glödlampa i SVG.

 

Med CSS ger jag glödlampan en fyllfärg och definierar dess animeringsegenskaper.

 .svg-light .bulb fill: hsl (204, 70%, 23%); animationsnamn: glödblå; animeringstid: 1s; animations-iteration-count: oändlig; animation-timing-funktion: lätt-in-out; animationsriktning: alternativ; 

De fylla egendom tillåter oss att ange ett SVG-elements färg. När det är möjligt, gillar jag att använda HSL (färgton, mättnad, ljushet) för att definiera färgvärden eftersom det är väldigt intuitivt att arbeta med. Här har jag valt en blå färg (nyans 204) och håller ljusvärdet lågt, 23%, vilket betyder att vi får en mörkblå färg.

Jag har satt lampan för att animeras av en keyframe-animering som heter glöd-blue. Animationens varaktighet är 1 sekund. Animeringen iterates oändligt, vilket betyder att det kommer att springa för alltid. Animeringens tidpunkt lindras i början och slutet av nyckelramarna, vilket ger en jämnare övergång vid animationens start- och slutpunkter. Slutligen är animeringen inställd på alternativ, vilket betyder att den kommer att gå fram och tillbaka från början till slutet och tillbaka igen.

Tips: Du kanske vet att det finns en kortfattad syntax för CSS-animeringsregler, men jag brukar föredra att dela ut reglerna så att de blir enklare att förstå, modifiera och dela om att kedja flera animeringar.

Nu ska jag definiera glöd-blue keyframe animation:

 @keyframes glödblå 0% fill: hsl (204, 80%, 23%);  100% fill: hsl (204, 80%, 63%); 

Här har jag satt start- och slutfyllningsfärgen på det element som den här animationen appliceras på. Det enda värdet som ändras är ljusets ljushet ("l" -biten i hsl), vilket innebär att ljuset kommer att animera från en mörkare till lättare version av samma färgton. Det är den intuitiva syntaxen som HSL tillhandahåller.

Eftersom jag har definierat animationen för att växla oändligt, kommer ljuset att växla från mörkt till ljus och sluta aldrig. Det verkar därför blinka.

Animera flera ljus

OK, nu kan vi kanalisera vår inre Clark W. Griswold och animera en hel massa julljus. Detta är vad jag ska skapa:

Se Penna 540257e4a8b727e435c8e4033602ebb0 av Noah Blon (@noahblon) på CodePen

Jag har skapat fem olika färgade ljus. Varje ljus är inslaget i en div med en bredd på 20%. Dessa div divideras sedan till vänster så att de förefaller inline med varandra. Eftersom jag inte har ställt in SVG för att vara en bestämd höjd eller bredd och behållt egenskapen viewbox är SVG flytande till storleken på dess förälder utan att förlora dess bildförhållande eller kvalitet. Bara en av SVGs stora styrkor.

 

För varje SVG har jag utökat bas svg-ljus klassen med ett färg suffix (till exempel svg-light-red). Här är ett utdrag av de regler som jag har använt för att animera de många lamporna:

 .svg-light .bulb animation-duration: 1s; animations-iteration-count: oändlig; animation-timing-funktion: lätt-in-out; animationsriktning: alternativ;  .svg-light - röd .bulb fill: hsl (6, 63%, 16%); animationsnamn: glödröd animationsfördröjning: .5s; animeringstid: 1,25 s;  @keyframes glow-red 0% fill: hsl (6, 63%, 16%);  100% fyll: hsl (6, 63%, 56%); 

De grundläggande animeringsegenskaperna tillämpas fortfarande på basklassen av svg-ljus så att de kan delas mellan alla ljus. För varje färgvariation har jag skapat en annan keyframe-animation som glöd-röd eller glöd-blue och gav dem olika animationsfördröjningar och varaktigheter. På så sätt blinkar lamporna med lämplig färg och alla blinkar inte samtidigt.


Rudolf med röda mulen

Jag använder samma begrepp som jag har beskrivit ovan för att animera Rudolphs mest berömda ren. Här är slutresultatet:

Se Penna SVG Rudolph Icon Animerad med CSS av Noah Blon (@noahblon) på CodePen

Först ska jag animera hans glödande röda näsa:

 .svg-rudolph .nose animation-name: glow; animeringstid: 6s; animations-iteration-count: oändlig; animation-timing-funktion: lätt-in-out; animationsriktning: alternativ;  @keyframes glöder 0% fill: hsl (6, 93%, 16%);  50% fill: hsl (6, 93%, 56%);  100% fyll: hsl (6, 93%, 56%); 

Det här ser ganska ut som vårt julljus. I keyframe-animationen animerar jag till 50% och sedan till 100%. Eftersom animeringstiden är sex sekunder betyder det att näsan blir trefärgad på tre sekunder och förblir den färgen i ytterligare tre sekunder till slutet av animationen. Också, för att jag har satt animationen till alternerande, kommer den nu att gå från slutet till början. Därför kommer näsan att vara full röd i ytterligare tre sekunder innan den slutligen mörknar under de senaste tre sekunderna. Förstå samspelet mellan keyframe-procentenheterna och animationsdefinitionerna, såsom varaktigheten, är nyckeln till att skapa effektiva CSS-animeringar.

Jag har också applicerat en övergång till höjdpunkten på Rudys näsa:

 .svg-rudolph. nose-highlight fill-opacity: 0; animationsnamn: highlight-fade; animeringstid: 6s; animations-iteration-count: oändlig; animation-timing-funktion: lätt-in-out; animationsriktning: alternativ;  @keyframes highlight-fade 0% fill-opacity: 0;  25% fyll-opacitet: 0;  100% fill-opacity: 1; 

Här animerar jag en annan SVG-egenskap, den fyll-opacitet. Den här egenskapen tar ett värde mellan 0 och 1; 0 är helt transparent, 1 är helt ogenomskinlig. Slutligen ska jag ta lite mer liv till Rudy genom att ögonblicken blinkar:

 .svg-rudolph .eye animation-name: blink; animeringstid: 8s; animations-iteration-count: oändlig; transformations-ursprung: 50%;  @keyframes blink 0% transform: scaleX (1) scaleY (1);  1% transform: skalaX (1,3) skala Y (0,1);  2% transform: skalaX (1) skala Y (1);  60% transform: skalaX (1) skala Y (1);  61% transform: skalaX (1.3) skalaY (0,1); 62% transform: skalaX (1) skalaY (1);  100% transform: skalaX (1) skala Y (1); 

Jag har skapat en animerad bild blinka. Denna animering körs i åtta sekunder och slutar aldrig. Jag byter inte animeringen denna gång, istället kommer animationen att gå till slutet och starta om från början.

I keyframes skapas den blinkande animationen genom att man manipulerar ögonskalan på X- och Y-axlarna. Till exempel vid 1% -markeringen skalas ögonen till 1,3 sin storlek på X-axeln och .1 gånger sin normala storlek på Y-axeln. Med andra ord blir de lite bredare och mycket kortare. En procent av animationsvaraktigheten senare återgår ögonskalan till normal. Skalförändringen sker därför extremt snabbt. 8 sekunder / 100 = 8 hundra sekunder av en sekund.

En nyckelkomponent i att använda transform för att animera SVG-element är att ställa in elementen transform-ursprung. I de flesta fall måste vi, för att en transform ska tillämpas korrekt i ett SVG, definiera omvandlingskoordinatens ursprung för att vara centrum för elementet. Till skillnad från det för ett HTML-element är omvandlingsvärdet för ett SVG-element som standard sitt övre vänstra hörn, (0,0) -koordinaten. Genom att ställa omvandlings-ursprung till (50%, 50%) kommer ursprunget för transformens X- och Y-axel att ligga i mitten av elementet, och omvandlingar kommer sedan att appliceras korrekt.

Notera: Firefox har problem när det gäller att omvandla ursprung. Tyvärr återställer transformationsuppkomsten till 50% faktiskt X / Y-koordinaterna för elementet. Ett arbete är att omvandla elementet tillbaka till sin ursprungliga position.


Ding Dong Merrily på High

För den här demoen ska jag animera en klocka som ringer så här:

Se Penna 63cdc3e8e785028deb35132d889b6090 av Noah Blon (@noahblon) på CodePen

Låt oss ta en titt på ett utdrag av SVG-markeringen:

           

Jag har lindat klockan och fyller med a (eller grupp) tagg. Den här taggen är väldigt användbar för att organisera element, som liknar hur du kan lägga in flera HTML-element med en

. Animationer kan tillämpas på en grupp. Eftersom jag i detta fall vill att både fyllning och kontur av klockan roterar, kan jag bara rotera gruppen istället för varje element individuellt.

 .svg-bell. group-bell animation-name: bell-ring; animeringstid: 3s; animations-iteration-count: oändlig; animation-timing-funktion: lätt-in-out; animationsfördröjning: -1.5s; animationsriktning: alternativ; transformations-ursprung: 50%;  @keyframes bell-ring 0% transform: rotera (27deg);  100% transform: rotera (-27deg); 

Denna CSS ska vara bekant nu, men det är ett par nya saker som händer. Först, i keyframe-animationen, omvandlas klockan, men istället för transformationsskala omvandlar jag elementets rotationsvärde. Denna animering gör att bellen oscillerar mellan 27 och -27 grader.

Det andra nya jag har gjort är att använda ett negativt värde för animering-fördröjning. Ett negativt värde gör att animeringen börjar så mycket tid i animationen. I det här fallet, istället för animeringen som börjar efter en 1,5 sekunders fördröjning, startar animationen faktiskt 1,5 sekunder i animationen. Genom att göra detta startar klockan i neutralläge, som det är vid 1,5 sekunder in i animationen, snarare än vid det roterade läget, som det är vid 0 sekunder i animationen.

 .svg-bell .striker animation-name: striker-move; animeringstid: 3s; animations-iteration-count: oändlig; animation-timing-funktion: linjär; animationsfördröjning: 1,5s; animationsriktning: alternativ; transformations-ursprung: 50%;  @keyframes anfallshållare 0% transform: translateX (3px);  100% transform: translateX (-3px); 

Jag har applicerat en liknande animering till gruppen som innehåller klockans stridselement. Den här gången översätter jag emellertid eller flyttar elementen längs X-axeln i stället för att rotera, så anfallaren svänger åt vänster och höger.


Låt det snöa! Låt det snöa! Låt det snöa!

För denna animering kommer jag att animera snö som faller in i en snöklot.

Se Penna 2addb5f98c757d61cec87bdcacb5870d av Noah Blon (@noahblon) på CodePen

Jag har skapat en massa cirkelelement för att representera snö, och jag har placerat dessa element runt snögubben, omsluter dem i en märka.

Snön är inte synlig utanför snögubben eftersom jag har applicerat en urklippsbana till gruppen som innehåller snön. En urklippsbana är en form som kan appliceras på SVG-element, maskerar andra inom den. I vårt exempel på jordklot har jag skapat en cirkulär urklippsbana som täcker världens inre.

     

De taggen är vårt maskeringselement, för att effektuera det måste vi ge det ett ID.

Jag har lindat klippningen i en defs märka. SVG tillåter oss att skapa element som vi kan återanvända senare, t.ex. urklippsbanor, filter eller former som vi kan stämpla ut. Det är bästa praxis att lägga in definitioner som klickvägar i en defs-tagg så att SVG lättare kan läsas.

För att tillämpa klippningen hänvisar vi till dess url, i det här fallet är dess ID föregånget av en hash-symbol i egenskapen för inline-urklipp av ett SVG-element:

          

Snön är nu bara synlig inuti den cirkulära klippvägen.

Snön är animerad med samma teknik som jag har beskrivit tidigare; översatt längs Y-axeln och fyllningsopaciteten närmar sig noll då animationen slutar.

 .svg-snowglobe .snow animation-name: snowfall; animations-varaktighet: 10s; animations-iteration-count: oändlig; animation-timing-funktion: inlämning  .svg-snowglobe .snow: nth-child (1) animation-delay: 2s;  .svg-snowglobe .snow: nth-child (2) animation-delay: 4s;  .svg-snowglobe .snow: nth-child (3) animation-delay: 6s;  .svg-snowglobe .snow: nth-child (4) animation-delay: 8s;  .svg-snowglobe .snow: nth-child (5) animation-delay: 10s;  .svg-snowglobe .snow: nth-child (6) animation-delay: 12s;  .svg-snowglobe .snow: nth-child (7) animation-delay: 14s;  .svg-snowglobe .snow: nth-child (8) animation-delay: 16s;  .svg-snowglobe .snow: nth-child (9) animation-delay: 18s;  .svg-snowglobe .snow: nth-child (10) animation-delay: 20s; 

Ja, CSS3-väljare arbetar med SVG-element! Här har jag givit varje snöelement en annan fördröjning så att de inte alla kommer att falla på en gång.


Säsong hälsningar

Slutligen ska jag animera lite SVG-baserad text för att få ett resultat så här:

Se Penna Meddelandet av Noah Blon (@noahblon) på CodePen

SVG ger oss möjlighet att tillämpa streck på SVG-element med CSS. För min sista animation visar jag dig hur man gradvis ritar ett elements stroke.

För att uppnå denna animering har jag använt följande slagegenskaper:

  • stroke-bredd: streckets bredd. Detta är i förhållande till SVG: s storlek och därför lyhörd.
  • stroke: Streckets färg.
  • stroke-dasharray: definierar en streckad stroke. En rad växelvärden definierar längden på de streckade delarna av streckad linje och det tomma utrymmet mellan bindestreck.
  • stroke-dashoffset: definierar var stroken startar i förhållande till banans längd.

Om du ställer in en streckad text krävs lite arbete i en grafikredigerare. Mitt arbetsflöde är enligt följande:

  1. Skapa ett textelement.
  2. Konvertera texten till vektorvägar.
  3. Slå samman dessa vägar i en sammansatt väg.

Här är min CSS för att ställa in animeringen:

 .svg-message .text stroke-width: 1px; stroke: hsl (6, 63%, 36%); stroke-dasharray: 1865.753px 1865.753px; stroke-dashoffset: 1865.753px; fyll-opacitet: 0; fyll: hsl (6, 63%, 36%); animationsnamn: stroke, fill; animeringstid: 1s; animationsfördröjning: 0, 1s; animations-iteration-count: 1; animation-timing-funktion: lätt-in-out; animations-fyll-läge: framåt;  @keyframes fadeIn 0% fill-opacity: 0;  100% fill-opacity: 1;  @keyframes drawStroke 100% stroke-dashoffset: 0

Jag har definierat stroke-dasharray egenskapen som längden på den totala vägen (du kan hitta det här värdet i Illustrator under Dokumentinfo Palette med objektet Objekt). Sedan har jag gett stroke-dashoffset ett värde av banans totala längd, vilket skjuter hela stroke ur synlighet. Då, genom keyframe animering av stroke-dashoffset egenskapen kommer strejken gradvis att dra sig på skärmen.

Om du vill lära dig mer om den här tekniken kan du kolla in Jake Archibalds post Animerade linjeteckning i SVG.

Jag har också satt texten för att blekna in efter att linjeläget har slutförts, med egenskapen fyllbarhet som liknar vad jag gjorde tidigare med snögubbeanimationen.


Går vidare med SVG och CSS

I denna handledning har jag visat att med CSS och SVG kan du skapa några ganska effektiva animeringar. Om du vill fastna med hela koden, liksom några ytterligare animeringar, kan du ladda ner exemplen från Github eller kolla min samling på Codepen.

Om du vill bli mer avancerad kan du utforska kontrollerande CSS-animationer med JavaScript eller komplettera dina CSS-animationer med mer komplex JavaScript-animering, som det stöds av det fantastiska SVG JS-biblioteket Snap SVG.

Tack för att du följer med denna handledning, jag kan inte vänta med att se de skapelser du kommer med!