O ikonkach słów kilka
Każdy z nas na pewno choć raz w życiu użył icon fontów – czy to Fontello, czy Font Awesome. Jednak nie każdy z nas zastanawiał się, jaki jest idealny sposób na wstawianie ich na stronę.
Tradycyjne sposoby
Zacznijmy od tego, że ikonki nie są jakimiś semantycznymi elementami – to co najwyżej obrazki, więc i
jest z założenia złe, co W3C już dawno ustaliło. Zatem nie ma co słuchać poradnika na Font Awesome i lepiej zostać przy span
Jeśli wstawiana ikonka jest tylko ozdobnikiem, a treść, jaką prezentuje, jest przekazywana także w inny sposób (np. przez tekst występujący obok niej), to wtedy mamy do czynienia z najprostszą sytuacją:
<span class="icon icon_email" aria-hidden="true"></span>
Czemu pusty element? Ponieważ to najprostszy sposób na stworzenie elementu, który będzie ignorowany przez czytniki ekranowe. Dodanie [aria-hidden=true]
sprawi, że czytnik ominie ten element (i tylko ten). Jest to konieczne, ponieważ czytniki ekranowe czytają znaczki Unicode, które są wstawione w pseudoelementy (np. ★ zostanie przeczytane przez VoiceOver jako “black star”). I tak, icon fonty używają niby tak odległych kodów Unicode, że nie powinny być do nich przypisane żadne znaki, ale emojis dodaje się do standardu tak dużo, że w końcu mogą zacząć pojawiać się jakieś konflikty. Zwłaszcza, że przecież system też może wykorzystać te rejony Unicode.
Natomiast jeśli ikonka niesie treść sama w sobie (nie towarzyszy jej żaden tekst), to wówczas można zrobić tak:
<span role="img" class="icon icon_email" aria-label="E-mail"></span>
Tak, powinno być użyte co najmniej [aria-label]
. [title]
też może zadziałać, ale pojawia się pewien problem: [title]
jest czytany tylko wówczas, gdy zawartość elementu nie jest możliwa do przeczytania. Czyli wracamy do problemu z Unicode. W przypadku [aria-label]
problemu nie ma, bo jest on czytany zamiast zawartości elementu (zawsze, nawet jak zawartość to całkowicie normalny tekst). Dodatkowo trzeba dodać elementowi odpowiednią rolę (z racji, że to ikonka, najlepiej użyć img
) – inaczej sposób może nie zadziałać.
Bardziej dostępne sposoby
Niemniej to jest dość słaby sposób, ponieważ działa tylko i wyłącznie dla czytników ekranowych (i to nie w przypadku korzystania równocześnie z Google Translate, jak zauważa Heydon). A co w sytuacjach, gdy style się nie doczytają, strona będzie użyta w przeglądarce tekstowej etc.? Innymi słowy mówiąc: jak sprawić, żeby ikonka działała naprawdę zawsze?
<span class="icon icon_email" aria-hidden="true"></span>
<span class="visuallyhidden">E-mail</span>
Implementację .visuallyhidden
warto skopiować z HTML5 Boilerplate – .sr-only
z BS-a wciąż nie jest zaktualizowane zgodnie z najnowszym feedbackiem ze strony FB czy Drupala.
W jeszcze idealniejszym świecie wszystko wyglądałoby jakoś tak:
<span class="icon">
<span class="icon__image" data-icon="email" aria-hidden="true"></span>
<span class="icon__label">E-mail</span>
</span>
Przykładowa implementacja, oparta na… image replacement. Chyba jedyny problem z tym to fakt, jak się dowiedzieć, czy icon font się wczytał i kiedy pokazać ikonę zamiast etykiety. Niemniej tego typu kod radzi sobie z większością scenariuszów, jakie wyżej opisałem.
A może by tak SVG?
Ale to wciąż wszystko hacki – bo przecież tym jest sama idea icon fontów. A prawda jest taka, że mamy rok 2017 i aż się prosi, żeby po prostu stosować SVG. Wówczas ikonki wyglądają tak:
<img src="nasz-svg#name-of-view" alt="Tekst alternatywny">
Oczywiście [alt]
jak dla normalnego obrazka: jeśli ikonka to ozdobnik – pusty, jeśli niesie treść – wiadomo. Można nawet używać sprite’ów i – jak widać – wsparcie jest zadziwiająco dobre. Dodatkowo SVG nie posiadają takich problemów z dostępnością, jak icon fonty.
Casus [title]
Ktoś pewnie jeszcze zapyta: “A co z [title]
? Przecież dostarcza informacji o ikonce użytkownikom myszki!”. No i właśnie tutaj jest największy problem: tylko użytkownikom myszki. Jeślibyśmy chcieli zrobić naprawdę dobry tooltip dla ikonek, który by działał np. też dla użytkowników klawiatury, warto rozważyć oskryptowane alternatywy.
Jak widać, sposobów na wstawienie icon fontów jest kilka, a najlepszy z nich to… wstawienie SVG.
Komentarze
Przejdź do komentarzy bezpośrednio na Githubie.
Dawne komentarze
Ten blog wcześniej korzystał z systemu komentarzy Disqus. Jednakże pożegnaliśmy się i postanowiłem, że zaimportuję do nowej wersji stare komentarze z niego. Cóż, jego system eksportu na wiele nie pozwala…
<3
tak tylko się wtrącę, że sr-only już jest zaktualizowany w bs-ie, na pewno w wersji v4.0.0-alpha.6 bo sprawdzałem osobiście, za wcześniejsze wersje nie ręczę
Faktycznie, niemniej to wydaje się jakaś inna wersja niż ta w HTML5 Boilerplate. Tak jakbyśmy na chwilę obecną mieli 3 równoległe wersje: starą, BS-a i H5BP
SVG w IMG. To jest dobre rozwiązanie gdy ikona jest statyczna. A co zrobić gdy chcemy zrobić efekt hover na niej i zmienić kolor? Jak to ustawić to w css? Mam w pliku SVG coś takiego:
<path class="zmien-mi-kolor" fill="" d="M24...
HTML:
<img src=" img="" icon.svg#zmien-mi-kolor"="">
CSS:
.zmien-mi-kolor {
fill: red;
}
Kombinowałem na wiele sposobów, bez efektów.
Wówczas trzeba niestety zastosować inline SVG, wstawione bezpośrednio do kodu HTML. Na `img` to średnio działa – a szkoda.
Lub użyć JavaScript. A szkoda.
Ziomeczki, a co z svg use ? Możecie użyć już tego jako zewnętrzny sprite. Ustawiacie fill na pathie jako currentColor. I w css możecie kolorować dowoli! Spoko artykuł https://fvsch.com/code/svg-...
Dodatkowo przyda się lekki polyfill ( w zależności co musicie supportować ) https://github.com/jonathan...
Ja wraz z nowym rokiem przerzuciłem się właśnie na svg sprites, ponieważ dają nam więcej możliwości, a utrzymywanie ico-fontów wygląda o wiele słabiej - zawsze to utrzymywanie kilka plików, nie jednego.
Owszem, można, ale i tak ostatecznie to jest wstawienie SVG do HTML-a.
Ładowanie zewnętrznych spritów to jest wstawianie SVG do HTML-a ? Nie miałem na myśli wstawiania na żywca całego kodu ze sprajta w kod HTML. Miałem raczej na myśli
Noo… To wciąż SVG ;) Owszem, w tym wypadku mamy tylko svg > use, ale to wciąż nie jest to samo, co img. Zwłaszcza, że dostarczenie treści alternatywnej jest nieco udziwnione w takim wypadku.
Ale fakt, jest to lepsze niż pakowanie całego SVG. Niemniej sprite'y w img też działają niemal wszędzie – oprócz kochanego Safari.
Tylko wtedy z tego co się orientuję, jak ładujesz sprite jako img nie masz właśnie tej możliwości pokolorowania danej ikonki przez css. Co do treści alternatywnych jest to faktycznie trochę udziwnione, ale da się. Generalnie widać, że to się rozwija w dobrym kierunku, w kierunku używalności ;-)
Fakt, nie da się. Ciekawe jak to zmienią, bo nie widzę za dużo możliwości ingerowania w SVG wstawione przez img.
Chociaż AFAIR byłyby pomysły z przekazywaniem jakoś CSS variables jako części hasha.
Nooo to było by piękne, ale narazie musimy zadowolić się tym co jest i balansować w wyborze dobrego rozwiązania. Jeszcze ciekawostka, że zmiennych CSS variables możemy już użyć też w svg inline. https://fvsch.com/code/svg-...
Nie jestem pewien czy zewnętrzny SVG zaczyta Tobie klasę CSS z innego pliku ? Co innego jak byś tą klasę CSS miał w samym pliku SVG wtedy możesz na pathie ustawić. Najłatwiejszym rozwiązaniem jest to co opisałem poniżej czyli na pathie w SVG ustawiasz fill jako currentColor a w CSS działasz już na właśności 'color'.
Czy svg nie powinno byc wstawiane przez <obvject> a nie <img> ?
`object` to pozostałość po dawnej, dawnej erze, gdy przeglądarki nie umiały w SVG. Obecnie stosuje się albo `svg`, albo `img`.
Miałem problem gdzie svg wstawione przez img działało wszędzie tylko nie na chrome. Wstawienie przez object pomogło
A jaki Chrome? Bo od kilkunastu wersji nie powinno być takich problemów.
Jeszcze nie zakopywałbym 'object'. Przekonałem się o tym, gdy chciałem użyć animacji GSAP na zewnętrznym, skomplikowanym svg. Oprócz 'object' mogłem jeszcze użyć ajaxa, aby wstrzyknąć svg do DOM HTML. Ze wspomnianym 'use' nie tylko był problem z wykonaniem animacji (GSAP), ale też z poprawnym wyświetlaniem pliku w Chrome. Nie wiem dlaczego, ale wyświetlał tylko część ilustracji. Nie wgłębiałem się w to zbytnio, bo jak już napisałem, 'object' ocalił mi skórę :)
Hm, ciekawe. Niemniej brzmi bardziej jak edge case.