Wypełnienia, które są osobnymi obiektami
Do tej pory fill przyjmował kolor. Teraz przyjmie coś zupełnie innego — odwołanie do obiektu zdefiniowanego gdzie indziej w pliku.
To jest zmiana sposobu myślenia, nie tylko nowa składnia. Gradient nie jest wartością koloru. Jest bytem, który leży w <defs> i ma własne id. Kształt tylko mówi „wypełnij mnie tamtym", a jeden gradient może obsłużyć dziesięć figur naraz.
Anatomia
html
<defs>
<linearGradient id="zachod">
<stop offset="0%" stop-color="#e05c1a"/>
<stop offset="100%" stop-color="#0f0f0f"/>
</linearGradient>
</defs>
<rect fill="url(#zachod)" .../>
Trzy elementy układanki. <defs> to schowek — wszystko, co w nim leży, nie jest rysowane, tylko czeka na wywołanie. <stop> to punkt na osi gradientu: offset mówi gdzie (od 0% do 100%), stop-color jakim kolorem, a opcjonalne stop-opacity z jaką przezroczystością. url(#id) to odwołanie.
Punktów zatrzymania może być dowolnie wiele i nie muszą być rozłożone równo. Dwa <stop> o tym samym offset dają ostrą granicę zamiast przejścia — tak robi się paski i flagi bez rysowania osobnych prostokątów.
Kierunek
html
<linearGradient id="g" x1="0" y1="0" x2="1" y2="0">
Cztery liczby wyznaczają oś, wzdłuż której biegnie przejście: od punktu początkowego do końcowego. Domyślnie jest to lewa krawędź do prawej.
Suwaki zmieniają wektor kierunku i pozycję środkowego punktu zatrzymania. Ustaw
y2na 1 przyx2równym 0, a gradient pójdzie z góry na dół. Oba na 1 — po przekątnej.
Zwróć uwagę, że te liczby są ułamkami, nie jednostkami. To dlatego, że domyślnie gradient działa w objectBoundingBox— układzie, w którym 0 to jedna krawędź kształtu, a 1 druga, niezależnie od jego prawdziwego rozmiaru.
Ma to ogromną zaletę: ten sam gradient wygląda tak samo na małej ikonie i na wielkim tle. I jedną wadę, o której warto wiedzieć zawczasu.
Pułapka: układ współrzędnych gradientu
Skoro układ jest przywiązany do prostokąta otaczającego kształt, to gradient rozciąga się razem z nim. Zastosowany do wąskiego, wysokiego prostokąta zostanie spłaszczony w poziomie. Zastosowany do kilku figur o różnych proporcjach będzie w każdej wyglądał inaczej, choć definicja jest jedna.
Gdy potrzebujesz, żeby gradient był położony w konkretnym miejscu płótna — a nie względem kształtu — przełącz go:
html
<linearGradient id="g" gradientUnits="userSpaceOnUse"
x1="0" y1="0" x2="200" y2="0">
Teraz liczby są zwykłymi jednostkami użytkownika, takimi jak w viewBox. Dzięki temu kilka osobnych kształtów może dzielić jedno wspólne przejście kolorów, tak jakby były wycięte z jednego tła. To standardowy trik przy ikonach składających się z kilku części.
Warto też znać spreadMethod. Domyślne pad przedłuża skrajne kolory poza oś gradientu. reflect odbija wzór tam i z powrotem, repeat powtarza go od nowa — obie wartości działają dopiero wtedy, gdy oś gradientu jest krótsza niż kształt.
Gradient promienisty
html
<radialGradient id="kula" cx="0.5" cy="0.5" r="0.6"
fx="0.35" fy="0.3">
Zamiast osi mamy okrąg. cx i cy to jego środek, r promień. Do tego dochodzą fx i fy — ognisko, czyli punkt, z którego kolor faktycznie wychodzi.
Gdy ognisko pokrywa się ze środkiem, dostajesz równomierne koło. Gdy je odsuniesz, przejście robi się asymetryczne i figura zaczyna wyglądać jak kula oświetlona z boku.
Przesuń ognisko w lewy górny róg i zmniejsz promień. Płaskie koło zamienia się w bryłę — bez żadnego cienia, jednym gradientem. To najtańszy sposób na trójwymiarowość w płaskiej grafice.
Wzory
<pattern> działa jak gradient, tylko zamiast przejścia kolorów powtarza kafelek z dowolną zawartością. W środku może być cokolwiek: kształty, tekst, inny gradient, a nawet obrazek rastrowy.
html
<pattern id="kropki" width="22" height="22"
patternUnits="userSpaceOnUse">
<circle cx="10" cy="10" r="5" fill="#e05c1a"/>
</pattern>
Zmniejszaj kafelek. Przy rozmiarze poniżej piętnastu kropka zaczyna być przycinana, a poniżej dziesięciu znika zupełnie — bo jej środek wypada już poza kafelkiem. Wszystko, co wystaje poza kafelek, jest ucinane, a nie przenoszone do sąsiedniego.
To najczęstszy błąd przy wzorach: element narysowany w rogu kafelka wygląda na przecięty, bo jego druga połowa nie pojawia się po drugiej stronie. Żeby wzór ładnie się schodził na krawędziach, trzeba rysować go w kafelku dwukrotnie — raz w środku i raz przesunięty o pełny rozmiar kafelka.
Zwróć też uwagę na patternUnits="userSpaceOnUse". Bez tego rozmiar kafelka byłby ułamkiem wielkości figury, więc na dużym prostokącie kropki byłyby ogromne, a na małym mikroskopijne. Przy wzorach ustawienie na jednostki użytkownika jest niemal zawsze tym, o co Ci chodzi.
Pułapka, o której trzeba wiedzieć na stronie
Ta jest praktyczna i gryzie właśnie w WordPressie, gdzie na jednej stronie ląduje kilkanaście osadzonych SVG naraz.
Identyfikatory są wspólne dla całego dokumentu HTML, nie dla pojedynczego SVG. Jeśli dwie ikony mają wewnątrz gradient o id="g", druga z nich będzie odwoływać się do definicji z pierwszej. Ikona nagle zmienia kolor, choć nikt jej nie ruszał — a w pliku źródłowym wszystko jest w porządku.
Objaw jest charakterystyczny: grafika wygląda poprawnie w podglądzie i psuje się po wstawieniu na stronę. Zwykle łamie się dopiero ta druga, trzecia albo dziesiąta, w zależności od kolejności.
Lekarstwo jest proste: unikalne, opisowe identyfikatory w każdym pliku — ifox-hero-gradient, a nie a. Optymalizatory potrafią to zrobić automatycznie i wrócimy do tego w lekcji o SVGO.
Podsumowanie
- Gradient i wzór to obiekty w
<defs>, przywoływane przezurl(#id). <stop>maoffset,stop-coloristop-opacity; dwa stopy o tym samym offsecie dają ostrą granicę.- Domyślnie współrzędne gradientu są ułamkami rozmiaru kształtu, więc gradient rozciąga się razem z nim.
gradientUnits="userSpaceOnUse"przełącza na jednostki płótna i pozwala kilku kształtom dzielić jedno przejście.- W gradiencie promienistym
fx/fyto ognisko — jego przesunięcie daje efekt bryły. - Zawartość wzoru jest przycinana do kafelka; nic nie przechodzi na sąsiedni.
- Identyfikatory są wspólne dla całej strony — powtórzone id to najczęstsza przyczyna psujących się grafik po osadzeniu.
W następnej lekcji zajmiemy się ukrywaniem części obrazu: clipPath tnie po kształcie, mask po jasności, a różnica między nimi decyduje o tym, czy krawędź będzie ostra, czy miękka.
Do wypróbowania: w presecie pattern dopisz w kafelku drugi element — na przykład <rect width="{{w}}" height="1" fill="#f0ede6"/>. Dostaniesz kropki na liniowanym tle, a przy okazji zobaczysz, że wzór może zawierać dowolną liczbę kształtów, nie jeden.