Здравствуйте, меня зовут Дмитрий Карловский и я… дизайнер. Дизайнер от слова design (проектирование), а не от слова style (дизайн). Я разрабатываю высокоуровневый фреймворк $mol. Одна из основных концепций которого — Лего. То есть это набор очень маленьких кирпичиков с простым и универсальным интерфейсом коммуникации. Комбинируя эти кирпичики в разных комбинациях можно строить приложения любой сложности.
Но, чтобы приложение не выглядело как лоскутное одеяло, а было лаконичным и опрятным, необходимо, чтобы выполнены эти кирпичики были в едином стиле, а располагать их можно было в любой комбинации, не теряя опрятности.
Поэтому, мы разработали математически выверенный концепт дизайна, суть которого можно уловить из следующей шпаргалки:
Далее я расскажу, почему всё именно так, и никак иначе...
Требования
Сперва сформулируем что мы хотим получить.
- Опрятность. Блоки аккуратно выравниваются по воображаемым направляющим, а не скачут как попало.
- Доступность. Интерактивные элементы должны быть достаточно большими, чтобы их удобно было нажимать пальцем.
- Компактность. На маленьких экранах мало места, так что чем больше контента влезет, тем лучше.
- Коммутативность. Возможность любые блоки располагать в любом порядке следования как по вертикали и горизонтали, так и по глубине вложенности.
- Круглые размеры. С ними банально проще работать и сложнее ошибиться.
Особенности людей
Теперь заметим особенности восприятия и управления человеком, которые не зависят от наших желаний.
- Правило логарифма. Человек хорошо различает расстояния, если они отличаются минимум в 2 раза.
- Правило близости. Объекты воспринимаются как группа, если расстояние между ними меньше, чем расстояние от них до любых других объектов.
- Правило сглаживания. Воспринимаемые габариты объекта игнорируют его мелкие выступающие детали, как если бы человек смотрел расфокусированным взглядом.
- Правило потока. Предложение (и тем более слова) человеку проще и быстрее воспринимать, когда оно написано в одну строку, а не разорвано на несколько.
- Правило центроида. Человек уверенно попадает пальцем по контролам, если их размер не менее 6 мм, что соответствует 40 css пикселям.
Технические ограничения
- Блуждающие глифы. Визуальный размер текста зависит от реальной гарнитуры шрифта, которую в общем случае мы не контролируем. Поэтому нужно быть готовыми к тому, что визуально текст может быть смещён на несколько пикселей или иметь на несколько пикселей иной размер.
- Привязка к физическим пикселям. Если задавать размеры и смещения, которые не попадают в физические пиксели, то в лучшем случае браузер округлит размер в большую или меньшую сторону (конкретная сторона слабо предсказуема), а в худшем — отрендерит линии размытыми. Поэтому важно все размеры и смещения задавать целым числом физических пикселей и избегать центрирования в блоках с переменной чётностью ширины.
- Несоответствие логических и физических пикселей. Отображение одних на другие зависит от физического экрана, настроек зуммирования операционной системы и пользовательского зума страницы браузера. Общий коэффициент можно узнать через свойство
widow.devicePixelRatio
. По умолчанию он имеет некоторое круглое значение, но пользователь может выставить и не круглое и получить "мыло".
Текст
По умолчанию размер шрифта в браузере равен 1rem
, что соответствует 16px
. У некоторых пользователей и/или на некоторых девайсах исходный размер шрифта может быть увеличен. Если мы будем выводить текст меньшего размера, то скорее всего у пользователя возникнут проблемы с чтением. Если же большего, то влезет этого текста на экран меньшее количество. Поэтому разумно использовать во всём интерфейсе именно размер шрифта по умолчанию — 1rem
, ибо это минимальный комфортный размер.
Заманчиво делать все остальные размеры кратными 1rem
. Тогда у нас был бы опрятный визуальный вертикальный ритм. Однако, это слишком крупная величина. Если задать высоту линии в многострочном тексте в 1rem
, то линии сольются в единое полотно и переносе взгляда при переносе строки будет сложно не промахнуться мимо следующей. Если же задать 2rem
, то между линиями появятся не менее дискомфортные просветы, которые ещё и места занимают существенно больше.
Стоит отметить, что визуально текст по высоте занимает раза в 2 меньше места, чем тот размер, что мы для него задаём. Это происходит потому, что сверху и снизу оставляется пространство для выносных элементов. Обычно сверху это пространство чуть больше.
Чтобы линии были хорошо различимы, визуальное расстояние между ними должно быть примерно вдвое больше видимого размера. Этого можно добиться с высотой линии в 1.5rem
.
Поэтому разумным будет выбор 0.5rem
в качестве базиса для всех остальных размеров. Это по умолчанию 8 пикселей, которые хорошо делятся на 2 и 4, что полезно для случаев, когда нужны меньшие размеры, которые в сумме дают шаг сетки, а значит не нарушают ритм.
Заголовки
Заголовки обычно выводятся увеличенным шрифтом. Но на маленьких экранах увеличенный шрифт повышает вероятность, что заголовок не влезет на строку и перенесётся. Таким образом удобство его чтения снизится, а занимать такой заголовок будет неоправданно много места. Поэтому по возможности стоит выводить заголовок того же размера, что и остальной текст. Выделять его можно полужирностью, цветом, гарнитурой, иконками, бордюром и тому подобными вещами, не сильно влияющими на ширину.
Если хочется всё же увеличить шрифт заголовка, то важно не переборщить. Размер этот можно спокойно увеличивать аж до 1.5rem
не меняя высоты линии. Относительное визуальное расстояние между строками будет уменьшаться, но это не страшно, так как заголовки не должны превышать 1-2 строк.
Если где-то потребуются шрифты большего размера, то добавляем к высоте строки по 0.5rem
, чтобы сохранялся вертикальный ритм.
Стоит отметить, что высоту линии нельзя задавать относительно размера шрифта (Например, line-height: 1.5
), ибо это сломает вертикальный ритм, сделав его не кратным 0.5rem
.
Текстовые блоки
Текст группируется в параграфы. Параграф может состоять из одной или нескольких строк. Кроме текста параграф может содержать ещё и иконки. Более того, параграф может быть вообще без текста — только иконка.
Параграф может быть частью группы параграфов, а может быть самостоятельной сущностью обрамлённой рамкой (например, кнопка или поле ввода).
Чтобы первая и последняя строки не выглядели оторванными от остальных строк и прилипшими ко краям, визуальный отступ строки от края параграфа должен быть не меньше, чем визуальное расстояние между строками. При высоте строки 1.5rem
визуальное расстояние между строками примерно равно 1rem
, а это значит, что сверху и снизу параграфа необходимо добавить по .5rem
отступов.
Блоки
Блоки в зависимости от ситуации могут стыковаться друг с другом по горизонтали, а могут и по вертикали. Они быть первыми в списке/строке, а могут оказаться в середине или последними. Раскладка блоков блоков — штука динамическая. Зависит от следующий факторов:
- Какие блоки хотим показать, а какие убрать.
- Сколько есть доступного пространства в контейнере.
- Сколько пространства требуется внутренностям блоков.
Отслеживать все эти факторы и менять отступы — слишком накладно, поэтому отступы должны быть такими, чтобы блоки адекватно располагались при любой раскладке. Добиться этого не сложно, если делать отступы одинаковыми со всех сторон.
Для обеспечения визуального ритма сумма отступов соседних блоков должна быть кратна 0.5rem
. То есть для отступа с одной стороны у нас есть следующие возможные значения: 0.25rem
, 0.5rem
, 0.75rem
, 1rem
.
Отметим, что высота линии у нас 1.5rem
. А это на 0.5rem
больше габаритов текста. То есть задавая размер линии мы неявно задали отступы примерно по 0.25rem
сверху и снизу. Чтобы это скомпенсировать, для текстового параграфа зададим асимметричные отступы, отличающиеся на 0.25rem
: 0.75rem
по горизонтали и 0.5rem
по вертикали (визуально по вертикали будут те же 0.75rem
).
Отступы всех остальных блоков мы уже можем задавать полностью идентичными. Тогда они будут на одинаковом расстоянии как от горизонтальных границ так и вертикальных. Однако, важно иметь ввиду, что если два блока стоят рядом, что их отступы складываются, то есть удваиваются в нашем случае. А отступ от края всегда одинарный. Выглядит это как прилипание ко краям. Чтобы выровнять отступы, для контейнера задаётся такой же внутренний отступ как и для каждого вложенного в него элемента.
Например, если у элементов отступ по 0.75rem
, то и у контейнера должен быть такой же. Тогда все отступы (что между элементами, что между контейнером и элементами) будут по 1.5rem
.
Иконки
Иконки меньше 1em
сложно разобрать. Размером же 1.5rem
они будут смотреться слишком большими относительно текста. Поэтому дефолтные 16 пикселей — отличный выбор. Важно отметить, что иконки — не текст, и высота линии на них не распространяется. Чтобы они правильно выравнивались относительно текста так же распирали параграф, как и текст, необходимо добавить им сверху и снизу те же 0.25rem
отступа, что тексту даёт высота линии.
Таким образом иконки у нас могут свободно использоваться там же, где и обычный текст. Они могут идти даже вместо текста, если места не очень много. Не забывайте, однако, добавлять всплывающие подсказки для контролов в которые вы вкладываете иконки, чтобы пользователь всегда мог понять что он делает.
Резюме
Обычно дизайнеры всем этим не занимаются, а рисуют картинки по наитию. Опытного дизайнера обычно отличает интуитивное восприятие описанных тут закономерностей. Мы же немного формализовали всё это дело. Это позволило нам не просто иметь опрятный внешний вид вручную нарисованного интерфейса, но и опрятный внешний вид интерфейса, собранного из блоков в произвольных комбинациях. Ну а дизайнеру больше не надо рисовать бесконечные мёртвые дизайн-макеты для всех форм-факторов — их можно собирать из реальных компонент не беспокоясь, что где-то что-то встанет криво. В $mol мы постепенно движемся в этом направлении. Догоняйте!