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

alexei06/04/2023 - 08:50
Магические числа в CSS

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

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


Посмотрите на этот простой набор вкладок:

Набор вкладок №1
Набор вкладок №1

Здесь для каждой из вкладок установлено значение width: 100px;. В этом примере 100 пикселей - это наше "магическое число". Есть множество вещей, которые могут пойти не так с этим определением.

Например, если добавить еще одну вкладку с более длинным текстом:

Набор вкладок №2
Набор вкладок №2

Получим немного некрасивый и, вероятно, нежелательный результат.

Мы могли бы предотвратить перенос с помощью white-space: nowrap;, но это, возможно, даже еще хуже:

Набор вкладок №3
Набор вкладок №3

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

Набор вкладок №4
Набор вкладок №4

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

Набор вкладок №5
Набор вкладок №5

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

Набор вкладок №6
Набор вкладок №6

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


Возьмем для примеру задачу, в которой необходимо у заголовков статей по боками отображать полоски. Если для вертикального выравнивания использовать свойство line-height, то его значение станет магическим числом. Предположим, что вы будете для заголовка использовать некий необычный шрифт в @font-face. Допустим, что шрифт не загружается, или пользователь переопределяет его, или страница просматривается в браузере, который не поддерживает правило @font-face. Тогда загрузится резервный шрифт, размер которого может кардинально отличаться от пользовательского шрифта. Линии на внешней стороне резервного шрифта теперь расположены не так как задумывалось, т.е. не по центру. Магическое число дало сбой.

Магическое число и пользовательский шрифт
Магическое число и пользовательский шрифт

Данный конкретный пример несколько надуман, но вы, наверняка, встречали пользовательские шрифты с совершенно сумасшедшими параметрами.


Теперь допустим, у вас есть куча блоков с разным количеством содержимого в них. Вы хотите упорядочить их в виде сетки, для этого вы создаете обтекание слева. И получаете какую-то мешанину:

Мешанина из блоков
Мешанина из блоков

Но, постойте! Если бы они все были одинаковой высоты, то и проблемы бы не было!

Выровненная сетка из блоков
Выровненная сетка из блоков

Но есть один нюанс. Все это было бы так, если бы пользователь просматривал сайт с теми же настройками размера шрифта, что и у вас. А ведь он может их и изменить:

Настройки размера шрифта в браузере Chrome
Настройки размера шрифта в браузере Chrome

И получаем грустную гримасу судьбы:

Мешанина текста в выровненных блоках
Мешанина текста в выровненных блоках

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


Гарри Робертс в одной из своих статей приводит классический пример магического числа в CSS:


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

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

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

Поскольку мы пытаемся сказать "не используйте это", важно правильно понять сам термин в отношении к CSS.

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


transform: translateZ(0);

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



.parent {
  padding: 22px;
}

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

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



top: 37px;

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


$topDistance: 37px;

.dropdown {
  top: $topDistance;
}

Это больше не "неименованная" числовая константа, верно? Ведь мы поименовали ее. Но в CSS это все еще магическое число. И все там так же хрупко, как и раньше.



letter-spacing: -.05em;

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

И в заключении

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

  • Стандарты кодирования CSS в самой популярной системе управления контентом WordPress говорят, что вы не должны использовать значения, похожие на магические числа. Если там нельзя, то зачем использовать в других местах?
  • Если вы используете шрифтовые иконки, помните, что они все же являются шрифтами, поэтому они умеют изменять размер. Вы не можете "зарезервировать место" для них где-нибудь в пиксельных значениях, так как размер шрифта может измениться, но значение в пикселях никогда не изменится.
  • Допустим, вы хотите центрировать изображение и текст. Свойство vertical-align работает довольно хорошо, но можно заметить, что оно часто отклоняется на 1 пиксель или около того, поэтому добавление к нему postion: relative; top: 1px; совсем не помешает. Будет ли это магическим числом? Мы в этом не уверены.