Использование булевой логики для условного применения правил CSS, без JS
Благодарности
Прежде чем мы начнем, я должен поблагодарить Леа Вероу за ее доклад о секретах переменных CSS на CSS Day 2022, который вдохновил на создание этого поста, и за слайд-деск, который она любезно предоставила.
В своем докладе Леа осветила некоторые малоизвестные возможности пользовательских свойств CSS и рассказала о некоторых будущих усовершенствованиях. На слайде 58 Лиа упомянула о том, как можно выполнять логические операции для условного применения стиля с помощью простой арифметики. В этой заметке я планирую изучить эту концепцию немного глубже.
Введение
Существует три основных логических операции: NOT, AND и OR, все из которых работают с булевыми значениями TRUE или FALSE. Однако, за исключением псевдокласса checked, CSS не очень хорошо поддерживает булевы операции. Чтобы преодолеть это ограничение, мы будем использовать двоичные значения (1/0) вместо булевых значений (TRUE/FALSE) соответственно.
Мы изучим механику моделирования логических операций с помощью пользовательских свойств и продемонстрируем, как значения 1 и 0 помогут нам применить стилизацию. Перед этим мы кратко подтвердим наше понимание фактических логических операций, которые можно найти в большинстве языков программирования, таких как JavaScript.
Операция NOT («!» в JavaScript)
Операция NOT принимает одно входное значение и инвертирует его. True становится False, False становится True, или, в нашем случае, входное значение 1 приводит к выходу 0, а 0 in становится 1 out.
Операция AND («&&» в JavaScript)
Операции AND и OR принимают два (или более) входных сигнала и выдают один выходной. Операция AND выдает значение True только в том случае, если все входы True, в противном случае на выходе получается False. В наших «функциях» используются только два входа, только когда вход-A и вход-B равны 1, на выходе будет 1.
Операция ИЛИ («||» в JavaScript)
Операция ИЛИ дает на выходе TRUE, если любой вход TRUE, и FALSE, если все входы FALSE. Следующая таблица истинности иллюстрирует простое поведение.
Логические операции CSS
Для поддержки наших операций нам понадобятся некоторые дополнительные значения, определенные в контексте классов CSS следующим образом.
Булевы (двоичные) значения
Определите булевы значения True и False как 1 и 0.
.not-operation, .and-operation, .or-operation {
--TRUE: 1;
--FALSE: 0;
}
Входные значения по умолчанию
Подготовьте входные значения для операций.
.not-operation, .and-operation, .or-operation {
--INPUT: var(--TRUE);
--INPUT-A: var(--FALSE);
--INPUT-B: var(--TRUE);
}
Логические операции
Используя следующие три основные операции, можно получить множество других операций, таких как NAND (НЕ И), NOR (НЕ ИЛИ), XOR и т.д.
НЕ
Используя числовые значения вместо булевых, операцию NOT можно получить путем вычитания входного значения (I) из 1. Когда I = 1, 1 — 1 = 0, когда I = 0, 1 — 0 = 1.
.not-operation {
--OUTPUT: calc(1 - var(--INPUT));
}
И
Снова используя 1 и 0, операция AND достигается путем умножения двух входов (I1 и I2).
Умножение значения на ноль дает ноль, поэтому только когда все (оба) входа равны единице, на выходе получается единица.
.and-operation, {
--OUTPUT: calc(var(--INPUT-A) * var(--INPUT-B));
}
ИЛИ
Наконец, у нас есть операция ИЛИ, которая является аддитивной с зажимом. Сложение двух входов (I1 & I2) приведет к результату:
Нам нужно зажать выход 1 + 1 от 2 до 1, что можно сделать двумя способами. Мы могли бы вычесть результат выполнения операции ADD на тех же входах, но CSS может помочь в этом с помощью функции ‘min’ следующим образом.
.or-operation {
--OUTPUT: min(var(--INPUT-A) + var(--INPUT-B), 1);
}
Демонстрация
Для демонстрации описанных выше операций мы выведем результат с помощью CSS свойства content псевдоэлемента ::after элемента DIV с классом ‘result’.
.result::after {
counter-reset: logic-result var(--OUTPUT);
content: counter(logic-result);
}
Операция [OPERATION], которую мы хотим выполнить, будет задана с помощью класса CSS. Входные значения будут задаваться путем присвоения соответствующего пользовательского свойства (-ise) через атрибут style.
Каждый тестовый пример будет иметь следующую форму.
<div class="result [OPERATION]" style="--INPUT: [BOOLEAN_VALUE]"></div>
<!-- or -->
<div class="result [OPERATION]"
style="--INPUT-A: [BOOLEAN_VALUE_A] --INPUT-B: [BOOLEAN_VALUE_B]"></div>
Вот тестовые примеры
<div class="result not-operation" style="--INPUT: var(--FALSE)"></div>
<div class="result not-operation" style="--INPUT: var(--TRUE)"></div>
<div class="result and-operation"
style="--INPUT-A: var(--FALSE); --INPUT-B: var(--FALSE)"></div>
<div class="result and-operation"
style="--INPUT-A: var(--FALSE); --INPUT-B: var(--TRUE)"></div>
<div class="result and-operation"
style="--INPUT-A: var(--TRUE); --INPUT-B: var(--FALSE)"></div>
<div class="result and-operation"
style="--INPUT-A: var(--TRUE); --INPUT-B: var(--TRUE)"></div>
<div class="result or-operation"
style="--INPUT-A: var(--FALSE); --INPUT-B: var(--FALSE)"></div>
<div class="result or-operation"
style="--INPUT-A: var(--FALSE); --INPUT-B: var(--TRUE)"></div>
<div class="result or-operation"
style="--INPUT-B: var(--FALSE); --INPUT-A: var(--TRUE)"></div>
<div class="result or-operation"
style="--INPUT-B: var(--TRUE); --INPUT-A: var(--TRUE)"></div>
Исходный код можно посмотреть в моем CodePen.