Notes · Notatka 002 · Typografia

Dziesięć języków, trzy pliki fontów

Gdy uruchamiasz stronę w dziesięciu językach, najpierw wykłada się budżet na fonty. Tutaj wytrzymał. Cyrylica i alfabet arabski miały jednak swoją cenę. Pokazaliśmy ją bez ukrywania kosztów.

Serhat Belen

Założyciel, BLN Global · · 6 min czytania

Krótka odpowiedź

Gdybyśmy pobierali te same trzy fonty z Google Fonts, strona po turecku ściągałaby 6 plików o rozmiarze 250 KB z dwóch zewnętrznych źródeł. Z naszego serwera pobiera 3 pliki, 165 KB, z jednego źródła. Większość oszczędności daje zablokowanie nieużywanych osi, a nie podział na podzbiory. Dla cyrylicy i alfabetu arabskiego musieliśmy wybrać osobne rodziny. W arabskim część symboli pochodzi przez to z fontu zastępczego.

Typografia strony opierała się na trzech rodzinach: Archivo do nagłówków, Instrument Sans do tekstu, Martian Mono do liczb i etykiet. Wszystkie trzy były fontami zmiennymi. Przy pięciu językach mieliśmy spokój. Przy dziesięciu naraz urosły dwa problemy: pobierane bajty i zakres alfabetów.

Co z czym porównujemy

Porównywanie surowych plików TTF z opublikowanymi plikami WOFF2 byłoby nieuczciwe. Większość różnicy wynika z kompresji, nie z podziału na podzbiory. Trzeba porównać je z realną alternatywą: ile danych pobrałaby przeglądarka, gdyby te same trzy rodziny pochodziły z Google Fonts.

Nie pobierze wszystkich dziewięciu plików. Przeglądarka unicode-range sprawdza pole i pobiera tylko podzbiory potrzebne stronie. Dla strony po turecku oznacza to latin + latin-ext na każdą rodzinę:

latin 88.0 KB <- latin-ext 83.8 KB <- vietnamese 33.6 KB latin 29.2 KB <- latin-ext 10.8 KB <- latin 23.0 KB <- latin-ext 15.5 KB <- cyrillic 10.3 KB cyrillic-ext 3.1 KB Turecka strona pobierze: 250 KB (6 plików)
Pobraliśmy CSS z Google Fonts, odczytaliśmy unicode-range w każdym bloku @font-face i zmierzyliśmy pliki jeden po drugim. Strzałka pokazuje te, które faktycznie pobiera strona po turecku.
250 KB / 6 plików / 2 zewnętrzne źródła165 KB / 3 pliki / jedno źródło

Ciężar fontów na tureckiej stronie

Jak to zmierzyliśmy Po lewej pomiar powyżej. Po prawej wynik z tego repozytorium archivo.woff2 + instrument.woff2 + martian.woff2 rzeczywisty rozmiar plików na dysku.

Poza bajtami zyskaliśmy jeszcze dwie rzeczy: sześć żądań spadło do trzech, a DNS + TLS do dwóch zewnętrznych źródeł zniknęły całkiem. Jak zamknęliśmy problem zasobu blokującego pierwsze malowanie w notatce o ostatnich 18 punktach opisujemy.

Trzy pułapki

Po pierwsze: podzbiór latin-ext nie zawiera podstawowych liter łacińskich

Przy pierwszej próbie pobraliśmy plik latin-ext z Google Fonts i utworzyliśmy z niego podzbiór. Wynik miał 130 glifów, ale nie zawierał cyfr. Powód był prosty. latin-ext to nakładka na latin. dodatek to podzbiór, a nie pełny alfabet. Pobierz cały font zmienny z repozytorium google/fonts i sam wytnij potrzebny podzbiór.

Po drugie: bez zablokowania nieużywanych osi plik rośnie pięciokrotnie

Każda oś fontu zmiennego zwiększa plik. Projekt używa tylko grubości i szerokości. Jeśli nie zablokujesz pozostałych osi na wartościach domyślnych, ich dane zostają w pliku.

pelny = {a.axisTag: a.defaultValue for a in t['fvar'].axes if a.axisTag not in osie} pelny.update(osie) # osie inne niż wght i wdth blokujemy na wartościach domyślnych, # inaczej plik rośnie pięciokrotnie
Zablokuj oś przed wycięciem podzbioru, a odzyskasz więcej miejsca niż na samym podzbiorze.

