Dlaczego SVG się skaluje, choć w rysunku nic się nie zmienia
Zacznijmy od pytania, które brzmi banalnie, a nie ma banalnej odpowiedzi: jak duży jest ten plik SVG?
Przy JPG odpowiedź jest oczywista — 1920 na 1080 pikseli, koniec tematu. Obraz jest siatką punktów i tych punktów jest dokładnie tyle. Przy SVG to pytanie jest źle postawione, bo w pliku nie ma żadnych pikseli. Jest opis: narysuj koło o środku w punkcie 50,50 i promieniu 40. Pięćdziesiąt czego? Czterdzieści czego?
Odpowiedź brzmi: niczego. I na tym stoi cała skalowalność tego formatu.
Płótno bez jednostek
SVG rysuje we własnym, abstrakcyjnym układzie współrzędnych. Punkt zero jest w lewym górnym rogu. Oś X rośnie w prawo — tak jak się spodziewasz. Oś Y rośnie w dół — co jest odwrotnie niż na lekcji matematyki i pierwszego dnia gwarantuje kilka figur narysowanych do góry nogami.
Współrzędne w tym układzie to czyste liczby. Nie są to piksele, milimetry ani punkty typograficzne. Są to jednostki użytkownika — umowna miara, której znaczenie ustala się dopiero w momencie wyświetlania. Dopóki plik leży na dysku, koło o promieniu 40 nie ma żadnego fizycznego rozmiaru. Ma proporcję.
To jest różnica między fotografią a przepisem. Zdjęcie ciasta ma rozdzielczość. Przepis na ciasto nie ma — mówi „dwie szklanki mąki", a jak duża jest szklanka, rozstrzyga się w kuchni.
viewBox: wybór wycinka
Skoro rysunek nie ma rozmiaru, ktoś musi powiedzieć przeglądarce, na który fragment nieskończonego płótna ma patrzeć. Robi to atrybut viewBox, który przyjmuje cztery liczby:
viewBox="min-x min-y szerokość wysokość"
Pierwsze dwie to punkt, od którego zaczyna się widoczny obszar. Dwie kolejne to jego rozmiar — w jednostkach użytkownika, nie w pikselach. Zapis viewBox="0 0 100 100" znaczy: pokaż kwadratowy wycinek płótna od punktu 0,0 o boku stu jednostek.
I teraz najważniejsze. Jeśli powiększysz trzecią i czwartą liczbę, obraz zmaleje. Nie dlatego, że rysunek się skurczył — dlatego, że okno się rozszerzyło, a rysunek został ten sam. To jak odsunięcie się od obrazu w galerii: obraz nie maleje, tylko zajmuje mniejszą część pola widzenia.
Sprawdź w playgroundzie — preset viewBox. Kwadrat ma zawsze bok 100 jednostek, kod kwadratu ani razu się nie zmienia. Rusza się wyłącznie
viewBox. Przy wartości 100 kwadrat wypełnia całe okno. Przy 300 tonie w pustce, choć jest dokładnie tak samo duży jak przedtem.
Warto od razu przyjąć nawyk: viewBox="0 0 100 100" albo 0 0 24 24 dla ikon. Okrągłe liczby, do których łatwo liczyć w głowie. Nic nie stoi na przeszkodzie, żeby użyć 0 0 1337 42, ale będziesz tego żałować przy pierwszej ręcznej poprawce.
width i height: dopiero tu pojawiają się piksele
Skoro viewBox ustala, co widać, to width i height ustalają, jak duże to jest na ekranie. Dopiero one operują realnymi jednostkami CSS.
html
<svg viewBox="0 0 100 100" width="240" height="240">
Czytaj to tak: weź stujednostkowy wycinek płótna i narysuj go na obszarze 240 na 240 pikseli. Przeglądarka wykonuje przeliczenie — jedna jednostka użytkownika staje się 2,4 piksela — i rysuje wszystko w natywnej rozdzielczości ekranu. Zmień 240 na 2400, a dostaniesz ten sam obraz, idealnie ostry, bez jednego bajtu więcej w pliku.
Te dwa atrybuty odpowiadają na dwa różne pytania i mylenie ich jest źródłem większości problemów ze skalowaniem SVG. viewBox to kadr. width/height to rozmiar odbitki.
Trzy klasyczne pomyłki
Pomyłka pierwsza: SVG w ogóle się nie skaluje. Prawie zawsze znaczy to, że w pliku nie ma viewBox. Bez niego przeglądarka nie wie, jaki wycinek pokazać, więc traktuje width i height jako sztywny rozmiar. Efekt: obrazek zachowuje się jak PNG i ignoruje CSS. Lekarstwo to jedna linijka — dopisz viewBox z wymiarami, które miał w width/height.
Pomyłka druga: SVG nie chce wypełnić kontenera. Zwykle winne są zaszyte w pliku width i height, które wygrywają z układem strony. Standardowe rozwiązanie: usuń oba atrybuty z pliku, zostaw viewBox, a rozmiarem steruj z CSS-a. Wtedy SVG zachowuje się jak porządny element blokowy i wypełnia to, co mu dasz.
Pomyłka trzecia: rysunek jest ucięty. Kadr jest mniejszy niż to, co narysowałeś. Kształt istnieje, tylko wystaje poza viewBox i nikt go nie widzi. Nie ma tu magii — trzeba policzyć skrajne współrzędne i poszerzyć okno.
Sprawdź w playgroundzie — w presecie viewBox ustaw wartość na 60. Koło zostaje ucięte przy krawędziach, choć w kodzie ma się dobrze. To jest dokładnie pomyłka trzecia, na żywo.
Gdy proporcje się nie zgadzają
Zostaje przypadek, o którym warto wiedzieć, zanim ugryzie. Co się dzieje, gdy viewBox jest kwadratowy, a miejsce na stronie prostokątne?
Domyślnie SVG nie rozciąga się. Zachowuje proporcje, wpisuje się w dostępny obszar i centruje — dokładnie tak, jak zdjęcie w trybie contain. Odpowiada za to atrybut preserveAspectRatio, którego domyślna wartość to xMidYMid meet: wyśrodkuj w obu osiach, zmieść całość.
Dwie zmiany warto znać. slice zamiast meet każe wypełnić cały obszar i przyciąć nadmiar — odpowiednik cover. A wartość none wyłącza zachowanie proporcji i pozwala rozciągnąć rysunek dowolnie. To ostatnie jest przydatne mniej więcej raz na sto przypadków, a wygląda dokładnie tak źle, jak brzmi.
Podsumowanie
- SVG rysuje w abstrakcyjnym układzie bez jednostek; oś Y rośnie w dół.
viewBoxwybiera wycinek płótna. Większe liczby to szersze okno, czyli mniejszy rysunek.widthiheightmówią, na jak dużym obszarze ekranu ten wycinek narysować. Dopiero tutaj pojawiają się piksele.- Brak
viewBoxodbiera SVG zdolność skalowania. To najczęstsza przyczyna „mój SVG nie działa jak wektor". - Przy niepasujących proporcjach obraz domyślnie się mieści i centruje, a nie rozciąga.
W następnej lekcji zaczniemy coś na tym płótnie rysować — od sześciu kształtów podstawowych, które załatwiają zaskakująco dużą część codziennej roboty.
Do wypróbowania: otwórz playground, wybierz preset viewBox i spróbuj ustawić kadr tak, żeby widoczna była wyłącznie prawa dolna ćwiartka koła. Podpowiedź: pierwsze dwie liczby też można zmieniać.