Условный border-radius в CSS
И поделился следующим твитом об этом открытии. Затем, я получил такой ответ от Мириам Сюзанн:
Через несколько часов, Фрэнк Ян из Facebook подтвердил, что это условный оператор, чтобы изменить 8px на 0px, когда карточка занимает всю ширину окна просмотра. Разве это не потрясающе?
Сначала я подумал, что это какая-то ошибка. К счастью, нет. В этой статье я постараюсь осветить проблему и объяснить, как работает ее решение.
Проблема
Содержание статьи:
У нас есть карточный компонент с border-radius равным 8px. Когда карточка не имеет поля или занимает всю ширину области просмотра, мы хотим изменить ее border-radius на 0.
Практический курс по верстке адаптивного сайта с нуля!
Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3
Это можно сделать, удалив border-radius с помощью медиа-запроса CSS, подобного такому:
CSS @media (min-width: 700px) { .card { border-radius: 8px; } }
12345 | @media (min-width: 700px) { .card { border-radius: 8px; }} |
В некоторых случаях это ограничение. Если по какой-то причине мы хотим активировать border-radius, когда размер области просмотра меньше 450px, нам нужно будет создать вариативный класс CSS и снова использовать медиа-запрос.
CSS @media (max-width: 450px) { .card—rounded { border-radius: 8px; } }
12345 | @media (max-width: 450px) { .card—rounded { border-radius: 8px; }} |
Решение
Это умный пример, сделанный командой Facebook. Он имитирует следующую логику:
JavaScript if (cardWidth >= viewportWidth) { radius = 0; } else { radius = 8px; }
12345 | if (cardWidth >= viewportWidth) { radius = 0;} else { radius = 8px;} |
Чтобы реализовать эту логику в CSS, нам нужно сравнить два значения с помощью функции сравнения CSS. Решение вдохновлено статьей Хейдона Пикеринга «Священный альбатрос Flexbox». Наман Гоэл из Facebook адаптировал его для работы с border-radius.
CSS .card { border-radius: max(0px, min(8px, calc((100vw — 4px — 100%) * 9999))); }
1234 | .card { border-radius: max(0px, min(8px, calc((100vw — 4px — 100%) * 9999)));} |
Давайте подробно рассмотрим приведенный выше CSS.
У нас есть функция max(), которая сравнивает 0px с вычисленным значением min(). Она выберет большее значение.
Функция min() сравнивает между 8px и вычисленным значением из calc((100vw — 4px — 100%) * 9999). Результатом будет очень большое положительное или отрицательное число.
Большое число 9999, заставляет значение быть либо 0px либо 8px.
Давайте объясним волшебство calc()! Волшебство происходит в значении 100%. Оно может отличаться в зависимости от двух разных сценариев:
Оно может быть равно 100% содержащему его элементу (родительский элемент / оболочка .. или как он там называется в вашем CSS).
Или оно может быть равно 100vw, если карта занимает всю ширину области просмотра (например, в мобильном телефоне).
Зачем Использовать 9999?
Это не потому, что это точное число имеет суперсилу или что-то в этом роде. Речь идет о том, чтобы избежать крайнего случая. Предположим, что ширина области просмотра равна 375px, а контейнера — 365px. Если подставить эти значения в уравнение, оно будет выглядеть так.
CSS .card { border-radius: max(0px, min(8px, calc(375px — 4px — 365px))); /* will result to */ border-radius: max(0px, min(8px, 6px)); }
12345 | .card { border-radius: max(0px, min(8px, calc(375px — 4px — 365px))); /* will result to */ border-radius: max(0px, min(8px, 6px));} |
Практический курс по верстке адаптивного сайта с нуля!
Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3
На основании вышеизложенного, браузером будет выбрано значение 6px. Мы этого не хотим. Вместо этого радиус должен быть либо 0px либо 8px. Для этого мы можем умножить результат на большое число, например 9999.
CSS .card { border-radius: max(0px, min(8px, calc((375px — 4px — 365px) * 9999))); /* will result to */ border-radius: max(0px, min(8px, 59994px)); }
123456 | .card { border-radius: max(0px, min(8px, calc((375px — 4px — 365px) * 9999))); /* will result to */ border-radius: max(0px, min(8px, 59994px));} |
Исходя из этого, браузер выберет значение 8px из функции min, а затем то же значение из функции max(). Возьмем пример, основанный на первом сценарии. У нас есть окно просмотра шириной 1440px, а компонент карты находится внутри контейнера 700px.
Умножение полученного значения на 9999 приведет 7359264 что является большим случайным числом. В этом случае CSS для браузера будет выглядеть следующим образом:
CSS .card { border-radius: max(0px, min(8px, 7359264px)); }
123 | .card { border-radius: max(0px, min(8px, 7359264px));} |
Поскольку у нас есть min(), будет выбрано наименьшее из имеющихся значений -8px. При сравнении с max(), тоже будет выбрано 8px. Это первый вариант использования такого CSS.
CSS .card { border-radius: 8px; }
123 | .card { border-radius: 8px;} |
Второй, когда карта занимает всю ширину области просмотра. Это можно увидеть в мобильном окне просмотра. Обратите внимание, что ширина контейнера и области просмотра одинакова.
Умножение значения на 9999 приведет к отрицательному значению -39996px. Браузер прочитает это так:
CSS .card { border-radius: max(0px, min(8px, -39996px)); }
123 | .card { border-radius: max(0px, min(8px, -39996px));} |
А теперь самое интересное! Браузеру нужно задать два вопроса:
Какое значение меньше? 8px или -39996px? Результат -39996px.
Какое значение больше? 0px или -39996px? Результат 0px.
CSS .card { border-radius: 0px; }
123 | .card { border-radius: 0px;} |
Вы видели, как это произошло? Меня все еще удивляет такое умное использование функций сравнения CSS. Мы также можем вывести это на новый уровень, используя CSS clamp(). Я думаю, что команда Facebook не использовала его, поскольку он не поддерживается в более старых версиях Safari (например, v12).
CSS .card { border-radius: clamp(0px, ((100vw — 4px) — 100%) * 9999, 8px); }
123 | .card { border-radius: clamp(0px, ((100vw — 4px) — 100%) * 9999, 8px);} |
Проверьте это на Codepen. Надеюсь, вам понравилась статья. Спасибо за чтение!
Автор: Ahmad Shadeed
Источник: webformyself.com