← všechny články

Ikonky na webu: inline SVG, zarovnání na řádek a pixelart


Při práci na mém CSS frameworku jsem narazil na problematiku ikonek. Dlouhá léta jsem používal ikonkové fonty, ale tohle řešení je poněkud neobratné. Na každé stránce člověk načítá všechny ikonky, i ty, které reálně nepoužije (pokud si font ručně neořeže jen na potřebné znaky). Čtečky obrazovky je navíc čtou špatně, a když se font nenačte, uvidí uživatel místo ikonek prázdné čtverečky.

Po zvážení dalších možností, jak s ikonkami pracovat, se mi jako nejlepší jeví to nejjednodušší řešení – formou inline SVG. Jsem tak schopen snadno modifikovat výstup SVG, pracovat s barvou, vykreslením apod. Daní za to je, že se inline SVG neukládá do cache a s každou ikonkou roste HTML. Při větším množství ikon proto stojí za zvážení SVG sprite, ze kterého se jednotlivé ikonky vkládají přes <use>.

Velikost ikonky

První záludnost je samotná velikost ikonky. Maximum je výška řádku (jinak by ikonka řádek roztáhla, a tím rozbila řádkování), to je ale v praxi moc – osobně se mi osvědčila velikost o fous větší, než je velikost fontu: používám řádkování 24 px, font 16 px a ikonky 20 px.

Zarovnání ikonky na střed řádku

Pokud používáme ikonky inline v rámci toku textu, ve výchozím stavu se usadí na baseline textu – jejich spodní hrana leží tam, kde spodní hrana malých písmen jako „a“ nebo „m“ (tedy těch, co nezasahují pod řádek). To je poněkud problematické, nejen proto, že spousta ikonek má kolem sebe průhledný okraj, který ikonku uměle posune nad tuto linii, ale taky proto, že ikona často vypadá, jako by byla opticky posunutá mírně nahoru oproti středu textu.

