Будни разработчика
14.6K subscribers
1.18K photos
337 videos
7 files
2.02K links
Блог Lead JS-разработчика из Хельсинки
Автор: @bekharsky

По рекламе: https://telega.in/channels/htmlshit/card?r=GLOiHluU или https://yangx.top/it_adv

Чат: https://yangx.top/htmlshitchat

№5001017849, https://www.gosuslugi.ru/snet/679b74f8dad2d930d2eaa978
加入频道
#статья дня в кратком переводе от подписчика

Ахмад шадид заметил что 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
#заметка дня

Итак, что же меня восхищает в волшебном значении border-radius равному 9999px?

Всё очень просто и забавно одновременно: border-radius: 9999px построит вам прямоугольник со скруглёнными углами. В случае квадрата это будет, очевидно, круг.

Вот issue из обсуждений спецификации CSS WG: https://www.w3.org/Style/CSS/Tracker/issues/29

Сам автор issue говорит, что без пол-литра картинок там не разобраться. Cut the crap, они пошли по третьему варианту: https://www.w3.org/TR/css-backgrounds-3/#corner-overlap

Там в целом геометрия эллипсов, потому описание формулы такое странное и учитываются все углы, но давайте просто посчитаем, что же получится для значения в 10000px (проще считать) и прямоугольника размером 320x240px, углы начинаем с верхнего левого (Top Left):

TL: 320/20000 vs 240/20000
TR: 320/20000 vs 240/20000
BR: 320/20000 vs 240/20000
BL: 320/20000 vs 240/20000

0.016 vs 0.012 в каждом случае

Итого, 0.012 — минимальное значение коэффициента приведения радиуса.

10000 * 0.012 = 120.

Половина высоты, выходит. Проверяем себя: https://codepen.io/alinaki/pen/jOxRwJJ

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

Во Flutter используется геометрия кривых и понять это пусть всё ещё проще, чем структуру исходного кода Chromium, но всё равно сложно. Тем не менее, имеются упоминания, что радиусы приводятся к минимальному значению размерности.

И да, 9999px это совсем не то же, что 50%, опять же — смотрите спецификацию, там эллипсы. Но в случае квадрата — и там и там будет круг.

#geometry #borderradius #css #flutter
👍5🤯3