Використання веб-шрифтів або як не застосовувати правило @font-face

15

Від автора: Використання правила @font-face для завантаження кастомних (користувача) веб-шрифтів — це прекрасна можливість створити для наших сайтів унікальний і запам’ятовується стиль. Однак, коли кастомні шрифти застосовуються в вебі з використанням стандартних технік, то вони можуть знизити швидкість завантаження і негативно позначитися на продуктивності (як реальної, так і сприйманої користувачами). На щастя, ми визначили деякі методи, уважне застосування яких забезпечить вашому сайту баланс юзабіліті, продуктивності і стилю.

Проблема з правилом @font-face

Оголошення CSS правила @font-face є стандартним підходом для вказівки кастомних шрифтів у вебі:

/* Визначаємо кастомный веб-шрифт */
@font-face {
font-family: ‘MyWebFont’;
url(‘webfont.woff2’) format(‘woff2’),
url(‘webfont.woff’) format(‘woff’),
url(‘webfont.ttf’) format(‘truetype’),
}
/* Використовуємо даний шрифт на сторінці */
body {
font-family: ‘MyWebFont’, sans-serif;
}

Просто і зрозуміло, але, на жаль, стандартна обробка правила @font-face в більшості браузерів є проблематичною. Коли ви посилаєтеся на зовнішній веб-шрифт, використовуючи @font-face, більшість браузерів зроблять будь-який текст, до якого застосовується даний шрифт, повністю невидимим на час завантаження цього зовнішнього шрифту. [Див. рис. 1]. Деякі браузери почекають завантаження шрифту якесь встановлене кількість часу (зазвичай три секунди), перш ніж покажуть даний текст, використовуючи альтернативний шрифт, вказаний у властивості font-family. Але браузери на «движку» WebKit (Safari, стандартний браузер Android, Blackberry), прямо як віддані песики, будуть чекати цілу вічність (гаразд, зазвичай 30 секунд) завантаження потрібного шрифту. Це означає, що ваші кастомні шрифти являють собою потенційну «єдину точку відмови» для доступного сайту.

Використання веб-шрифтів або як не застосовувати правило @font-face

Рис. 1: Скріншот веб-сторінки, що завантажується в iOS Safari, де текст залишається невидимим під час завантаження кастомних шрифтів.

Навіть коли шрифти завантажуються коректно, кастомні шрифти уповільнюють сприймається користувачами швидкість роботи сайту, в основному з-за того, що сторінка, на якій багато невидимого тексту, не є корисною для користувачів. Звичайно, якщо сторінка була відвідана одного разу, то кастомні шрифти будуть закешированы і будуть відображатися швидко, але сприймається користувачами швидкість при першому перегляді сторінки є критичним параметром. Якщо наша сторінка не може бути отрисована за кілька секунд, то ми втратимо велику кількість користувачів.

Наприклад, на рис. 2 показана тимчасова лінія на сайті webpagetest.org, на якій видно, як сайт filamentgroup.com буде виглядати при стабільному 3G з’єднання, якщо б використовувалося стандартне поведінку при завантаженні шрифтів. Зверніть увагу на те, що текст, до якого застосовується правило @font-face, починає відображатися тільки через цілу секунду після первинного візуалізації:

Використання веб-шрифтів або як не застосовувати правило @font-face

Рис. 2: Тимчасова лінія завантаження сайту Filament Group (використання стандартної завантаження шрифтів). При 3G з’єднанні завантаження шрифтів затримується на цілу секунду.

Нашим користувачам потрібна готова сторінка, як можна раніше — в ідеалі, протягом однієї секунди — тобто нам потрібно, щоб текст починав відображатися, як можна ближче до даного показника. Є кілька підходів, які можна використовувати в даному випадку, але найголовніше, що ви можете зробити, — це відмовитися від стандартного способу завантаження шрифтів, про який ми говорили раніше.

Ось критерії, якими повинні керуватися при оцінці підходу щодо завантаження шрифтів:

