Lekcja 16. SVG a CSS

wrz 3, 2026 | Bez kategorii

Dlaczego ikona przez <img> nie chce zmienić koloru

To najbardziej praktyczna lekcja w kursie. Nie o rysowaniu, tylko o tym, co dzieje się, gdy gotowa grafika trafia na stronę — i dlaczego zachowuje się wtedy zupełnie inaczej, niż w edytorze.

Wszystko sprowadza się do jednego pytania: czy przeglądarka traktuje Twój SVG jak część dokumentu, czy jak obrazek.

Cztery sposoby osadzenia

Inline — kod SVG wklejony wprost w HTML:

html

<svg viewBox="0 0 24 24" class="ikona">
  <path d="..."/>
</svg>

Grafika jest częścią dokumentu. CSS strony do niej sięga, JavaScript może ją zmieniać, currentColor działa, fonty ze strony są widoczne. Pełna kontrola.

Koszty też są: kod powiększa HTML, nie jest cache'owany osobno i przy dziesięciu tych samych ikonach powtarza się dziesięć razy — chyba że użyjesz sprite'u z lekcji czternastej.

Znacznik <img>:

html

<img src="ikona.svg" alt="Ulubione">

Przeglądarka renderuje plik w izolacji, jak każdy inny obrazek. To jest ta cecha, która tłumaczy większość zaskoczeń:

  • CSS strony nie sięga do środka — żadna reguła nie zmieni koloru
  • JavaScript nie ma dostępu do wnętrza
  • fonty wczytane na stronie nie są widoczne (o czym była lekcja piętnasta)
  • odwołania do zewnętrznych plików nie działają

Działa za to wszystko, co siedzi wewnątrz pliku: SMIL, znacznik <style>, gradienty, filtry. I plik jest normalnie cache'owany, a alt daje gotową dostępność.

Tło w CSS:

css

.ikona { background-image: url("ikona.svg"); }

Zachowuje się jak <img> pod względem izolacji, ale bez tekstu alternatywnego — więc nadaje się wyłącznie do dekoracji.

Jeśli wstawiasz SVG jako data URI wprost w CSS, pamiętaj o jednej pułapce: znak # trzeba zakodować jako %23. Niezakodowany zaczyna być traktowany jak identyfikator fragmentu i tło po prostu znika. To najczęstsza przyczyna „ikona działa w pliku, nie działa w data URI".

<object> i <iframe> — dają dostęp z JavaScriptu, ale komplikują styling i rzadko są tego warte. Wspominam, żeby nie zaskoczyły w cudzym kodzie.

Jak wybrać

Prosta reguła, która obejmuje większość przypadków:

  • Ikona ma zmieniać kolor razem z tekstem, stanem przycisku albo motywem → inline, najlepiej ze sprite'u.
  • Grafika jest duża, złożona i statyczna — ilustracja, mapa, wykres tła → <img>, żeby nie puchł HTML i żeby działał cache.
  • Element jest czysto dekoracyjny → tło w CSS.

Atrybut przegrywa z regułą

Teraz rzecz, którą trzeba znać, bo tłumaczy objaw wyglądający na zepsucie pliku.

W SVG istnieją dwa sposoby zapisania wyglądu. Atrybut prezentacyjny, czyli fill="#e05c1a" w znaczniku. I reguła CSS, czyli fill: red w arkuszu.

Wyglądają na równorzędne. Nie są. Atrybut prezentacyjny stoi w kaskadzie najniżej — przegrywa z każdą regułą CSS, nawet z selektorem uniwersalnym *.

Oba prostokąty mają identyczny atrybut fill. Lewy ma dodatkowo klasę i jedną regułę w <style> — i to ona decyduje. Prawy zostaje pomarańczowy.

Konsekwencja praktyczna jest poważna: jedna nieostrożna reguła w motywie potrafi zmienić wygląd wszystkich osadzonych grafik naraz. Reset typografii z * obejmujący letter-spacing albo font-size zmieni każdy napis w każdym inline'owym SVG na stronie. Objaw: „grafika wygląda dobrze w pliku, źle po wgraniu", a w kodzie SVG wszystko jest poprawne, bo problem jest gdzie indziej.

