#статья дня в кратком переводе от подписчика
Ахмад шадид заметил что Facebook меняет border-radius своих карточек не настройкой media query как мы привыкли это делать, а с помощью логических выражений.
Погнали!
Проблема:
Допустим у нас есть компонент карточки с border-radius: 8px. Когда у карточки нет отступов а также она занимает всю ширину вьюпорта, нам надо изменить значение на border-radius: 0px.
Мы могли бы использовать CSS media query, чтобы просто сбрасывать значение, например так:
@media (min-width: 700px) {
.card {
border-radius: 8px;
}
}
А что если в некоторых случаях нам снова нужен border-radius, например когда размер вью порта будет меньше 450px, нам придётся писать кучи медиа выражений:
@media (max-width: 450px) {
.card--rounded {
border-radius: 8px;
}
}
Решение:
Пример использованный инженерами Facebook, имитирует следующую логику:
if (ширинаКарточки >= ШиринеВьюПорта) {
radius = 0;
} else {
radius = 8px;
}
Чтобы реализовать эту логику в CSS, нам нужно сравнить два значения с помощью функций CSS.
.card {
border-radius: max(0px, min(8px, calc((100vw - 4px - 100%)
* 9999)));
}
Пройдемся по деталям реализации примера выше.
1. Функция max(), которая сравнивает 0px и вычисленное значение функции min(). Функция Max() выбирает наибольшее значение.
2. Функция min() сравнивает 8px и вычисленное значение из calc((100vw - 4px - 100%) * 9999). Это приведет к очень большому положительному или отрицательному числу.
3. 9999 - это просто большое число, чтобы мы могли точно установить одно из двух значений, значение 0px или 8px.
Число 9999 используется не потому что у него есть супер сила, а лишь для того, чтобы избежать крайнего случая (ниже)
Предположим, что ширина вью порта составляет 375px, а размер контейнера - 365px. Если подставить эти значения в уравнение, оно будет выглядеть так:
.card {
border-radius: max(0px, min(8px, calc(375px - 4px - 365px)));
/* Превратится в */
border-radius: max(0px, min(8px, 6px));
}
Из вышеизложенного, браузер выберет значение 6px. Мы этого не хотим. Вместо этого радиус должен быть либо 0px, либо 8px. По этому мы умножаем результат на большое число, которое с меньшей вероятностью будет использоваться в CSS, например 9999.
.card {
border-radius: max(0px, min(8px, calc((375px - 4px - 365px) * 9999)));
/* Превратится в */
border-radius: max(0px, min(8px, 59994px));
}
Исходя из этого, браузер выберет 8px из функции min(), а затем такое же значение из функции max().
Возьмем пример, основанный на первом сценарии. У нас есть область просмотра шириной 1440px, а карточка находится в контейнере 700px.
.card {
border-radius: max(0px, min(8px, calc((100vw - 4px - 100%) * 9999)));
/* В нашем случае это: */
border-radius: max(0px, min(8px, calc((1440px - 4px - 700px) * 9999)));
}
Умножение полученного значения на 9999 даст 7359264. В этом случае CSS будет выглядеть для браузера следующим образом:
.card {
border-radius: max(0px, min(8px, 7359264px));
}
Обе функции min() и max() в примере выше выберут значение в 8px.
.card {
border-radius: 8px;
}
Это первый пример использования этого сценария.
А что будет, когда карточка займёт всю ширину вьюпорта?
.card {
border-radius: max(0px, min(8px, calc((100vw - 4px - 100%) * 9999)));
/* А в нашем случае это: */
border-radius: max(0px, min(8px, calc((375px - 4px - 375px) * 9999)));
}
Умножение значения на 9999 даст -39996 пикселей, что является отрицательным. Для браузера это будет выглядеть так:
.card {
border-radius: max(0px, min(8px, -39996px));
}
А теперь самое интересное! Браузеру нужно задать два вопроса:
Какое значение меньше? 8px или -39996px? Результат -39996 пикселей.
Какое значение больше? 0px или -39996px? Результат - 0 пикселей.
Круто? До сих пор удивляюсь столь умному использованию функций сравнения CSS.
Полная
статья, а также
codepen прилагаются.
#borderradius #css #viewport