CSS запит, що містить правило(а) font-face, не повинен блокувати рендеринг сторінок. Замість підключення ваших шрифтів через елемент в області або через @import зовнішньої таблиці стилів, спробуйте завантажувати ваші шрифти асинхронно. Не турбуйтеся, ми покажемо вам, як це робити.

Запити шрифтів повинні бути налаштовані таким чином, щоб під час їх завантаження відображався альтернативний текст, що дозволить уникнути мерехтіння/відблисків при завантаженні тексту (Flash of the Invisible Text або FOIT).

Як завантажують шрифти Filament Group

Щоб оптимізувати перше відображення тексту, ми спочатку переконуємося в тому, що властивості font-family крім кастомного шрифту у нас вказано ще і вбудований шрифт, в нашому випадку font-family: Open Sans, sans-serif;. Це стадія, на якій визначається рендеринг тексту з використанням запасного шрифту, поки відбувається завантаження кастомного шрифту, згідно з нашим новим методом завантаження. JavaScript може бути застосований, щоб визначити найкращий для використання формат шрифту (WOFF2, WOFF, TTF) і для асинхронної завантаження таблиці стилів, в якій містяться всі шрифти, прописані за допомогою data: URI. Це трохи нетрадиційний підхід, але це дозволяє нам завантажувати всі кастомні шрифти за один HTTP запит. А це чудово позначається як на скороченні кількості перерахунків розмірів і розташування елементів на сторінці (всі шрифти з’являються відразу), так і на зменшенні кількості HTTP запитів в цілому. Ми можемо піти ще далі, і, після запиту шрифту, встановити куки (cookie), щоб відзначити, що кастомні шрифти були закешированы, і що ми можемо уникнути відблисків/мерехтінь стандартних шрифтів на наступних сторінках.

КРОК 1: ПІДГОТУЙТЕ ВАШІ ШРИФТИ

Кастомні шрифти можуть бути дуже важкими, тому насамперед потрібно мінімізувати кількість шрифтів для завантаження. Пам’ятайте, що кожен варіант насиченості (regular, light, bold) і накреслення (regular italic, bold italic) шрифту є окремим файлом, який може швидко збільшити загальний обсяг завантажуваних шрифтів. Намагайтеся, щоб загальна кількість кастомних шрифтів не перевищувало 5 штук, але ми зазвичай, по можливості, намагаємося використовувати 2-3 шрифту.

Щоб ще покращити доставку шрифтів, використовуйте техніку «розбиття» шрифту, яка дозволяє вам прибрати з шрифту букви і символи, які вам не потрібні. З допомогою сервісу FontSquirrel це досить легко зробити.

КРОК 2: ПІДГОТУЙТЕ ТАБЛИЦІ СТИЛІВ ЗІ ШРИФТАМИ

Кодування шрифтів за допомогою data: URI

Припустимо, що ви використовуєте шрифт Open Sans в двох варіантах насиченості: 400 і 700 (жирний). Щоб забезпечити підтримку найбільшого числа браузерів, нам знадобиться три різних формати для кожного варіанту: WOFF2, WOFF і TrueType (TTF):

OpenSans-Regular.ttf

OpenSans-Bold.ttf

OpenSans-Regular.woff

OpenSans-Bold.woff

OpenSans-Regular.woff2

OpenSans-Bold.woff2

Якщо у вас не вистачає, наприклад, одного з цих форматів, ви можете створити його за допомогою генератора шрифтів Font Squirrel.

Потім візьміть кожен з цих файлів зі шрифтом та закодуйте їх для подальшої вставки в таблицю стилів за допомогою data:URI. Якщо ви не знайомі з тим, як це зробити, то існує багато варіантів: SASS (Compass), PHP, онлайн-генератори або OpenSSL в командному рядку (openssl base64 -in filename.woff).

Скопіюйте отриманий результат в три окремі таблиці стилів, один CSS файл для кожного формату: WOFF2 (data-woff2.css), WOFF (data-woff.css) і TTF (data-ttf.css для Android). Ось, наприклад, як може виглядати data-woff.css:

