Ikony SVG w WordPress - dlaczego inline to antywzorzec i jak to naprawić
Spis treści
Rozwiń spis treści
Popularny wzorzec, który nie powinien być popularny
Przeglądam kod motywów WordPress i widzę to regularnie. Tablica PHP z ikonami social media, gdzie każda ikona to pełny kod SVG wklejony jako string.
$options = array(
'facebook' => array(
'key' => 'facebook',
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24"><path d="M12 2C6.477 2 2 6.477 2 12C2 16.991 5.657 21.128 10.438 21.879V14.89H7.898V12H10.438V9.797C10.438 7.291 11.93 5.907 14.215 5.907C15.309 5.907 16.453 6.102 16.453 6.102V8.562H15.193C13.95 8.562 13.563 9.333 13.563 10.124V12H16.336L15.893 14.89H13.563V21.879C18.343 21.129 22 16.99 22 12C22 6.477 17.523 2 12 2Z"/></svg>',
),
'instagram' => array(
'key' => 'instagram',
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24">...</svg>',
),
// ... kolejne ikony
);
$output[] = '<a href="' . esc_url($url) . '">' . $settings['icon'] . '</a>';
Działa? Technicznie tak. Ale to architektura, która płaci podatek przy każdym page view.
Policz sobie koszty
Pojedyncza ikona SVG to zazwyczaj 500-2000 bajtów kodu. Typowy zestaw social media (Facebook, Instagram, LinkedIn, Twitter/X, YouTube) to 5 ikon.
Przy 1 KB średnio na ikonę masz 5 KB nadmiarowego HTML-a w każdej odpowiedzi serwera.
A teraz pomnóż to przez liczbę podstron, na których te ikony się pojawiają. Footer z ikonami na 50 podstronach? To 250 KB transferu, który mógłby nie istnieć.
Co tracisz:
| Problem | Konsekwencja |
|---|---|
| Brak cache przeglądarki | SVG ładowane od nowa przy każdym page view |
| Większy HTML | Wolniejszy parsing DOM |
| Duplikacja | Ta sama ikona renderowana osobno na każdej podstronie |
| Czytelność kodu | PHP zaśmiecony wielolinijkowymi stringami SVG |
| Edycja ikon | Wymaga zmian w PHP zamiast podmianki pliku |
| Niespójność wizualna | Różne wersje tej samej ikony w różnych miejscach |
Problem z kodem generowanym przez LLM
Jest jeszcze jeden aspekt, który staje się coraz bardziej widoczny w erze AI-assisted development.
Prosisz Claude’a, GPT czy Copilota o komponent z ikonami social media. Dostajesz działający kod z inline SVG. Tydzień później prosisz o kolejny komponent z tymi samymi ikonami. Dostajesz inny wariant SVG.
Efekt? Rozjechana ikonografia.
LLM nie ma pamięci o tym, jakiego wariantu ikony Facebook użył w poprzednim prompcie. Każda generacja to potencjalnie:
- Inna grubość linii (stroke width)
- Inny viewBox
- Inna wersja logo (Facebook zmienia logo co kilka lat)
- Inny styl - outline vs filled vs rounded
Widziałem projekt, gdzie ta sama ikona LinkedIn występowała w trzech różnych wariantach na jednej stronie. Nie dlatego, że ktoś świadomie wybrał różne style - tylko dlatego, że każdy fragment kodu został wygenerowany osobno.
Rozwiązanie: Single Source of Truth
Gdy trzymasz ikony jako zewnętrzne pliki, masz jedno źródło prawdy. Niezależnie od tego, ile razy poprosisz LLM o komponent używający ikony Facebook - zawsze odwołuje się do tego samego pliku facebook.svg.
// LLM generuje tylko referencję, nie całą ikonę
'icon' => 'facebook.svg',
Zamiast:
// LLM generuje pełny SVG - za każdym razem potencjalnie inny
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" width="28"...',
To nie jest edge case. To staje się domyślny scenariusz w projektach, gdzie duża część kodu powstaje z pomocą AI. Więcej o pracy z LLM i jak unikać takich pułapek znajdziesz w artykule Subiektywnie o vibe codingu.
Lepszy wzorzec - zewnętrzne pliki SVG
Architektura, która ma sens:
Struktura plików
assets/images/social/
├── facebook.svg
├── instagram.svg
├── linkedin.svg
├── twitter.svg
└── youtube.svg
Kod PHP
$icons_url = get_stylesheet_directory_uri() . '/assets/images/social/';
$options = array(
'facebook' => array(
'key' => 'facebook',
'icon' => 'facebook.svg',
),
'instagram' => array(
'key' => 'instagram',
'icon' => 'instagram.svg',
),
);
// Generowanie HTML
$icon_html = sprintf(
'<img src="%s" alt="%s" width="28" height="28" loading="lazy" />',
esc_url($icons_url . $settings['icon']),
esc_attr($social)
);
$output[] = sprintf(
'<a target="_blank" rel="noopener noreferrer" href="%s">%s</a>',
esc_url($url),
$icon_html
);
Co zyskujesz:
- Cache przeglądarki - ikona ładowana raz, potem serwowana z pamięci (304 Not Modified)
- Lżejszy HTML - zamiast 1 KB kodu SVG masz ~80 bajtów taga
<img> - Lazy loading - ikony poniżej folda ładowane dopiero gdy są potrzebne
- Łatwa edycja - podmiana pliku SVG bez dotykania PHP
- Czytelny kod - tablice PHP zawierają tylko nazwy plików
Kiedy inline SVG ma sens
Nie twierdzę, że inline SVG jest zawsze złe. Jest kilka scenariuszy, gdzie ma uzasadnienie:
1. Dynamiczna zmiana koloru przez CSS
.icon-link:hover svg path {
fill: currentColor;
}
Jeśli potrzebujesz, żeby ikona dziedziczyła kolor z rodzica lub zmieniała się przy hover - musisz mieć SVG w DOM.
2. Animacje zależne od DOM
Animacje SMIL lub JavaScript manipulujące ścieżkami SVG wymagają dostępu do elementów wewnątrz SVG.
3. Ikona używana tylko raz
Jeśli ikona pojawia się na jednej podstronie i nigdzie indziej - overhead osobnego requestu HTTP może nie mieć sensu.
4. Critical path rendering
Ikona above the fold, która musi być widoczna natychmiast bez dodatkowego roundtripa do serwera.
Hybrydowe podejście - SVG sprite
Jeśli potrzebujesz dynamicznych kolorów, ale nie chcesz duplikować kodu, rozważ SVG sprite:
<!-- Jeden plik sprite.svg z definicjami -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="icon-facebook" viewBox="0 0 24 24">
<path d="M12 2C6.477 2 2 6.477..." />
</symbol>
<symbol id="icon-instagram" viewBox="0 0 24 24">
<path d="..." />
</symbol>
</svg>
<!-- Użycie -->
<svg width="28" height="28"><use href="#icon-facebook" /></svg>
Sprite definiujesz raz (np. w headerze), a potem odwołujesz się przez <use>. Zachowujesz kontrolę CSS nad fill, ale kod nie jest duplikowany.
Podsumowanie
| Aspekt | Inline SVG | Zewnętrzne SVG | SVG Sprite |
|---|---|---|---|
| Cache przeglądarki | Brak | Tak | Częściowo |
| Rozmiar HTML | Duży | Minimalny | Średni |
| Dynamiczny kolor CSS | Tak | Nie | Tak |
| Lazy loading | Nie | Tak | Nie |
| Edycja ikon | Wymaga PHP | Podmiana pliku | Wymaga sprite |
Domyślnie trzymaj się zewnętrznych plików SVG. Sięgaj po inline tylko wtedy, gdy masz konkretny powód - dynamiczne kolory, animacje, critical rendering path.
Nie dlatego, że “tak jest wygodniej pisać kod”.
Pamiętaj też, że optymalizacja kodu to tylko część układanki. Jeśli Twój serwer zwraca TTFB na poziomie kilku sekund, żadna ilość mikro-optymalizacji tego nie naprawi. Więcej o tym piszę w artykule Dlaczego hosting powinien być krokiem numer jeden.
Jakie jest Twoje zdanie? Daj znać w komentarzach.