To nie jest przykład teoretyczny — dokładnie ten błąd wystąpił przy budowie playgroundu do tego kursu. Reset chroniący interfejs widgetu obejmował też podgląd i zjadał font-size z kodu użytkownika. Grafika renderowała się poprawnie, tylko z cudzą typografią.

Jeśli grafika ma być odporna, jej wygląd warto zapisać w atrybutach i nie dawać jej klas, które motyw mógłby przypadkiem złapać. Jeśli ma być sterowalna — odwrotnie.

currentColor

Znasz to z lekcji o sprite'ach, ale tutaj widać, do czego naprawdę służy.

html

<g color="#e05c1a">
  <circle fill="currentColor"/>
  <rect stroke="currentColor"/>
</g>

Jedna wartość steruje i wypełnieniem, i obrysem. Trzeci kształt ma kolor wpisany na sztywno i nie reaguje — dokładnie tak samo zachowa się przy zmianie motywu.

currentColor czyta właściwość color, która jest dziedziczona. Wystarczy więc ustawić ją raz, wyżej w drzewie — na przycisku, na sekcji, na body — a wszystkie ikony pod spodem dopasują się same.

To jest podstawa działających ikon: jeden plik, dowolny kolor, zero duplikatów.

Tryb ciemny

Sposób zależy od osadzenia i tu jest jedna miła niespodzianka.

Inline — najprościej przez currentColor albo zmienne CSS:

css

.ikona { color: #0f0f0f; }
@media (prefers-color-scheme: dark) {
  .ikona { color: #e8e4dc; }
}

<img> — CSS strony nie dosięgnie grafiki, ale zapytanie medialne umieszczone wewnątrz pliku SVG działa. Przeglądarka przekazuje preferencję motywu także do obrazków renderowanych w izolacji:

html

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <style>
    path { fill: #0f0f0f; }
    @media (prefers-color-scheme: dark) {
      path { fill: #e8e4dc; }
    }
  </style>
  <path d="..."/>
</svg>

Jeden plik, dwa motywy, żadnego JavaScriptu — i działa nawet jako background-image. To jedna z najbardziej niedocenianych możliwości tego formatu.

Rozmiar na stronie

Na koniec przepis, który oszczędza sporo prób i błędów.

Żeby SVG zachowywał się jak porządny element blokowy i wypełniał kontener, usuń z pliku width i height, zostaw viewBox, a rozmiarem steruj z CSS. Wtedy proporcje pilnuje viewBox, a szerokość ustala układ strony.

css

.ikona { width: 24px; height: 24px; display: block; }
.ilustracja { width: 100%; height: auto; display: block; }

display: block jest tu ważne — domyślnie SVG jest elementem liniowym, więc pod spodem pojawia się kilkupikselowa przerwa na linię bazową tekstu. To ta sama zagadka co przy obrazkach w starym HTML i to samo rozwiązanie.

Podsumowanie

  • Inline daje pełną kontrolę: CSS, JavaScript, currentColor, fonty strony.
  • <img> i tło w CSS renderują plik w izolacji — bez CSS strony, bez JS, bez fontów, bez odwołań zewnętrznych.
  • W data URI znak # musi być zakodowany jako %23.
  • Atrybut prezentacyjny przegrywa z każdą regułą CSS, więc reset w motywie potrafi zmienić wygląd wszystkich grafik.
  • currentColor czyta dziedziczoną właściwość color — jedna definicja obsługuje wszystkie kolory.
  • Zapytanie prefers-color-scheme wewnątrz pliku SVG działa nawet w <img>.
  • Do skalowania: bez width i height w pliku, z viewBox, plus display: block w CSS.

W następnej lekcji zaczynamy blok o higienie: optymalizacja, czyli co eksporter wpycha do pliku niepotrzebnie i co wolno z tego wyciąć.


Do wypróbowania: w presecie kaskada dopisz do reguły CSS stroke: #0f0f0f; stroke-width: 4;, a do prawego prostokąta te same wartości jako atrybuty. Wyglądają identycznie — ale spróbuj teraz zmienić oba jedną regułą rect { stroke: none; }. Zniknie tylko ten z atrybutami, bo reguła z klasą jest silniejsza.

Nie Znaleziono Wyników

Nie można odnaleźć żądanej strony. Spróbuj doprecyzować wyszukiwanie lub użyj nawigacji powyżej, aby znaleźć wpis.