Это зависит от задачи. Расскажу, как мы решаем эту проблему в книгах бюро.
Книги предназначены для длительного и многократного чтения. Мы оптимизируем загрузку шрифтов соответственно: никаких миганий, первое открытие медленное, последующие — быстрые.
Долгое время мы загружали веб‑шрифты, кодируя их в Base64 и встраивая прямо в ЦСС. Это медленно: шрифты весят на 30% больше, плюс уходит время на декодирование. Когда мы вынесли шрифты из ЦСС и стали загружать их в WOFF2 по HTTP/2, время до первой отрисовки сократилось на треть.
А чтобы при следующем открытии шрифты не грузились заново, явно кешируем их навечно:
cache-control:max-age=315360000
expires:Thu, 31 Dec 2037 23:55:55 GMT
Чтобы шрифты загружались ещё быстрее, используем предзагрузку: браузер начинает скачивать шрифты одновременно с загрузкой страницы, а не когда увидит их в стилях и убедится, что они нужны на странице.
<head>
<title>...</title>
<link rel="preload" as="font" type="font/woff2"
href="https://fonts.bureau.ru/1.6/bureausans-regular.woff2"
crossorigin>
<link rel="preload" as="font" type="font/woff2"
href="https://fonts.bureau.ru/1.6/bureausans-bold.woff2"
crossorigin>
</head>
Чтобы шрифты не мигали, мы дожидаемся их загрузки и готовности. Для этого в книгах есть «пробники» — элементы с заданным шрифтом и требуемой шириной.
Например, мы знаем, что слово mmm, набранное Бюросансом с кеглем в 100 пикселей, имеет ширину 238 пикселей на экране. То же слово, набранное системным шрифтом, — 250 пикселей. Значит, если ширина элемента с текстом mmm равна 238 пикселям, шрифт загружен и готов к использованию.
<style>
.fontChecker {
position: fixed;
z-index: -1;
font-size: 100px;
opacity: 0;
}
.fontChecker::before {
content: 'mmm';
}
</style>
<div
style="font-family: Bureausans;"
data-min-width="237"
data-max-width="240"
class="fontChecker js__fontChecker">
</div>
Перед запуском книга ждёт, пока размеры всех пробников не попадут в требуемые:
let fontCheckInterval
// Как часто проверяем пробники
const FONT_CHECK_INTERVAL = 100
// Максимальное время ожидания шрифтов
const MAX_FONTS_WAIT = 4000
const isFontLoaded = (font) => {
const probeWidth = font.$el.width()
return probeWidth >= font.minWidth && probeWidth <= font.maxWidth
}
const onFontsReady = (callback) => {
const fonts = $('.js__fontChecker').map((_, el) => {
const $el = $(el)
return {
$el: $el,
minWidth: +$el.attr('data-min-width'),
maxWidth: +$el.attr('data-max-width'),
}
}).get()
let timeSpent = 0
fontCheckInterval = setInterval(function() {
const allFontsReady = fonts.every(isFontLoaded)
// Если все шрифты уже готовы или
// мы так и не дождались их загрузки,
// отрисовываем страницу
if (allFontsReady || timeSpent > MAX_FONTS_WAIT) {
clearInterval(fontCheckInterval)
callback()
}
timeSpent += FONT_CHECK_INTERVAL
}, FONT_CHECK_INTERVAL)
}
// onFontsReady(initApp)
Ещё по теме
P. S. Это был совет о веб‑разработке. Хотите знать всё о коде, тестах, фронтенд‑разработке, цеэсэсе, яваскрипте, рельсах и джейде? Присылайте вопросы.