@font-face {
font-family: Open Sans;
src: url(«data:application/x-font-woff;charset=utf-8;base64,…») format(«woff»);
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: Open Sans;
src: url(«data:application/x-font-woff;charset=utf-8;base64,…») format(«woff»);
font-weight: 700; /* Жирний */
font-style: normal;
}

Усередині всіх інших файлів зі шрифтами запис src: url(…) format(…) повинна відповідати певним форматом. Наприклад, всередині файлу data-woff2.css у вас буде зазначено url(«data:application/font-woff2;charset=utf-8;base64,…») format(«woff2»);, а для data-ttf.css — url(«data:application/x-font-ttf;charset=utf-8;base64,…») format(«truetype»);

КРОК 3: НАЛАШТУЙТЕ ЗАВАНТАЖУВАЧ ТАБЛИЦЬ СТИЛІВ

Після того як файл зі шрифтом підготовлений, нам потрібно завантажувати його асинхронно, щоб уникнути відблисків/мерехтінь тексту. Ми використовуємо для цього нашу утиліту loadCSS. Наприклад, ось як ми можемо використовувати loadCSS для завантаження шрифтів у форматі WOFF2:

loadCSS( ‘/url/to/data-woff2.css’ );

Звичайно, нам потрібно завантажувати відповідну таблицю стилів зі шрифтом для кожного браузера, відвідує наш сайт. Як нам визначити, який формат використовувати? За замовчуванням ми використовуємо формат WOFF завдяки його широкій браузерної підтримки. Якщо браузер проходить перевірку на підтримку формату WOFF2, ми використовуємо формат WOFF2, тому що його розмір зазвичай на 30% менше. Якщо ми можемо досить впевнено визначити, що поточним браузером є стандартний браузер Android на «движку» Webkit (не Chrome), ми перемикаємося на формат TTF з підтримкою для Android 4.X. Пам’ятайте про те, що якщо буде завантажений некоректний формат, то браузер буде використовувати альтернативний варіант з локальними шрифтами.

Ось уривок JavaScript коду, який ми використовуємо для завантаження шрифтів. Ми рекомендуємо розміщувати даний JavaScript код всередині елемента script в області head вашого HTML документа, щоб якомога раніше відправити запит шрифту (більш детальна інформація про те, як ми конфігуруємо область head для наших сторінок за допомогою Enhance.js):

// Увага!! Перевірка підтримки формату WOFF2 і утиліта loadCSS не наведені тут для стислості
var ua = window.navigator.userAgent;
// Використовуємо формат WOFF2, якщо він підтримується
if( supportsWoff2 ) {
loadCSS( «/url/to/data-woff2.css» );
} else if( ua.indexOf( «Android 4.» ) > -1 && ua.indexOf( «like Gecko» ) > -1 && ua.indexOf( «Chrome» ) === -1 ) {
// Стандартний браузер Android використовує формат TTF замість WOFF
loadCSS( «/url/to/data-ttf.css» );
} else {
// За замовчуванням використовується WOFF
loadCSS( «/url/to/data-woff.css» );
}

Браузер не буде робити текст невидимим, оскільки наш CSS файл data:URI завантажується асинхронно. Це означає, що можна буде прочитати альтернативний текст, поки відбувається завантаження наших веб-шрифтів (навіть якщо запит «завис» і відповіді так і не було отримано).

На рис. 3 показані зміни: з допомогою цієї техніки ми відразу ж, при первинному рендерінгу, отримуємо текст, який можна читати. Ось що ми отримуємо (тимчасова лінія при 3G з’єднання):

Використання веб-шрифтів або як не застосовувати правило @font-face

Рис. 3: Успіх! Ось тимчасова лінія завантаження нашого сайту з використанням нашого способу завантаження кастомних шрифтів. Якщо використовується 3G з’єднання, то шрифт вже відображається при первинному рендерінгу.

