Перевод статьи Zell Liew «Viewport Unit Based Typography».
UPDATE 21.11.2016
Если размер шрифта по данной формуле указан и у родителя, и у дочернего элемента, то дочерний элемент высчитывает процент от родительского и устанавливает его неправильно.
Чтоб избежать данной проблемы нужно заменить проценты на rem-ы (чтоб размер высчитывался не относительно родителя, а относительно корневого элемента). То есть, если размер шрифта стоит по умолчанию (16px), а размер какого-то блока нужен, например, 24px, то в формуле указываем не 150%, а 1.5rem.
Что такое viewport-юниты?
Есть четыре разных viewport-юнитов на сегодня:
- vw — процент от ширины вьюпорта
- vh — процент от высоты вьюпорта
- vmax — наибольшее значение из vw и vh
- vmin — наименьшее значение из vw и vh
В данном случае, под вьюпортом подразумевается окно браузера. То есть 1vw — это 1% от ширины окна. 100vw, соответственно, — полная ширина окна.
Плюс viewport-юнитов заключается в том, что они автоматически пересчитываются при изменении окна браузера. Это происходит при загрузке, при изменении размера окна или при смене ориентации устройства.
Итак, если viewport-юниты автоматически пересчитываются, то это даёт нам возможность легко создать элемент, который всегда занимает четверть от размера окна.
.component {
width: 50vw;
height: 50vh;
background: rgba(255, 0, 0, 0.25)
}
Итак, это был раздел «viewport для чайников». А теперь вперёд, к самой мякотке!
Использование viewport-единиц для адаптивной типографики
Есть одна причина из-за которой вы должны подумать о том, чтобы использовать viewport-юниты в типографике: они автоматически пересчитываются в зависимости от размера окна браузера пользователя. Это означает, что вам не нужно менять размеры шрифта в медиа-запросах.
Давайте рассмотрим пример, чтобы понять о чём идёт речь.
Рассмотрим код, в котором мы меняем размер шрифта с 16px на 20px, при достижении размером окна 800px:
// Здесь и далее стили написаны на SCSS
html {
font-size: 16px;
@media (min-width: 800px) {
font-size: 20px;
}
}
В коде вы видите, что размер шрифта прыгает с 16px до 20px, когда размер окна становится больше 800px. Так мы делали долгое время и это нормально.
Иногда приходится добавлять ещё один промежуточный медиа-запрос, чтобы указывать какое-то среднее значение размера шрифта, при котором всё будет отображаться нормально:
html {
font-size: 16px;
@media (min-width: 600px) {
font-size: 18px;
}
@media (min-width: 800px) {
font-size: 20px;
}
}
Обычно, мы ограничиваемся тремя-четырьмя промежуточными медиа-запросами. Можно использовать больше, но это уже будет перебор.
Но что, если вы хотите получить тот же результат, но без указания лишних медиа-запросов и лишнего изменения размера шрифта?
Вот тут-то на сцену и выходят viewport-юниты. Вы можете легко получить тот же результат, прописав viewport-юниты для указания размера шрифта.
Посмотрим на следующий код:
html { font-size: 3vw; }
Круто, да?
Но проблема в том, что viewport-единицы слишком чувствительны к изменению размера окна.
Если вы укажете размер шрифта 3vw, как в примере выше, то получите размер шрифта в 10px на экране шириной в 320px (мобильные) и 43px на экране шириной в 1440px (ноутбук). Это слишком маленькое и слишком большое значение.
Теперь перед нами стоит интересная задача — укрощение вьюпорта.
К счастью, есть простой способ решения данной проблемы: мы установим минимальное значение размера шрифта и будем его увеличивать с помощью небольшого viewport-значения, используя calc().
Вот как это выглядит:
html { font-size: calc(18px + 0.25vw) }
Круто, не так ли? Я узнал об этом способе от Mike Riethmuller в его статье «Precise control over responsive typography».
К сожалению, я понял, что этот код не работает в некоторых браузерах. Например, это не работает на Safari для Mac.
Исправление, на удивление, просто. Мы совмещаем использование процентов и vw и это позволяет данному коду работать в Safari:
html { font-size: calc(112.5% + 0.5vw) }
Тадам!
Отлично! Теперь мы реально можем перестать использовать em-ы, rem-ы и медиа-запросы? Я не могу дождаться момента, когда попробую это!
Следующая проблема, которую я должен был решить, — указание в viewport-единицах размеров заголовков (h1-h6).
Установка размера других элементов типографики в viewport-единицах
Первое что я попробовал — это создание заголовка h1, который в два раза больше основного шрифта. Оказалось, что не всё так просто
Я просто взял значение, указанное в font-size для html, и умножил его на два. Но получилось, что размер заголовка стал больше, чем он должен был быть:
html { font-size: calc(112.5% + 0.25vw) }
h1 { font-size: calc((112.5% + 0.25vw) * 2); }
Это случилось потому что я использовал font-size для h1 основанный на процентах. То есть, я пересчитал font-size для h1, после того, как он унаследовал уже пересчитанный размер у html.
Давайте рассмотрим это на примере и, для удобства, используем другие числа. Представим, что мы сейчас размер нашего окна составляет 800px , а значение шрифта — 16px.
- Сначала вычисляется значение font-size для html: 112.5% от 16px = 18px (112.5/100 * 16px)
- Затем вычисляется значение, указанное в vw: 800px * 0.25 ÷ 100 = 2px
- И, наконец, значения складываются: 18px + 2px = 20px
Пока всё идёт хорошо. Отлично!
Мы будем использовать тот же метод для вычисления размера h1. Обратите особое внимание на значение 112.5% в вычислении.
- 112.5% для h1 превращается в 22.5px (112.5/100 * 20px)
- 0.25vw, всё также, равно 2px (800px * 0.25 ÷ 100)
- В итоге получаем 49px ((22.5px + 2px) * 2)
Значение h1 должно было быть равным 40px, так как оно должно быть в два раза больше основного текста. А 49px не равно 40px
Проблема вызвана наследование значения font-size для h1 от html. Есть два решения этой проблемы.
Первое: просто заменить 112.5% на 100% для h1:
h1 { font-size: calc((100% + 0.25vw) * 2) }
Второе: убедитесь, что размер шрифта не наследуется элементами.
h1 { font-size: calc((100% + 0.25vw) * 2) }
p { font-size: calc((100% + 0.25vw)) }
Оба способа не очень хороши и меня это не устраивало.
В итоге, я решил, что лучший способ — использование rem и em. Не стоит забывать о старых друзьях, когда появились новые.
html { font-size: calc(112.5% + 0.25vw) }
h1 { font-size: 2em; }
Так как мы говорим об изменении размера шрифта, следующий вопрос, который мы зададим себе, будет «А что там с межстрочными интервалами?».
Ну что ж, давайте теперь поговорим об этом.
Межстрочные интервалы при использовании viewport-юнитов
Ответ прост. Вы заметили, что viewport-юниты используются только для установки значения для корневого элемента (html)? Во всех остальных случаях мы всё ещё используем rem-ы и em-ы! Это означает, что вы можете использовать rem-ы и em-ы так, как я описывал в статье «Everything I know about Responsive Web Typography». Ничего не изменилось!
Чуть не забыл! Ещё одна вещь, о которой стоит сказать до того, как мы закончим статью.
Была ещё одна проблема, которую мне пришлось решить: «Как рассчитать так, чтобы размер шрифта был 20px при достижении окном размера 800px?». Вопрос можно сократить до одного слова — «Точность». Проще говоря, как я могу быть точно уверен, что размер шрифта станет таким, каким надо, при увеличении окна до 800px?
Точность
Оказывается, Майк решил эту проблему. Давайте просто возьмём его формулу и разберём её.
Итак, что мы хотим:
- При viewporte в 600px font-size равен 18px
- При viewporte в 1000px font-size равен 22px
Первое что мы делаем — преобразуем меньшее значение (18px) в проценты: 18/16 * 100% = 112.5%.
Следующее: мы вычисляем количество vw. Здесь чуть сложнее.
Для этого мы возьмем разницу между font-size (22px — 18px), поделим на разницу viewport-а (1000 — 600) и умножим на 100vw — меньшее значение viewport-а (100vw — 600px).
Вот как это выглядит:
html {
font-size: calc(112.5% + 4 * (100vw - 600px) / 400)
}
Это может показаться немного сложным, но как только вы поймете из чего он состоит, то сможете упростить его в SASS-миксин.
Indrek Paas уже сделал это здесь.
Супер точность
А что делать, если вы хотите, чтобы шрифт увеличивался с разной скоростью в разных промежутках?
Вот один из ответов:
html {
font-size: 100%;
// Увеличиваем шрифт на 1px каждые 100px от 600px до 1000px
@media (min-width: 600px) {
font-size: calc(112.5% + 4 * (100vw - 600px) / 400)
}
// Увеличиваем шрифт на 0.5px каждые 100px от 1000px до 2000px
@media (min-width: 1000px) {
font-size: calc(137.5% + 5 * (100vw - 1000px) / 1000)
}
}
Но в реальности вы, скорее всего, не будете увеличивать шрифт с разной скоростью.
Поэтому более реалистичным будет следующий код:
html {
font-size: 100%;
// Увеличиваем размер шрифта на 1px каждые 100px от 600px и выше
@media (min-width: 600px) {
font-size: calc(112.5% + 4 * (100vw - 600px) / 400)
}
// Устанавливаем размер шрифта в 22px после 1000px
@media (min-width: 1000px) {
font-size: calc(137.5%)
}
}
Всё, парни, закругляемся!
И, под конец, главный вопрос: «Я могу это всё использовать на реальных проектах?»
Возможно. Я работал с viewport-юнитами достаточное время, чтобы сделать какой-то вывод. Прежде чем пускать это всё в продакшен нужно:
- Сделать SASS-миксин
- Протестировать в разных браузерах на наличие каких-нибудь багов
Будет круто, если вы нашли какие-то ошибки и сообщите о них в комментариях.
Итак, мы поговорили об использовании viewport-единиц для указания размера шрифтов. Viewport-единицы могут быть очень полезны, так как они автоматически пересчитываются при изменении размера окна.
В ходе реализации, я заметил, что лучше всего их использовать только для html. Для всего остального есть MasterCard лучше использовать rem-ы и em-ы.
Поделиться