Магические числа в CSS

Несмотря на довольно весёлое название, магические числа — это плохо. Термин берёт свое начало в программировании и означает «безымянную числовую константу». Другими словами, это помещенное в код число, которое сильно влияет на то, будет ли код работать корректно, но его конкретное предназначение непонятно тем, кто не слишком тщательно разобрался в коде. В CSS очень часто встречаются безымянные числовые константы, но они обычно окружены контекстом в виде селекторов и свойств, потому не являются слишком загадочными. И все же, в CSS присутствуют магические числа, и ничего хорошего в этом нет.

В CSS магическими можно назвать числа, которые «работают» в определённых обстоятельствах, но очень хрупки и склонны к сбоям, когда эти обстоятельства изменяются. В большинстве случаев они имеют какое-то отношение к шрифтам. Их обычно используют люди, которые ограничиваются тестированием в одном браузере с идеальными настройками. Давайте рассмотрим несколько примеров, чтобы разобраться, что такое магические числа, и избегать их в будущем.

Взгляните на этот простой набор вкладок:

Вкладки1

Для каждой из вкладок установлена ширина width: 100px;. В этом примере 100px и есть то самое «магическое число». При его использовании многое может пойти не так, как нужно. В этом можно убедиться, добавив вкладку с текстом подлиннее:

Вкладки2

Выглядит немного странно и вряд ли так, как хотелось бы. Переноса строки можно избежать, применив white-space: nowrap;, но так, наверное, еще хуже:

Вкладки3

Вероятность некрасивого отображения вкладок можно уменьшить, используя min-width:

Вкладки4

Или же можно вообще не указывать ширину:

Вкладки5

Если же вы во что бы то ни стало хотите, чтобы все вкладки были одной ширины, можете попробовать использовать overflow: hidden; и text-overflow: ellipsis;:

Вкладки6

В таком случае, наверное, стоит добавить атрибут title, чтобы можно было каким-то образом отобразить полное название вкладки. Вам может прийти в голову, что это можно решить путем ограничения длины названий вкладок в системе управления контентом. Но как насчет пользователей, которые самостоятельно увеличивают размер шрифта для своего удобства? Такое решение с ограничением длины названия вкладок может причинить им неудобства.

В недавней публикации «Заголовки с линиями по бокам» я использовал для свойства line-height значение, которое можно считать магическим числом. Скажем, вы использовали этот прием в сочетании с причудливым шрифтом, подключенным через @font-face. Теперь представьте, что подключенный шрифт не загрузился, или же пользователь поменял его на какой-то другой, или страницу просматривают в браузере, который не поддерживает @font-face. Загружается запасной шрифт, размеры которого могут кардинально отличаться от размеров вашего подключенного шрифта. Линии вокруг текста с запасным шрифтом размещаются странным образом и не центрируются, как было задумано. Магическое число не работает.

Шрифты

Этот конкретный пример немного надуман, но, могу поспорить, вы встречали подключенные шрифты с немыслимой высотой строчного знака или другими особенностями, коренным образом отличающими их от стандартных решений.

Скажем, у вас есть группа блоков с различным количеством содержимого. Вам нужно расположить их в виде сетки, и вы используете для этого float:left;. Получается довольно безобразно:

Блоки1

Постойте, ведь если задать для них одинаковую высоту, проблема будет решена!

Блоки2

Это если пользователь будет просматривать сайт с точно такими же настройками размеров шрифта, что и у вас. Но пользователи могут их менять.

Chrome

В этом месте мне хочется заплакать:

Блоки3

Используя min-height, можно избежать странностей с перекрытием, но тогда размеры блоков будут разными, и снова возникает проблема с float. Я не буду слишком углубляться в решение этой проблемы, потому что она и без того стала слишком абстрактной, но наверняка можно использовать прокрутку внутри блоков, подкорректировать размеры блоков с помощью JavaScript или же использовать какой-то другой макет.

Гарри Робертс (Harry Roberts) привел классический пример магического числа в своей статье «Код CSS „с душком“».

.site-nav > li:hover .dropdown{
  position: absolute;
  top: 37px;
  left: 0;
}

Это CSS выпадающего меню. Меню спрятано за пределами экрана до тех пор, пока пользователь не наведет курсор на элемент в родительском списке, тогда выпадающее меню появляется в зоне видимости. Оно должно располагаться под родительским элементом. В браузере автора этого кода высота родительского элемента составляла 37px. Уверен, вы уже успели предположить что это не во всех случаях будет так. 37px является магическим числом. Гарри советует заменить его на top: 100%, сбои при котором намного менее вероятны.

В статье «Боремся с пробелами между элементами со свойством Inline-Block», автор утверждает, что задав значение -4px для границ, можно избавиться от лишнего пространства между блоками. Это без сомнения магическое число. По стечению обстоятельств, 4px — это всего лишь ширина пробела для довольно большого количества гарнитур при кегле 16px, который обычно указан по умолчанию.

Измените font-family на что-то вроде Monaco. Сбой. Увеличьте или уменьшите кегль. Сбой.

Сбой

В этой статье указаны и другие возможные решения.

Путаница в определении

Так как я пытаюсь аргументировать отказ от использования магических чисел, нужно четко определить, что же они из себя представляют, когда речь идет о CSS. Я стал свидетелем множества обсуждений, в которых мнения на этот счёт расходятся. (1) (2) (3).

Вот несколько примеров:

CSS

-webkit-transform: translateZ(0);

Магическое число? Нет. Просто маленький хак, который мы когда-то использовали чтобы улучшить производительность.

CSS

.parent {
  padding: 22px;
}
.child {
  bottom: 22px;
  left: 22px;
}

Магическое число? Нет. Это число странное, но не магическое. Дочерний элемент позиционируется по нижнему левому краю родительского элемента без отступов. Поскольку числа одинаковы, происходящее вполне логично. Если бы все они были разными, это бы значило что здесь не обошлось без хитромудрой привязки к font-size, и тогда речь бы шла о магических числах.

CSS

top: 37px;

Допустим, что это магическое число, так же, как и в примере с выпадающим меню выше. Можно ли с этим разобраться с помощью Sass?

SCSS

$topDistance: 37px;

.dropdown {
  top: $topDistance;
}

Это больше не «безымянная» числовая константа, так как мы дали ей название, верно? Тем не менее, это все еще магическое число в CSS. Оно осталось столь же хрупким, как и было.

CSS

letter-spacing: -.05em;

Магическое число? Нет. Оно наверное было бы таким если бы использовались пиксели, так как значение в пикселях остается неизменным, и эффект от его использования зависит от текущего значения font-size. При большом font-size изменения практически незаметны, при маленьком font-size, изменения существенны. Использование относительных единиц уменьшает вероятность сбоев.

В качестве заключения

Знали бы вы, как я не люблю эту часть публикаций, однако полезно выделить своего рода свалку для мелочей, которым не нашлось места где-нибудь еще.