Щоб ви могли дізнатися детальніше про даному підході, ми також підготували для вас вихідний код на GitHub.

Використовуємо cookie-файли, щоб було ще краще

На даний момент ми сфокусувалися на підготовку і вдумливої завантаженні наших кастомних шрифтів. Таким чином, ми можемо показувати альтернативний шрифт, поки ми чекаємо завантаження наших кастомних шрифтів. Коли потрібні шрифти дійсно завантажаться, браузер замінить стандартні шрифти на кастомний. Це викличе переотрисовку і, як правило, невеликі зрушення в розмітці, т. к. шрифти мають трохи різні розміри. Ми вважаємо, що при першому відвідуванні сторінки така «жертва» є виправданою, оскільки ми в рази швидше надаємо користувачам готову сторінку, але подібна ситуація може дратувати користувачів при здійсненні навігації по сайту.

Щоб вирішити цю проблему, ми використовуємо куки, щоб визначити, завантажилися чи кастомні шрифти і вони знаходяться в кеші браузера. Якщо так, то ми відразу ж показуємо кастомні шрифти, щоб уникнути будь-яких зрушень в розмітці.

Замість завантажувача шрифтів нам потрібно інший завантажувач, який наведено нижче. Ми будемо додавати файли cookie, щоб наголосити, що наші шрифти закешированы. Плюс, куки також містять URL на конкретний формат шрифту (data-woff2.css, data-woff.css або data-ttf.css). Не забудьте використовувати утиліту Filament Group для роботи з куками:

// Увага!! Перевірка підтримки формату WOFF2, утиліти loadCSS і cookie не наведені тут для стислості
// За замовчуванням використовується WOFF
var fontFileUrl = «/url/to/data-woff.css»,
ua = window.navigator.userAgent;
// Використовуємо формат WOFF2, якщо він підтримується
if( supportsWoff2 ) {
fontFileUrl = «/url/to/data-woff2.css»;
} else if( ua.indexOf( «Android 4.» ) > -1 && ua.indexOf( «like Gecko» ) > -1 && ua.indexOf( «Chrome» ) === -1 ) {
// Стандартний браузер Android використовує формат TTF замість WOFF
fontFileUrl = «/url/to/data-ttf.css»;
}
// Додано: Переконайтеся в тому, що шрифти ще не закешированы
if( fontFileUrl && !cookie( «fonts» ) ) {
// Завантажуємо шрифти асинхронно
loadCSS( fontFileUrl );
// Додано: Встановлюємо куки, показують, що шрифти закешированы
// Куки також вказують на використовуваний формат (WOFF, WOFF2 або TTF)
cookie( «fonts», fontFileUrl, 7 );
}

Потім додаємо наступний код з розміткою в область , замінюючи значення кожної змінної fontsWOFF, fontsWOFF2, fontsTTF на URL, який містить адресу до CSS файлу зі шрифтом. Зверніть увагу на те, що коли куки були встановлені і містять значення URL, що містить формат шрифту для завантаження, вставляється блокуючий елемент link, який вказує на CSS файл data:URI. Однак, блокуючу поведінку цього запиту в даному випадку нормально, оскільки даний CSS запит вже був закеширован браузером і буде завантажений практично миттєво.

Вищенаведений код вимагає наявності спеціального модуля сервера Apache, але ви можете використовувати щось схоже на будь-якому сервері мовою.

Щоб дізнатися більше про даному підході з використанням кук, ми також підготували для вас вихідний код на GitHub.

Підбиваючи підсумок

Використання веб-шрифтів може бути по-справжньому чудовим способом поліпшення якості вашого веб-проекту, але завантаження шрифтів звичайним способом може бути дуже згубною для сприйняття користувачами продуктивності сайту. Вищенаведений метод відмінно справляється з проблемою невидимого тексту, що асоціюється зазвичай з правилом @font-face, і набагато швидше робить наші сторінки доступними для користувачів. Ми сподіваємося, що для вас і ваших користувачів) це виявиться корисним!