Jeg har nylig laget et murveggmønster som en del av min #PetitePatterns serie, en utfordring der jeg lager organiske mønstre eller teksturer i SVG innenfor 560 byte (eller omtrent på størrelse med to tweets). For å passe denne begrensningen har jeg gått gjennom en reise som har lært meg noen radikale måter å optimalisere SVG-mønstre på, slik at de inneholder så lite kode som mulig uten å påvirke den generelle bildekvaliteten.
Jeg vil lede deg gjennom prosessen og vise deg hvordan vi kan ta et SVG-mønster som starter på 197 byte helt ned til bare 44 byte – en gigantisk reduksjon på 77.7 %!
SVG-mønsteret
Dette er det som kalles et "løpende bånd" mursteinsmønster. Det er det vanligste mursteinsmønsteret der ute, og et du sikkert har sett før: hver rad med murstein er forskjøvet med halvparten av lengden på en murstein, og skaper et gjentatt forskjøvet mønster. Ordningen er ganske enkel, noe som gjør SVG-er <pattern>
element som passer perfekt for å reprodusere det i kode.
SVG <pattern>
elementet bruker et forhåndsdefinert grafisk objekt som kan replikeres (eller "flises") med faste intervaller langs den horisontale og vertikale aksen. I hovedsak definerer vi et rektangulært flismønster, og det blir gjentatt for å male fyllområdet.
Først, la oss angi dimensjonene til en murstein og gapet mellom hver murstein. For enkelhets skyld, la oss bruke rene, runde tall: en bredde på 100
og en høyde på 30
for mursteinen, og 10
for de horisontale og vertikale gapene mellom dem.
Deretter må vi identifisere vår "base" flis. Og med "flis" snakker jeg om mønsterfliser i stedet for fysiske fliser, for ikke å forveksle med klossene. La oss bruke den uthevede delen av bildet ovenfor som mønsterflisen vår: to hele klosser i den første raden, og en hel klemt mellom to halvklosser i den andre raden. Legg merke til hvordan og hvor hullene er inkludert, fordi de må inkluderes i den gjentatte mønsterflisen.
Når du bruker <pattern>
, må vi definere mønsterets width
og height
, som tilsvarer bredden og høyden på grunnflisen. For å få dimensjonene trenger vi litt matematikk:
Tile Width = 2(Brick Width) + 2(Gap) = 2(100) + 2(10) = 220
Tile Height = 2(Bright Height) + 2(Gap) = 2(30) + 2(10) = 80
Ok, så mønsterflisen vår er 220✕80
. Vi må også stille inn patternUnits
attributt, hvor verdien userSpaceOnUse
betyr egentlig piksler. Til slutt legger du til en id
til mønsteret er nødvendig slik at det kan refereres til når vi maler et annet element med det.
<pattern id="p" width="220" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
Nå som vi har etablert flisdimensjonene, er utfordringen å lage koden for flisen på en måte som gjengir grafikken med minst mulig antall byte. Dette er hva vi håper å ende opp med helt til slutt:
Innledende markering (197 byte)
Den enkleste og mest deklarative tilnærmingen til å gjenskape dette mønsteret som kommer til meg er å tegne fem rektangler. Som standard er fill
av et SVG-element er svart og stroke
er gjennomsiktig. Dette fungerer bra for å optimalisere SVG-mønstre, siden vi ikke eksplisitt trenger å deklarere de i koden.
Hver linje i koden nedenfor definerer et rektangel. De width
og height
er alltid satt, og x
og y
posisjoner settes bare hvis et rektangel er forskjøvet fra 0
stilling.
<rect width="100" height="30"/>
<rect x="110" width="100" height="30"/>
<rect y="40" width="45" height="30"/>
<rect x="55" y="40" width="100" height="30"/>
<rect x="165" y="40" width="55" height="30"/>
Den øverste raden av flisen inneholdt to klosser i full bredde, den andre klossen er plassert til x="110"
tillate 10
piksler av gap før mursteinen. På samme måte er det 10
piksler av gap etter, fordi mursteinen slutter kl 210
piksler (110 + 100 = 210
) på den horisontale aksen selv om <pattern>
bredde er 220
piksler. Vi trenger litt ekstra plass; ellers ville den andre klossen smeltet sammen med den første klossen i den tilstøtende flisen.
Klossene i den andre (nederste) raden er forskjøvet slik at raden inneholder to halve klosser og en hel kloss. I dette tilfellet vil vi at klossene med halv bredde skal smelte sammen slik at det ikke er noe gap i starten eller slutten, slik at de kan flyte sømløst med klossene i tilstøtende mønsterfliser. Når vi utligner disse klossene, må vi også inkludere halve hull, og dermed x
verdier er 55
og 165
Hhv.
Gjenbruk av element, (-43B, totalt 154B)
Det virker ineffektivt å definere hver kloss så eksplisitt. Er det ikke en måte å optimalisere SVG-mønstre ved å gjenbruke formene i stedet?
Jeg tror ikke det er allment kjent at SVG har en <use>
element. Du kan referere til et annet element med det og gjengi det refererte elementet hvor som helst <use>
benyttes. Dette sparer ganske mange byte fordi vi kan utelate å spesifisere bredden og høyden til hver kloss, bortsett fra den første.
Med det sagt, <use>
kommer med en liten pris. Det vil si at vi må legge til en id
for elementet vi ønsker å gjenbruke.
<rect id="b" width="100" height="30"/>
<use href="#b" x="110"/>
<use href="#b" x="-55" y="40"/>
<use href="#b" x="55" y="40"/>
<use href="#b" x="165" y="40"/>
Den korteste id
mulig er ett tegn, så jeg valgte "b" for murstein. De <use>
element kan plasseres på samme måte som <rect>
, Med den x
og y
attributter som forskyvninger. Siden hver kloss har full bredde nå som vi har byttet til <use>
(husk at vi eksplisitt halverte klossene i den andre raden av mønsterflisen), vi må bruke en negativ x
verdi i den andre raden, og sørg for at den siste klossen renner over fra flisen for den sømløse forbindelsen mellom klossene. Disse er imidlertid ok, fordi alt som faller utenfor mønsterflisen blir automatisk kuttet av.
Kan du se noen gjentatte strenger som kan skrives mer effektivt? La oss jobbe med de neste.
Omskriver til bane (-54B, 100B totalt)
<path>
er sannsynligvis det kraftigste elementet i SVG. Du kan tegne omtrent hvilken som helst form med "kommandoer" i d
Egenskap. Det er 20 kommandoer tilgjengelig, men vi trenger bare de enkleste for rektangler.
Her er hvor jeg landet med det:
<path d="M0 0h100v30h-100z M110 0h100v30h-100 M0 40h45v30h-45z M55 40h100v30h-100z M165 40h55v30h-55z"/>
Jeg vet, veldig rare tall og bokstaver! De har alle mening, selvfølgelig. Her er hva som skjer i dette spesifikke tilfellet:
M{x} {y}
: Flytter til et punkt basert på koordinater.z
: Lukker gjeldende segment.h{x}
: Tegner en horisontal linje fra gjeldende punkt, med lengden påx
i retningen definert av tegnet påx
. Små bokstaverx
indikerer en relativ koordinat.v{y}
: Tegner en vertikal linje fra gjeldende punkt, med lengden påy
i retningen definert av tegnet påy
. Små bokstavery
indikerer en relativ koordinat.
Denne markeringen er mye mer kortfattet enn den forrige (linjeskift og mellomrom med innrykk er kun for lesbarhet). Og hei, vi har klart å kutte ut halvparten av den opprinnelige størrelsen, og nådde 100 byte. Likevel er det noe som får meg til å føle at dette kan være mindre...
Tile revisjon (-38B, 62B totalt)
Har ikke mønsterflisen vår repeterende deler? Det er tydelig at i den første raden gjentas en hel murstein, men hva med den andre raden? Det er litt vanskeligere å se, men hvis vi kutter den midterste mursteinen i to blir det tydelig.
Vel, den midterste mursteinen er ikke akkurat kuttet i to. Det er en liten forskyvning fordi vi også må ta hensyn til gapet. Uansett, vi har nettopp funnet et enklere grunnflisemønster, som betyr færre byte! Dette betyr også at vi må halvere width
av vår <pattern>
element fra 220 til 110.
<pattern id="p" width="110" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
La oss nå se hvordan den forenklede flisen er tegnet med <path>
:
<path d="M0 0h100v30h-100z M0 40h45v30h-45z M55 40h55v30h-55z"/>
Størrelsen er redusert til 62 byte, som allerede er mindre enn en tredjedel av den opprinnelige størrelsen! Men hvorfor stoppe her når det er enda mer vi kan gjøre!
Forkorte banekommandoer (-9B, totalt 53B)
Det er verdt å komme litt dypere inn i <path>
element fordi det gir flere hint for å optimalisere SVG-mønstre. En misforståelse jeg har hatt når jeg har jobbet med <path>
handler om hvordan fill
attributtet fungerer. Etter å ha lekt mye med MS Paint i barndommen, har jeg lært at enhver form jeg ønsker å fylle med en solid farge må lukkes, dvs. ikke ha åpne punkter. Ellers vil malingen lekke ut av formen og søle over alt.
I SVG er dette imidlertid ikke sant. La meg sitere spesifikasjonen seg selv:
Fylloperasjonen fyller åpne underbaner ved å utføre fylloperasjonen som om en ekstra "lukkebane"-kommando ble lagt til banen for å koble det siste punktet i underbanen med det første punktet i underbanen.
Dette betyr at vi kan utelate kommandoene for lukke bane (z
), fordi underbanene anses som automatisk lukket når de er fylt ut.
En annen nyttig ting å vite om banekommandoer er at de kommer i store og små bokstaver. Små bokstaver betyr at relative koordinater brukes; store bokstaver betyr at absolutte koordinater brukes i stedet.
Det er litt vanskeligere enn det med H
og V
kommandoer fordi de bare inkluderer én koordinat. Slik vil jeg beskrive disse to kommandoene:
H{x}
: Tegner en horisontal linje fra gjeldende punkt for å koordinerex
.V{y}
: Tegner en vertikal linje fra gjeldende punkt for å koordinerey
.
Når vi skal tegne den første mursteinen i mønsterflisen, starter vi fra (0,0)
koordinater. Vi tegner så en horisontal linje til (100,0)
og en vertikal linje til (100,30)
, og til slutt tegner du en horisontal linje til (0,30)
. Vi brukte h-100
kommando i siste linje, men det tilsvarer H0
, som er to byte i stedet for fem. Vi kan erstatte to lignende forekomster og parere koden til vår <path>
ned til dette:
<path d="M0 0h100v30H0 M0 40h45v30H0 M55 40h55v30H55"/>
Ytterligere 9 byte barbert - hvor mye mindre kan vi gå?
Brobygging (-5B, totalt 48B)
De lengste kommandoene som står i veien for et fullt optimalisert SVG-mønster er "flytt til"-kommandoene som tar opp henholdsvis 4, 5 og 6 byte. En begrensning vi har er at:
Et banedatasegment (hvis det er et) må begynne med en "moveto"-kommando.
Men det er greit. Den første er den korteste uansett. Bytter vi på radene kan vi komme opp med en banedefinisjon der vi bare trenger å bevege oss enten horisontalt eller vertikalt mellom klossene. Hva om vi kunne bruke h
og v
kommandoer der i stedet for M
?
Diagrammet ovenfor viser hvordan de tre figurene kan tegnes med en enkelt bane. Merk at vi utnytter det faktum at fill
drift lukker automatisk den åpne delen mellom (110,0)
og (0,0)
. Med denne omorganiseringen flyttet vi også gapet til venstre for klossen i full bredde i den andre raden. Slik ser koden ut, fortsatt delt inn i én kloss per linje:
<path d="M0 0v30h50V0 h10v30h50 v10H10v30h100V0"/>
Sikkert, vi har funnet den absolutt minste løsningen nå som vi er nede på 48 byte, ikke sant?! Vi vil…
Siffertrimming (-4B, 44B totalt)
Hvis du kan være litt fleksibel med dimensjonene, er det en annen liten måte vi kan optimalisere SVG-mønstre på. Vi har jobbet med en mursteinsbredde på 100
piksler, men det er tre byte. Endre det til 90
betyr én byte mindre når vi trenger å skrive den. På samme måte brukte vi et gap på 10
piksler - men hvis vi endrer det til 8
i stedet lagrer vi en byte på hver av disse forekomstene.
<path d="M0 0v30h45V0 h8v30h45 v8H8v30h90V0"/>
Dette betyr selvfølgelig også at vi må justere mønsterdimensjonene deretter. Her er den endelige optimaliserte SVG-mønsterkoden:
<pattern id="p" width="98" height="76" patternUnits="userSpaceOnUse"> <path d="M0 0v30h45V0h8v30h45v8H8v30h90V0"/>
</pattern>
Den andre linjen i utdraget ovenfor – uten å telle innrykk – er 44 bytes. Vi kom hit fra 197 byte i seks iterasjoner. Det er en tykk 77.7 % størrelsesreduksjon!
Jeg lurer på... er dette virkelig den minste størrelsen som er mulig? Har vi sett på alle mulige måter å optimalisere SVG-mønstre på?
Jeg inviterer deg til å prøve å forminske denne koden ytterligere, eller til og med eksperimentere med alternative metoder for å optimalisere SVG-mønstre. Jeg ville elske å se om vi kunne finne det sanne globale minimum med mengden visdom!
Mer om å lage og optimalisere SVG-mønstre
Hvis du er interessert i å lære mer om å lage og optimalisere SVG-mønstre, les artikkelen min om lage mønstre med SVG-filtre. Eller, hvis du vil sjekke ut et galleri med 60+ mønstre, kan du se PetitePatterns CodePen Collection. Til slutt er du velkommen til å se mine opplæringsprogrammer på YouTube for å hjelpe deg med å komme enda dypere inn i SVG-mønstre.
Optimalisering av SVG-mønstre til deres minste størrelse opprinnelig publisert på CSS-triks. Du burde få nyhetsbrevet.
- "
- 10
- 100
- 77
- 9
- 98
- Om oss
- Absolute
- Logg inn
- Ytterligere
- Alle
- tillate
- allerede
- En annen
- tilnærming
- AREA
- Artikkel
- attributter
- tilgjengelig
- AKSER
- Bit
- Svart
- utfordre
- endring
- stengt
- kode
- Felles
- tilkobling
- inneholder
- innhold
- koordinere
- kunne
- Opprette
- Gjeldende
- dato
- dypere
- ned
- slutter
- etablert
- alt
- eksempel
- Unntatt
- eksperiment
- Endelig
- Først
- passer
- flyten
- funnet
- videre
- mellomrom
- få
- Global
- å ha
- høyde
- hjelpe
- her.
- Fremhevet
- Hvordan
- HTTPS
- identifisere
- bilde
- inkludere
- inkludert
- IT
- selv
- kjent
- lekke
- LÆRE
- lært
- utnytte
- linje
- lite
- så
- elsker
- GJØR AT
- Making
- fikk til
- math
- tankene
- mer
- mest
- flytte
- MS
- Antall
- tall
- offset
- Okay
- åpen
- optimalisert
- ellers
- Mønster
- fysisk
- Point
- posisjonert
- mulig
- kraftig
- pen
- pris
- prosess
- gir
- kvalitet
- runde
- rennende
- Sa
- sømløs
- Serien
- sett
- figurer
- lignende
- Enkelt
- SIX
- Størrelse
- So
- løsning
- noe
- Rom
- Spot
- Begynn
- starter
- Støttes
- snakker
- Gjennom
- topp
- gjennomsiktig
- tutorials
- bruke
- verdi
- Se
- W3
- Se
- velkommen
- Hva
- innenfor
- uten
- Arbeid
- arbeid
- virker
- verdt
- youtube