← Назад к вопросам

Как загружаются шрифты если браузер не поддерживает некоторые форматы?

1.0 Junior🔥 191 комментариев
#HTML и CSS

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как загружаются шрифты, если браузер не поддерживает некоторые форматы

Загрузка шрифтов — сложный процесс. Браузер может не поддерживать все форматы, и нужно предусмотреть fallback. Расскажу, как это работает в деталях.

1. Основной механизм — multiple formats

@font-face {
  font-family: 'MyFont';
  src: 
    url('/fonts/myfont.woff2') format('woff2'),
    url('/fonts/myfont.woff') format('woff'),
    url('/fonts/myfont.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
}

Как это работает:

  1. Браузер читает список форматов слева направо
  2. Пытается загрузить первый (woff2)
  3. Если браузер его поддерживает — загружает и использует
  4. Если нет — переходит к следующему (woff)
  5. И так до тех пор, пока не найдёт поддерживаемый или не закончится список

Пример: Internet Explorer не поддерживает woff2

Browser: IE 11
- Пробует woff2? НЕТ (не поддерживает)
- Пробует woff? ДА! Загружает его
- Остальное игнорирует

Browser: Chrome
- Пробует woff2? ДА! Загружает его (самый компактный)
- Остальное игнорирует

2. Форматы шрифтов и поддержка браузерами

ФорматРазмерIE 9+ChromeFirefoxSafariПоддержка
WOFF2Очень малыйНетДа (26+)Да (39+)Да (11+)Отличная для современных
WOFFМалыйДа (6+)ДаДаДа (5+)Универсальная
TTFСреднийНетДаДаДаХорошая
OTFСреднийНетДаДаДаХорошая
EOTСреднийДа (4+)НетНетНетТолько IE (устаревший)
SVGБольшойНетДа (?)НетДаСтарые Safari

3. Лучшая стратегия — минимальный набор

/* Для современных браузеров достаточно WOFF2 + WOFF */
@font-face {
  font-family: 'Inter';
  src: 
    url('/fonts/inter.woff2') format('woff2'),
    url('/fonts/inter.woff') format('woff');
}

/* Если нужна совместимость со старыми браузерами */
@font-face {
  font-family: 'OpenSans';
  src:
    url('/fonts/opensans.woff2') format('woff2'),    /* Chrome 26+, Safari 11+ */
    url('/fonts/opensans.woff') format('woff'),      /* IE 9+, все современные */
    url('/fonts/opensans.ttf') format('truetype');   /* Fallback */
}

4. Система fallback шрифтов (generic families)

Если все форматы не загрузятся, браузер использует систему fallback:

body {
  /* Первый выбор — наш шрифт, второй — что-то похожее, третий — generic */
  font-family: 'Inter', 'Helvetica Neue', sans-serif;
}

heading {
  font-family: 'Playfair Display', 'Georgia', serif;
}

code {
  font-family: 'Fira Code', 'Courier New', monospace;
}

Generic families:

  • sans-serif — без засечек (Helvetica, Arial, Verdana)
  • serif — с засечками (Times New Roman, Georgia)
  • monospace — моноширинный (Courier, Courier New)
  • cursive — рукописный (Comic Sans, Brush Script)
  • fantasy — фантазийный (Impact, Papyrus)

5. Как браузер выбирает шрифт

// Если взять @font-face выше
const computedStyle = window.getComputedStyle(document.body);
console.log(computedStyle.fontFamily);
// Вывод зависит от загрузки:
// 1. Если Inter загрузился: '"Inter"' или просто браузер использует его
// 2. Если не загрузился: '"Helvetica Neue"' (fallback)
// 3. Если ничего не загрузилось: generic sans-serif (системный шрифт)

6. Использование @font-face с media queries

/* Разные шрифты для разных экранов */
@font-face {
  font-family: 'MyFont-Light';
  src: url('/fonts/myfont-light.woff2') format('woff2');
}

@media (max-width: 768px) {
  body {
    font-family: 'MyFont-Light', sans-serif; /* Легче для мобильных */
    font-size: 14px;
  }
}

@media (min-width: 769px) {
  body {
    font-family: 'MyFont', sans-serif; /* Полный шрифт для десктопа */
    font-size: 16px;
  }
}

7. Современный подход с Next.js и Google Fonts

// next/font/google автоматически выбирает лучший формат
import { Inter, Playfair_Display } from 'next/font/google';

const inter = Inter({ 
  subsets: ['latin', 'cyrillic'],
  display: 'swap' // Показать fallback шрифт пока загружается
});

const playfair = Playfair_Display({ 
  subsets: ['latin'],
  weight: ['400', '700'],
  variable: '--font-playfair' // CSS переменная
});

export default function App() {
  return (
    <html className={`${inter.className} ${playfair.variable}`}>
      <body>
        {/* Inter загружен автоматически */}
        <h1 style={{ fontFamily: 'var(--font-playfair)' }}>Title</h1>
      </body>
    </html>
  );
}

Next.js автоматически:

  • Выбирает WOFF2 для современных браузеров
  • Оптимизирует размер
  • Использует font-display: swap для быстрой загрузки

8. font-display стратегия

@font-face {
  font-family: 'MyFont';
  src: url('/fonts/myfont.woff2') format('woff2');
  font-display: swap; /* Какая стратегия при загрузке? */
}

Варианты:

ЗначениеПоведениеКогда использовать
autoПо умолчанию браузераРедко задаём явно
blockЖдём 3 сек, потом swapДля важных шрифтов
swapСразу fallback, потом swapДля основного текста
fallbackСразу fallback, потом swap с таймаутомДля шрифтов которые не так важны
optionalСразу fallback, swap если успели 100мсДля декоративных шрифтов
/* Основной шрифт — показываем fallback сразу */
body {
  font-family: 'Inter', sans-serif;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-display: swap; /* swap для основного текста */
}

/* Декоративный шрифт — можно подождать */
h1 {
  font-family: 'Playfair Display', serif;
}

@font-face {
  font-family: 'Playfair Display';
  src: url('/fonts/playfair.woff2') format('woff2');
  font-display: fallback; /* fallback для декоративных */
}

9. Проверка поддержки форматов JavaScript

// Проверяем, что браузер поддерживает
const isFontFormatSupported = async (format) => {
  try {
    return await document.fonts.check(`1em TestFont`);
  } catch {
    return false;
  }
};

// Более правильная проверка
function isFontSupported(fontName) {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const text = 'Test';
  
  const width1 = ctx.measureText(text).width;
  ctx.font = `12px "${fontName}", sans-serif`;
  const width2 = ctx.measureText(text).width;
  
  return width1 !== width2; // Если отличается — шрифт загружен
}

console.log(isFontSupported('Inter')); // true/false

10. Практический пример: полная стратегия

/* HTML файл */
<head>
  <style>
    /* 1. Локальный системный шрифт (максимально быстро) */
    @font-face {
      font-family: 'Inter';
      src: local('Inter');
    }
    
    /* 2. Скачиваемые форматы (для современных браузеров) */
    @font-face {
      font-family: 'Inter';
      src: 
        url('/fonts/inter.woff2') format('woff2'),
        url('/fonts/inter.woff') format('woff');
      font-display: swap;
    }
  </style>
</head>

<body style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
  <!-- Если Inter не загрузился, будет использован fallback -->
</body>

11. Оптимизация размера

# Уменьшаем размер шрифта, используя subsetting
# Берём только нужные символы (например, только латинский + кириллица)

# Инструмент: subsetter (например, FontTools)
fonttools subset myfont.woff2 --unicodes="U+0000-007F,U+0400-04FF" 
output myfont-subset.woff2

Ключевой вывод

Браузер загружает шрифты следующим образом:

  1. Читает @font-face слева направо по форматам
  2. Пытается загрузить первый поддерживаемый формат
  3. Если не поддерживается — переходит к следующему
  4. Если ничего не загрузилось — использует fallback шрифт
  5. Если fallback тоже нет — использует generic family (sans-serif, serif, etc.)

Рекомендации:

  • Используй WOFF2 + WOFF для современных браузеров
  • Добавь TTF для совместимости
  • Используй font-display: swap для быстрой загрузки
  • Всегда указывай fallback: font-family: 'MyFont', sans-serif
  • Для Next.js используй next/font (это автоматизирует всё)