Niedawno stworzyłem wzór ściany z cegły w ramach mojego #MałeWzory seria, wyzwanie, w którym tworzę organicznie wyglądające wzory lub tekstury w SVG o rozmiarze 560 bajtów (lub mniej więcej wielkości dwóch tweetów). Aby dopasować się do tego ograniczenia, odbyłem podróż, która nauczyła mnie kilku radykalnych sposobów optymalizacji wzorców SVG, tak aby zawierały jak najmniej kodu bez wpływu na ogólną jakość obrazu.
Chcę przeprowadzić cię przez ten proces i pokazać, jak możemy wziąć wzór SVG, który zaczyna się od 197 bajtów, aż do zaledwie 44 bajtów — oszałamiająca redukcja o 77.7%!
Wzór SVG
Jest to tak zwany wzór cegieł z „bieżącym wiązaniem”. Jest to najpopularniejszy wzór cegieł, który z pewnością widziałeś wcześniej: każdy rząd cegieł jest przesunięty o połowę długości cegły, tworząc powtarzający się wzór schodkowy. Układ jest dość prosty, dzięki czemu SVG's <pattern>
element idealnie dopasowany do odtworzenia go w kodzie.
SVG <pattern>
element wykorzystuje predefiniowany obiekt graficzny, który może być powielany (lub „układany”) w stałych odstępach wzdłuż osi poziomej i pionowej. Zasadniczo definiujemy prostokątny wzór kafelkowy i jest on powtarzany, aby pomalować obszar wypełnienia.
Najpierw ustalmy wymiary cegły i odstęp między każdą cegłą. Dla uproszczenia użyjmy czystych, okrągłych liczb: szerokość 100
i wysokość 30
za cegłę i 10
dla szczelin poziomych i pionowych między nimi.
Następnie musimy zidentyfikować nasz „podstawowy” kafelek. A mówiąc „płytka” mam na myśli płytki z wzorami, a nie fizyczne płytki, których nie należy mylić z cegłami. Użyjmy podświetlonej części powyższego obrazu jako naszej płytki z wzorem: dwie całe cegły w pierwszym rzędzie i jedną całość wciśniętą między dwie połówki cegieł w drugim rzędzie. Zwróć uwagę, w jaki sposób i gdzie uwzględniane są przerwy, ponieważ muszą one zostać uwzględnione w kafelku z powtarzającym się wzorem.
Podczas używania <pattern>
, musimy zdefiniować wzorzec width
i height
, które odpowiadają szerokości i wysokości płytki bazowej. Aby uzyskać wymiary, potrzebujemy trochę matematyki:
Tile Width = 2(Brick Width) + 2(Gap) = 2(100) + 2(10) = 220
Tile Height = 2(Bright Height) + 2(Gap) = 2(30) + 2(10) = 80
W porządku, więc nasza płytka z wzorem to 220✕80
. Musimy też ustawić patternUnits
atrybut, gdzie wartość userSpaceOnUse
zasadniczo oznacza piksele. Na koniec dodając id
do wzoru jest konieczne, aby można było się do niego odnieść podczas malowania nim innego elementu.
<pattern id="p" width="220" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
Teraz, gdy ustaliliśmy już wymiary kafelka, wyzwaniem jest stworzenie kodu dla kafelka w sposób, który renderuje grafikę z możliwie najmniejszą liczbą bajtów. Oto, co mamy nadzieję skończyć na samym końcu:
Wstępny znacznik (197 bajtów)
Najprostszym i najbardziej deklaratywnym podejściem do odtworzenia tego wzoru, który przychodzi mi do głowy, jest narysowanie pięciu prostokątów. Domyślnie fill
elementu SVG jest czarny, a stroke
jest przezroczysty. Działa to dobrze przy optymalizacji wzorców SVG, ponieważ nie musimy wyraźnie deklarować ich w kodzie.
Każda linia w poniższym kodzie definiuje prostokąt. ten width
i height
są zawsze ustawione, a x
i y
pozycje są ustawiane tylko wtedy, gdy prostokąt jest odsunięty od 0
pozycji.
<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"/>
Górny rząd płytki zawierał dwie cegły o pełnej szerokości, druga cegła jest ustawiona na x="110"
pozwalając 10
piksele przerwy przed cegłą. Podobnie jest 10
piksele przerwy po, ponieważ cegła kończy się na 210
piksele (110 + 100 = 210
) na osi poziomej, mimo że <pattern>
szerokość to 220
piksele. Potrzebujemy trochę dodatkowej przestrzeni; w przeciwnym razie druga cegła połączyłaby się z pierwszą cegłą w sąsiedniej płytce.
Cegły w drugim (dolnym) rzędzie są przesunięte tak, że rząd zawiera dwie połówki cegieł i jedną całą cegłę. W tym przypadku chcemy, aby cegiełki o połowie szerokości połączyły się, aby nie było przerwy na początku ani na końcu, co pozwoliłoby im płynnie płynąć z cegłami w sąsiednich płytkach ze wzorem. Przy odsuwaniu tych cegieł musimy również uwzględnić połówkowe szczeliny, a więc x
wartości są 55
i 165
, Odpowiednio.
Ponowne użycie elementu, (-43B, łącznie 154B)
Tak jednoznaczne zdefiniowanie każdej cegły wydaje się nieefektywne. Czy nie ma sposobu na zoptymalizowanie wzorów SVG poprzez ponowne użycie kształtów?
Nie sądzę, aby powszechnie wiadomo, że SVG ma <use>
element. Możesz odwołać się do innego elementu z nim i wyrenderować ten element, do którego się odwołuje, gdziekolwiek <use>
jest używany. Oszczędza to sporo bajtów, ponieważ możemy pominąć określanie szerokości i wysokości każdej cegły, z wyjątkiem pierwszej.
To mówi, <use>
ma niewielką cenę. Oznacza to, że musimy dodać id
dla elementu, którego chcemy ponownie użyć.
<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"/>
Najkrótszy id
możliwy jest jeden znak, więc wybrałem „b” jako cegłę. ten <use>
element można ustawić podobnie do <rect>
Z x
i y
atrybuty jako przesunięcia. Ponieważ każda cegła ma teraz pełną szerokość, po przejściu na <use>
(pamiętaj, że wyraźnie podzieliliśmy na pół cegły w drugim rzędzie płytki deseniowej), musimy użyć negatywu x
wartość w drugim rzędzie, a następnie upewnij się, że ostatnia cegła przelewa się z płytki, aby uzyskać płynne połączenie między cegłami. Są one jednak w porządku, ponieważ wszystko, co wykracza poza kafelek wzoru, jest automatycznie odcinane.
Czy potrafisz dostrzec kilka powtarzających się ciągów, które można pisać wydajniej? Popracujmy nad tymi następnymi.
Przepisywanie do ścieżki (-54B, łącznie 100B)
<path>
jest prawdopodobnie najpotężniejszym elementem SVG. Możesz narysować dowolny kształt za pomocą „polecenia” w jego d
atrybut. Dostępnych jest 20 poleceń, ale dla prostokątów potrzebujemy tylko tych najprostszych.
Oto, gdzie wylądowałem z tym:
<path d="M0 0h100v30h-100z M110 0h100v30h-100 M0 40h45v30h-45z M55 40h100v30h-100z M165 40h55v30h-55z"/>
Wiem, super dziwne cyfry i litery! Wszystkie mają znaczenie, oczywiście. Oto, co dzieje się w tym konkretnym przypadku:
M{x} {y}
: Przechodzi do punktu na podstawie współrzędnych.z
: Zamyka bieżący segment.h{x}
: Rysuje linię poziomą od bieżącego punktu o długościx
w kierunku określonym przez znakx
. Małe literyx
wskazuje współrzędną względną.v{y}
: Rysuje linię pionową od bieżącego punktu o długościy
w kierunku określonym przez znaky
. Małe literyy
wskazuje współrzędną względną.
Ten znacznik jest znacznie bardziej zwięzły niż poprzedni (podziały wierszy i białe znaki wcięcia służą tylko do czytelności). I hej, udało nam się wyciąć połowę początkowego rozmiaru, dochodząc do 100 bajtów. Jednak coś sprawia, że czuję, że to mogłoby być mniejsze…
Rewizja płytek (-38B, łącznie 62B)
Czy nasza płytka ze wzorem nie ma powtarzających się części? Widać, że w pierwszym rzędzie powtarza się cała cegła, ale co z drugim rzędem? Trochę trudniej to zobaczyć, ale jeśli przetniemy środkową cegłę na pół, stanie się to oczywiste.
Cóż, środkowa cegła nie jest dokładnie przecięta na pół. Jest niewielkie przesunięcie, ponieważ musimy również uwzględnić lukę. Tak czy inaczej, właśnie znaleźliśmy prostszy wzór kafelków bazowych, co oznacza mniej bajtów! Oznacza to również, że musimy zmniejszyć o połowę width
naszego <pattern>
element od 220 do 110.
<pattern id="p" width="110" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
Zobaczmy teraz, jak narysowany jest uproszczony kafelek <path>
:
<path d="M0 0h100v30h-100z M0 40h45v30h-45z M55 40h55v30h-55z"/>
Rozmiar zostaje zmniejszony do 62 bajtów, co stanowi już mniej niż jedną trzecią oryginalnego rozmiaru! Ale po co się tu zatrzymywać, skoro możemy zrobić jeszcze więcej!
Polecenia skracania ścieżki (-9B, 53B łącznie)
Warto zagłębić się w <path>
element, ponieważ zawiera więcej wskazówek dotyczących optymalizacji wzorców SVG. Jedno nieporozumienie, które miałem podczas pracy? <path>
dotyczy tego, w jaki sposób fill
atrybut działa. Bawiąc się dużo z MS Paint w dzieciństwie, nauczyłem się, że każdy kształt, który chcę wypełnić jednolitym kolorem, musi być zamknięty, tj. nie mieć otwartych punktów. W przeciwnym razie farba wycieknie z kształtu i rozleje się na wszystko.
Jednak w SVG nie jest to prawdą. Pozwól, że zacytuję specyfikacja się:
Operacja wypełniania wypełnia otwarte podścieżki, wykonując operację wypełniania tak, jakby do ścieżki dodano dodatkowe polecenie „zamknij ścieżkę”, aby połączyć ostatni punkt podścieżki z pierwszym punktem podścieżki.
Oznacza to, że możemy pominąć polecenia close path (z
), ponieważ podścieżki są automatycznie zamykane po wypełnieniu.
Inną przydatną rzeczą, którą należy wiedzieć o poleceniach ścieżki, jest to, że występują one w odmianach pisanych wielkimi i małymi literami. Małe litery oznaczają, że używane są współrzędne względne; wielkie litery oznaczają zamiast tego współrzędne bezwzględne.
To trochę trudniejsze niż w przypadku H
i V
poleceń, ponieważ zawierają tylko jedną współrzędną. Oto jak opisałbym te dwa polecenia:
H{x}
: Rysuje linię poziomą od bieżącego punktu do współrzędnychx
.V{y}
: Rysuje pionową linię od bieżącego punktu do współrzędnychy
.
Kiedy rysujemy pierwszą cegłę w płytce ze wzorem, zaczynamy od (0,0)
współrzędne. Następnie rysujemy poziomą linię, aby (100,0)
i pionową linię do (100,30)
, a na koniec narysuj poziomą linię, aby (0,30)
. Użyliśmy h-100
polecenie w ostatnim wierszu, ale jest to odpowiednik H0
, czyli dwa bajty zamiast pięciu. Możemy zastąpić dwa podobne wystąpienia i sparować kod naszego <path>
do tego:
<path d="M0 0h100v30H0 M0 40h45v30H0 M55 40h55v30H55"/>
Kolejne 9 bajtów ogolonych — o ile mniejsze możemy zejść?
Mostkowanie (-5B, łącznie 48B)
Najdłuższe polecenia stojące na naszej drodze do w pełni zoptymalizowanego wzorca SVG to polecenia „przenieś do”, które zajmują odpowiednio 4, 5 i 6 bajtów. Jednym z ograniczeń, jakie mamy, jest to, że:
Segment danych ścieżki (jeśli istnieje) musi zaczynać się od polecenia „moveto”.
Ale to dobrze. Pierwsza i tak jest najkrótsza. Jeśli zamienimy wiersze, możemy wymyślić definicję ścieżki, w której musimy tylko poruszać się poziomo lub pionowo między cegłami. Co by było, gdybyśmy mogli użyć h
i v
komendy tam zamiast M
?
Powyższy diagram pokazuje, jak można narysować trzy kształty jedną ścieżką. Zauważ, że wykorzystujemy fakt, że fill
operacja automatycznie zamyka otwartą część między (110,0)
i (0,0)
. Dzięki tej zmianie przesunęliśmy również odstęp na lewo od cegły pełnej szerokości w drugim rzędzie. Oto jak wygląda kod, wciąż podzielony na jedną cegiełkę na linię:
<path d="M0 0v30h50V0 h10v30h50 v10H10v30h100V0"/>
Z pewnością znaleźliśmy absolutnie najmniejsze rozwiązanie teraz, gdy mamy już 48 bajtów, prawda?! Dobrze…
Przycinanie cyfr (-4B, łącznie 44B)
Jeśli możesz być nieco elastyczny w zakresie wymiarów, jest jeszcze jeden mały sposób na optymalizację wzorów SVG. Pracowaliśmy z cegłą o szerokości 100
piksele, ale to trzy bajty. Zmieniam to na 90
oznacza o jeden bajt mniej, ilekroć musimy go napisać. Podobnie wykorzystaliśmy lukę 10
piksele — ale jeśli zmienimy to na 8
zamiast tego zapisujemy bajt na każdym z tych wystąpień.
<path d="M0 0v30h45V0 h8v30h45 v8H8v30h90V0"/>
Oczywiście oznacza to również, że musimy odpowiednio dostosować wymiary wzoru. Oto ostateczny zoptymalizowany kod wzorca SVG:
<pattern id="p" width="98" height="76" patternUnits="userSpaceOnUse"> <path d="M0 0v30h45V0h8v30h45v8H8v30h90V0"/>
</pattern>
Drugi wiersz w powyższym fragmencie — nie licząc wcięć — to 44 bajtów. Dotarliśmy tutaj ze 197 bajtów w sześciu iteracjach. To jest grube 77.7% zmniejszenie rozmiaru!
Zastanawiam się jednak… czy to naprawdę najmniejszy możliwy rozmiar? Czy przyjrzeliśmy się wszystkim możliwym sposobom optymalizacji wzorców SVG?
Zapraszam do spróbowania i dalszej minimalizacji tego kodu, a nawet eksperymentowania z alternatywnymi metodami optymalizacji wzorców SVG. Chciałbym zobaczyć, czy z mądrością tłumu uda nam się znaleźć prawdziwe globalne minimum!
Więcej o tworzeniu i optymalizacji wzorów SVG
Jeśli chcesz dowiedzieć się więcej o tworzeniu i optymalizacji szablonów SVG, przeczytaj mój artykuł na ten temat tworzenie wzorów za pomocą filtrów SVG. Lub, jeśli chcesz sprawdzić galerię ponad 60 wzorów, możesz wyświetlić Kolekcja PetitePatterns CodePen. Na koniec zapraszamy do oglądania moje tutoriale na YouTube aby pomóc Ci jeszcze głębiej zagłębić się w wzorce SVG.
Optymalizacja wzorców SVG do ich najmniejszego rozmiaru pierwotnie opublikowany w dniu Sztuczki CSS. Powinieneś pobierz biuletyn.
- "
- 10
- 100
- 77
- 9
- 98
- O nas
- bezwzględny
- Konto
- Dodatkowy
- Wszystkie kategorie
- Pozwalać
- już
- Inne
- podejście
- POWIERZCHNIA
- artykuł
- atrybuty
- dostępny
- OSIE
- Bit
- Czarny
- wyzwanie
- zmiana
- zamknięte
- kod
- wspólny
- połączenie
- zawiera
- zawartość
- koordynować
- mógłby
- Tworzenie
- Aktualny
- dane
- głębiej
- na dół
- kończy się
- ustanowiony
- wszystko
- przykład
- Z wyjątkiem
- eksperyment
- W końcu
- i terminów, a
- dopasować
- pływ
- znaleziono
- dalej
- szczelina
- miejsce
- Globalne
- mający
- wysokość
- pomoc
- tutaj
- Podświetlony
- W jaki sposób
- HTTPS
- zidentyfikować
- obraz
- zawierać
- włączony
- IT
- samo
- znany
- przeciec
- UCZYĆ SIĘ
- dowiedziałem
- lewarowanie
- Linia
- mało
- wyglądał
- miłość
- WYKONUJE
- Dokonywanie
- zarządzane
- matematyka
- nic
- jeszcze
- większość
- ruch
- MS
- numer
- z naszej
- offset
- W porządku
- koncepcja
- zoptymalizowane
- Inaczej
- Wzór
- fizyczny
- punkt
- ustawione
- możliwy
- mocny
- bardzo
- Cena
- wygląda tak
- zapewnia
- jakość
- okrągły
- bieganie
- Powiedział
- bezszwowy
- Serie
- zestaw
- kształty
- podobny
- Prosty
- SIX
- Rozmiar
- So
- rozwiązanie
- coś
- Typ przestrzeni
- Spot
- początek
- rozpocznie
- Utrzymany
- rozmawiać
- Przez
- Top
- przezroczysty
- tutoriale
- posługiwać się
- wartość
- Zobacz i wysłuchaj
- W3
- Oglądaj
- powitanie
- Co
- w ciągu
- bez
- Praca
- pracujący
- działa
- wartość
- youtube