Po trzecie: gvar ładuje się leniwie

gdy po zablokowaniu osi w fontTools od razu próbujesz wyciąć podzbiór KeyError: space robimy subset. Powód: leniwe ładowanie danych glifów zmiennych (gvar). Po przypięciu obiekt wygląda w pamięci spójnie, ale narzędzie do subsetowania go nie odczyta. Obejście jest kręte, lecz mieści się w jednej linijce: zapisz plik jako tymczasowy TTF, otwórz go ponownie, potem zrób subset.

Cyrylica i arabski: cena, którą płacisz

Archivo nie ma cyrylicy. Instrument Sans też nie. Żaden z nich nie ma arabskiego. Dla tych dwóch języków musieliśmy wybrać osobne rodziny, a wybór nie był przypadkowy.

  • Rosyjski: Roboto Flex. Jedyne dopasowanie w strukturze: oś szerokości. Czyli wszystkie ustawienia w CSS font-variation-settings działa bez zmiany wartości. Jeden plik obsługuje nagłówki i tekst główny. Strona rosyjska pozostaje lżejsza od łacińskiej.
  • Arabski: Noto Sans Arabic. Jedyny kandydat z osią szerokości. Jeden plik ma 144 KB i pełni trzy role, więc strona arabska pobiera mniej danych niż łacińska.

Cena jest tutaj: w Noto Sans Arabic i nie ma tych znaków. Na arabskiej stronie oba pochodzą z fontu zastępczego i wyglądają trochę inaczej niż sąsiednie znaki. Zamiast to ukrywać, opisaliśmy powód w komentarzu CSS. Kolejna osoba zobaczy tę różnicę i uzna ją za błąd.

Układ od prawej do lewej wymaga osobnej pracy: odwróciliśmy kierunek strzałek i zastąpiliśmy właściwości pozycjonowania ich logicznymi odpowiednikami (margin-inline-start, inset-inline-start), dzięki czemu ten sam CSS działa poprawnie w obu kierunkach.

Mała zmiana: dlaczego Martian Mono ma optional

Dwie z trzech rodzin font-display:swap używa. Martian Mono optional. Powód mamy z pomiaru: przy swap Martian przychodzi późno, każe ponownie zmierzyć przycisk menu i robi przesunięcie układu 0,015. Po preloadzie w praktyce zdąża. Gdy raz nie zdąży, strona nie skacze, tylko zostaje przy foncie zastępczym.

Folder z fontami dla dziesięciu języków zajmuje łącznie 404 KB. Nikt nie pobiera całości. Każda strona ładuje tylko pliki swojego języka.

Częste pytania

Czy lepiej przenieść Google Fonts na własny serwer?

W bajtach nie zawsze. Przy połączeniach najczęściej tak. Google Fonts łączy się z dwoma osobnymi źródłami, a każde nowe źródło każe przeglądarce odpytać DNS i zrobić handshake TLS. U nas pomiar pokazał różnicę: 250 KB / 6 plików / 2 źródła zamiast 165 KB / 3 pliki / jedno źródło.

Co daje więcej: wyciąć podzbiór czy zablokować oś?

Zablokuj oś. Każda oś fontu zmiennego, której nie używasz, zajmuje miejsce w pliku. Jeśli jej nie zablokujesz, plik rośnie kilka razy. Znaki tniesz dopiero potem.

Czy podzbiór latin-ext wystarczy dla tureckiego?

Nie, sam nie wystarczy dla żadnego języka. latin-ext to rozszerzenie zestawu latin. Nie zawiera podstawowych liter ani cyfr. Pobierz pełny font zmienny i sam utwórz z niego podzbiór.

swap czy optional dla font-display?

Jeśli tekst buduje główną część strony, a font wczytujesz wstępnie, optional daje bezpieczniejszy efekt: gdy font się spóźni, strona nie skacze i zostaje przy zapasowym. U nas swap robił na stronach arabskich przesunięcie układu 0,287. optional zbił je do zera.

Jakie fonty wybraliście dla arabskiego i rosyjskiego? Dlaczego?

Dla rosyjskiego Roboto Flex, dla arabskiego Noto Sans Arabic. To nie była decyzja estetyczna, tylko strukturalna: oba mają oś szerokości, czyli obecne w CSS font-variation-settings działa bez zmiany wartości.

Źródła

Powiązane projekty