Lekcja 6. fill i stroke

wrz 3, 2026 | Kurs SVG

Wypełnienie, obrys i dwie rzeczy, które zaskakują wszystkich

Blok o path za nami. Umiesz narysować dowolny kształt. Teraz zajmiemy się tym, jak on wygląda — a zaczniemy od dwóch właściwości, które wpisywaliśmy przez pięć lekcji bez zastanowienia.

fill to wypełnienie wnętrza. stroke to obrys konturu. Brzmi banalnie i w 90% przypadków takie jest. Ale zostałe 10% zawiera dwie pułapki, na których wykłada się każdy.

Wartości domyślne

Warto je znać na pamięć, bo są nieoczywiste:

  • fill domyślnie jest czarne. Nie przezroczyste — czarne.
  • stroke domyślnie nie istnieje. Wartość to none.

Stąd dwa objawy z lekcji drugiej: linia bez stroke jest niewidoczna, a łamana bez fill="none" zamienia się w plamę. Kształt bez żadnych atrybutów będzie czarną sylwetką.

Obie właściwości przyjmują też none, dowolny kolor CSS (#e05c1atomatorgb()hsl()) oraz odwołanie do gradientu przez url(#id), o czym będzie osobna lekcja.

Do przezroczystości służą fill-opacity i stroke-opacity — osobno dla środka i konturu. Jest jeszcze zbiorcze opacity, ale ono działa inaczej: przyciemnia cały element naraz, po złożeniu, więc nachodzące na siebie kontur i wypełnienie nie prześwitują przez siebie. Przy półprzezroczystych kształtach ta różnica bywa widoczna.

Pułapka pierwsza: obrys leży na krawędzi

To jest rzecz, która psuje układy i której nie widać, dopóki ktoś nie pokaże.

Obrys nie jest rysowany wewnątrz kształtu ani na zewnątrz. Jest rozłożony na krawędzi po połowie. Przy stroke-width="20" dziesięć jednostek wchodzi do środka, a dziesięć wystaje na zewnątrz.

Cienka czarna linia pokazuje prawdziwą geometrię prostokąta — dokładnie to, co podałeś w xywidth i height. Pomarańczowy obrys rozkłada się na niej symetrycznie. Podkręć suwak do końca, a zobaczysz, jak figura wychodzi poza viewBox i zostaje przycięta, mimo że sam prostokąt cały czas siedzi w środku.

Konsekwencje są praktyczne. Prostokąt 100×100 z obrysem grubości 20 zajmuje w rzeczywistości 120×120. Ikona zaprojektowana w viewBox="0 0 24 24" z obrysem grubości 2 będzie miała ścięte krawędzie, jeśli kontur dotyka brzegu kadru. Dlatego zestawy ikon konturowych projektuje się z marginesem — zwykle jedną jednostkę z każdej strony.

W CSS istnieje box-sizing, który pozwala wybrać, jak liczyć obramowanie. W SVG nie ma odpowiednika. Jeśli potrzebujesz obrysu wyłącznie wewnętrznego, trzeba go przyciąć maską — i o tym będzie lekcja o clipPath.

Zakończenia i połączenia

Gdy obrys robi się gruby, zaczyna mieć znaczenie, co dzieje się na jego końcach i narożnikach.

stroke-linecap decyduje o końcach otwartej linii. butt ucina równo w punkcie końcowym, round dokłada półkole, squaredokłada kwadrat. Uwaga: round i square wydłużają linię o połowę jej grubości z każdej strony, więc odcinek od 20 do 180 z grubością 16 zajmie w rzeczywistości od 12 do 188.

stroke-linejoin decyduje o narożnikach. miter przedłuża oba boki, aż się spotkają, round zaokrągla, bevel ścina.

Zjedź wierzchołkiem do góry przy ustawieniu miter. Im ostrzejszy kąt, tym dłuższy kolec — a przy bardzo ostrym kącie kolec miałby długość dążącą do nieskończoności. Dlatego SVG ma bezpiecznik.

Tym bezpiecznikiem jest stroke-miterlimit. Określa, ile razy dłuższy od grubości linii może być kolec, zanim narożnik zostanie automatycznie ścięty. Domyślna wartość to 4. Zmniejsz ją w widgecie do 1 i zobacz, że narożnik przeskakuje na bevel już przy łagodnym kącie.

To wyjaśnia zjawisko, które wygląda jak błąd przeglądarki: narożnik nagle zmienia kształt, choć nic w nim nie zmieniałeś. Nie zmieniałeś — przekroczyłeś limit.

Pułapka druga: co właściwie jest środkiem

Zostaje pytanie, które wygląda na filozoficzne, a jest jak najbardziej praktyczne. Gdy ścieżka przecina samą siebie, co jest jej wnętrzem?

Popatrz na gwiazdę narysowaną jednym ciągiem, jak pentagram na kartce. Środkowy pięciokąt jest w środku czy na zewnątrz? Odpowiedź zależy od przyjętej reguły, a SVG oferuje dwie.

Ta sama ścieżka, dwa ustawienia fill-rule. Różnica dotyczy wyłącznie środkowego pięciokąta.

nonzero — domyślna. Prowadzi promień od badanego punktu na zewnątrz i liczy przecięcia z konturem, ale ze znakiem: przecięcie w jedną stronę dodaje, w drugą odejmuje. Wynik różny od zera oznacza wnętrze. W gwieździe wszystkie odcinki biegną w tę samą stronę, więc środek wychodzi na wypełniony.

evenodd — liczy przecięcia bez znaku. Nieparzysta liczba to wnętrze, parzysta to zewnętrze. Środek gwiazdy przecina kontur dwa razy, więc zostaje pusty.

W praktyce potrzebujesz tego w dwóch sytuacjach: kształty z dziurami (litera „o", pierścień, ramka) oraz ikony z wyciętym wnętrzem. Jeśli w wyeksportowanym pliku dziura nagle się zalała, fill-rule jest pierwszym miejscem do sprawdzenia — zaraz po kierunku, w którym narysowany jest wewnętrzny kontur.

Kolejność malowania

Domyślnie SVG rysuje najpierw wypełnienie, potem obrys na nim. Przy grubym obrysie oznacza to, że kontur zjada połowę wypełnienia od środka.

Zmienia to właściwość paint-order. Zapis paint-order="stroke fill" odwraca kolejność i sprawia, że wypełnienie ląduje na obrysie — dzięki czemu obrys wygląda, jakby był wyłącznie zewnętrzny. To najprostszy sposób na obwódkę wokół tekstu i na ikony z grubym konturem, który nie ma zjadać środka.

Podsumowanie

  • fill domyślnie czarne, stroke domyślnie żaden.
  • fill-opacity i stroke-opacity działają osobno; zbiorcze opacity przyciemnia element po złożeniu.
  • Obrys rozkłada się na krawędzi po połowie i powiększa realny rozmiar figury o swoją grubość.
  • linecap typu round i square wydłużają linię o połowę grubości z każdej strony.
  • miter tworzy kolec przy ostrych kątach; stroke-miterlimit (domyślnie 4) automatycznie ścina go na bevel.
  • fill-rule rozstrzyga, co jest wnętrzem ścieżki przecinającej samą siebie. evenodd daje dziury.
  • paint-order pozwala położyć wypełnienie na obrysie zamiast pod nim.

W następnej lekcji zostajemy przy obrysie, ale zaczniemy go przerywać — stroke-dasharray i mechanizm, na którym stoi efekt rysującej się linii.


Do wypróbowania: w presecie stroke-width dopisz do pomarańczowego prostokąta paint-order="stroke fill" i ustaw grubość na 30. Obrys przestanie zjadać wypełnienie od środka i zacznie wyglądać, jakby był rysowany wyłącznie na zewnątrz — choć geometrycznie nic się nie zmieniło.