Тип Поста

Точность вычисления процентных значений в CSS и Sass

Точность вычисления процентных значений в CSS и Sass

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

Поговорим об этих вещах, а также о возможных способах решения возникающих проблем.

Подготовка

Прежде чем начать разбор особенностей вычислений в CSS и Sass, возьмем небольшой кусочек кода, который отлично подойдет для наших целей:

.list-item {
  float: left;
  width: 33%;
}

Что не так с этим кодом?

Скорей всего, у вас возникнет резонный вопрос: -“А что же не так с этим кодом?”. На первый взгляд, там всего ничего – только три строчки кода, которые отвечают за построение трех-колоночной сетки. Довольно-таки просто, скажите вы.

Тем не менее, если произвести простое сложение ширины каждой из трех колонок, получается следующее: 33% + 33% + 33% равно 99%, но не 100%. В большинстве случаев, потеря точности в 1% не будет заметна, но при расположении подряд нескольких блоков – один процент точности имеет большое значение.

Например, 1% от 1400px – это уже будет погрешность в 14px, что является совершенно недопустимой величиной.

В таком случае, почему бы на просто не увеличить точность, задав значение ширины, например, с точностью до сотой части? Мы могли бы уменьшить погрешность до 1.4px, или даже до 0.14px, что будет вполне подходящим вариантом, как можно было бы предположить:

.list-item {
  float: left;
  width: 33.33%;
}

Этот код уже будет работать гораздо лучше, но все равно недостаточно хорошо.

Проблема заключается в том, что при ширине в 33.33% от 1400px, браузер переведет это в 466.62px. Так как блоков у нас три штуки, каждый блок в теории должен занять эту ширину. Но у каждого браузера свои алгоритмы расположения блоков при дробных значениях ширины. Например, полученная нами дробная ширина в 466.62px, каким-то браузером может округлиться до 467px. Проделав нехитрые вычисления: 467px * на три блока, получим общую ширину блоков в 1401px, что не поместится в наш контейнер размером в 1400px.

Браузеры не могут справиться с этой проблемой?

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

Здесь уместно будет привести цитату из хорошей статьи на эту тему:

[…] в шести-колоночной сетке, каждая колонка будет равна 100% ÷ 6 = 16.666667% ширины. На примере контейнера шириной в 1000px (ширина выбрана для удобства вычислений), процентная ширина каждой колонки преобразуется в 166.66667 пикселей. Так как в спецификации нет руководства для действия в подобных случаях, разработчики браузеров придумывают свои правила. Если браузер будет округлять дробное значение к ближайшему пикселю, в нашем примере, мы получим 167 пикслей. Но это получается 167 x 6 = 1002 пикселей, и мы больше не имеем свободного пространства в контейнере для всех шести колонок. В другом случае, при окрулении браузером в меньшую сторону к 166 пикселям, мы получим лишние четыре пикселя, что не будет соответствовать размеру нашего контейнера для полного заполнения имеющегося пространства.

Это именно то, что случится. Старые версии Internet Explorer (в основном 6 и 7) округляют значение к ближайшему целому числу, что будет причиной поломки всей верстки.

Браузеры на движке Webkit округляют значение в меньшую сторону, что предотвращает катастрофические последствия для верстки, но оставляет дополнительное неиспользуемое пространство.

Opera (по крайней мере в старых версиях движка) производить какие-то совершенно странные манипуляции, которые даже попытаться объяснить не представляется возможным.

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

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

Что на счет Sass?

Как известно, Sass поддерживает математические операции. Это одна из множества возможностей Sass, из-за которой стоит использовать этот CSS-препроцессор, например, для построения grid-систем. Все, что мы должны сделать, так это сказать Sass, что мы хотели бы разделить ширину нашего контейнера на три равные части:

.list-item {
  float: left;
  width: (100% / 3);
}

Также, мы могли бы использовать для этих целей percentage() функцию:

.list-item {
  float: left;
  width: percentage(1 / 3);
}

Sass, в обоих случаях реализации на Ruby или LibSass, имеет значение точности вычислений равное пяти знакам после запятой. Это является некоторой проблемой, из-за малого значения точности и сложности с её переопределением – точность в десять знаков была бы в самый раз.

Следующий код является результатом работы Sass:

.list-item {
  float: left;
  width: 33.33333%;
}

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

Лучшее из Sass и CSS

Только что мы узнали, что хорошей идеей будет позволить Sass производить за нас все вычисления, чем жестко указывать какие-либо значения. Теперь, комбинируя полученные знания, самым лучшим вариантом решения возникших проблем – это дать возможность браузеру решить созданную им же проблему. Для этого используем CSS-функцию calc():

.list-item {
  float: left;
  width: calc(100% / 3);
}

Этот кусочек кода не будет претерпевать каких-то ни было изменений, – он будет работать так, как должен по спецификации CSS. Точно не известно, обрабатывает ли браузер значения функции calc() по тем же алгоритмам, что и без неё. Предположительно, некоторые браузеры добавляют дополнительные пиксели при рендере для выравнивания ширины блоков.

Для тех браузеров, которые не поддерживают функцию calc() – это в основном Internet Explorer 8 и Opera Mini, мы можем поместить выражение Sass, результатом работы которого будет статическое значение ширины, прямо рядом с calc(). Такой вариант является наиболее подходящим для нашего случая, и содержит в себе лучшее из CSS и Sass:

.list-item {
  float: left;
  width: (100% / 3);
  width: calc(100% / 3);
}

Заключение

Давайте подведем небольшое резюме из вышесказанного.

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

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

Ну а самым лучшим вариантом будет использование возможностей браузера для вычисления значений с помощью CSS-функции calc().

На этом все. Надеюсь, это небольшое напоминание об особенностях вычисления значений в CSS и Sass будет полезным.

При создании статьи были использованы следующие источники:

  1. A Tale of CSS and Sass Precision
  2. Responsive Design’s Dirty Little Secret
  3. Sass Documentation
  4. CSS Documentation: function calc()
Поделиться

Оставить комментарий

Вы можете использовать следующие HTML-теги:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
Обязательно к заполнению