Dá se to štelovat vlastností vertical-align: hodnota middle zarovná střed ikony na střed malých písmen textu (tedy do poloviny tzv. x-výšky), text-bottom zarovná spodek ikony na spodek textu (vč. přesahů pod řádek) a sub zarovná ikonu jako dolní index. Čili neexistuje hodnota, která by ikonku zarovnala na střed řádku :(

Dá se to jedině doladit ručně, když se nastaví hodnota posunu, třeba vertical-align: -4px – takto se dá ikonka napozicovat tak, aby nám to opticky lahodilo vůči textu. Pevný posun v pixelech je ale zrádný, jakmile se změní velikost písma: v nadpisu, v drobném textu nebo když si uživatel v prohlížeči nastaví větší písmo. Proto je lepší použít relativní jednotku em, aby se posun vztahoval k velikosti fontu (v tomto případě -0.25em). Nejsem v tom sám – Font Awesome používá u svých SVG ikon vertical-align: -0.125em.

Posun má ještě jeden, méně viditelný efekt. U běžných fontů zbývá při řádkování 24 px a fontu 16 px nad baseline zhruba 17–18 px místa. Ikonka vysoká 20 px usazená na baseline se tam nevejde a řádek o kousek roztáhne. Posunutá o 4 px dolů už se do řádku vejde celá a řádkování zůstane pravidelné.

Celé nastavení ikonky pak vypadá takhle:

.icon {
  width: 1.25em;          /* 20 px při fontu 16 px */
  height: 1.25em;
  vertical-align: -0.25em;
  fill: currentColor;     /* barva podle okolního textu */
}

Ikonky a pixelart

Mám slabost pro pixelart a spojení pixelartu a ikonek se přímo nabízí. Na internetu existuje obrovské množství pixelartových ikonek (třeba sada Pixelarticons s více než tisícovkou ikon zdarma pod licencí MIT) a snadno si je vyrobíte i sami.

O co jde? Pixelartové ikonky se zkrátka skládají z viditelných čtverečků, jsou záměrně „zubaté“ podobně jako třeba Minecraft nebo staré počítačové hry. Jak tedy vyrobit pixelartovou ikonku?

Nejdříve je potřeba zvolit rozměr, tedy plátno, na kterém budeme ikonku vytvářet. Pokud bychom kreslili po jednom pixelu, ikonka by byla příliš mrňavá a pixely by nebyly dobře rozeznatelné. Pokud bychom dělali kostičky po třech pixelech, už by byla ikonka příliš hrubá, takže 2 px jsou v tomto případě ideál.

Pokud tedy vytvářím ikonku o rozměru 24 × 24 px, bude se skládat z dvanácti čtverečků na výšku a na šířku. Tady narážím na první problém – jak jsem nastínil výše, ikonky vysoké 24 px jsou prostě moc velké, reálně potřebujeme ikonky menší, třeba 20 px. Pokud ale ikonku namaluju na plátno 24 × 24 px a pak ji v prohlížeči zmenším na 20 px, bude rozmazaná – z každé dvoupixelové kostičky se stane kostička o velikosti 1,67 px. Monitor ale umí vykreslit jen celé pixely a cokoli mezi tím chytře fejkuje barevnými odstíny (tzv. vyhlazování), což způsobí právě onu rozmazanost. Nezachrání to ani Retina: tam má kostička 3,33 fyzického pixelu, takže rozmazání je jen méně vidět.

Čili pixelartové ikonky potřebujeme právě v té velikosti, kterou chceme zobrazovat (nebo v jejich násobcích).

Pozor ale i na zvětšení obrazovky ve Windows: při 125 % nebo 150 % odpovídá jednomu CSS pixelu 1,25 nebo 1,5 fyzického a rozmazat se může i ikonka v přesné velikosti. Proti tomu pomáhá SVG atribut shape-rendering="crispEdges", který prohlížeči řekne, ať hrany nevyhlazuje. Kostičky pak nemusí být všechny přesně stejně velké, ale zůstanou ostré.

Tip: Figma

SVG pixelartové ikonky se dají krásně a snadno vyrábět ve Figmě. Stačí vytvořit rámec (frame) o velikosti ikonky, nechat zapnuté přichytávání k pixelové mřížce, naklikat potřebné kostičky, pak je sloučit (Union a potom Flatten, ⌘E) a vyexportovat jako SVG. Vyexportované SVG je potřeba ještě maličko upravit: fill nastavuju na currentColor (ikonka pak přebírá barvu textu) a stroke na none. Pevné atributy width a height mažu, aby velikost řídilo CSS – viewBox ale musí zůstat. Nakonec SVG proženu přes SVGOMG, který odstraní zbytečná metadata (jen pozor, ať v nastavení nechá viewBox).

Výsledek pak vypadá třeba takhle – jednoduché plus na mřížce 20 × 20 px z dvoupixelových kostiček:

<svg class="icon" viewBox="0 0 20 20" fill="currentColor" stroke="none"
     shape-rendering="crispEdges" aria-hidden="true">
  <path d="M8 2h4v6h6v4h-6v6H8v-6H2V8h6z"/>
</svg>

Atribut aria-hidden="true" patří ke každé dekorativní ikonce vedle textu, aby ji čtečka obrazovky přeskočila. Pokud ikonka nese význam sama (třeba tlačítko bez textu), dejte místo toho popisek tlačítku: <button aria-label="Přidat">.

Shrnutí

  • Inline SVG místo ikonkového fontu: načtete jen ikonky, které stránka opravdu používá, a barvu převezmou z textu přes currentColor.
  • Velikost o fous větší než písmo: při fontu 16 px a řádkování 24 px se mi osvědčilo 20 px (1.25em).
  • Posun vertical-align: -0.25em: ikonka opticky sedne doprostřed textu a neroztáhne řádek.
  • Pixelart kreslete ve výsledné velikosti (nebo v jejím násobku) a přidejte shape-rendering="crispEdges", jinak se kostičky rozmažou.

Ikonky vypadají jako drobnost, ale právě na nich je vidět, jestli si s webem někdo vyhrál.

Zdroje