Помните сказку про мальчика, который кричал «волки»? Примерно так же в 2025 году случилось с «программированием на CSS». Вышла функция if(). Блогеры преждевременно хайпанули: всё, теперь у нас условия в CSS. Разработчики пошли читать спецификации, попробовали — и довольно быстро выяснилось, что внутри условного выражения style() возможностей почти нет. Многие разочаровались и похоронили идею.
В конце 2025 года Chrome выкатил революционный Range Syntax For Style Container Queries. Обновлённый style() научился сравнивать переменные между собой и поддерживать диапазонные выражения. Мы наконец‑то получили мощную условную логику в CSS, но мало кто это заметил.
В этой статье мы попытаемся реанимировать идею программирования на CSS. На примере интерфейсного паттерна — «выделение диапазона дат в календаре» — разберём, как обычная JS‑логика превращается в CSS‑логику (спойлер: очень просто).
Заинтригованы? Поехали.
Задача: выделение диапазона дат

Диапазоны дат встречаются повсюду:
бронирование отеля,
выбор отпуска,
спринты в планировщике,
фильтр по периоду в аналитике.
Типовая формулировка задачи звучит так: подсветить все дни между стартом и концом диапазона. Есть ряд особенностей:
Календарь обычно делают таблицей, а не плоским списком, то есть ячейки дней расположены внутри рядов недель.
При смене месяца выделенный диапазон должен сохраняться.
Диапазон может состоять из одного дня.
Границы диапазона включают даты старта и конца диапазона.
Обычный подход на JS
Типичный подход — пройтись по ячейкам, проверить на попадание в диапазон и поставить нужный класс. Примерно так:
const start = 4; const end = 6; document.querySelectorAll('.day-now').forEach((cell) => { const day = Number(cell.dataset.day); cell.classList.toggle('in-range', day >= start && day <= end); });
Всё работает. Проблема в том, что это исключительно «визуальная» задача. Точно такая же, как создание полосатых таблиц.
Сейчас никому и в голову не придёт делать полосатые таблицы на JS. А чем выделение диапазона дат хуже? Только тем, что у нас нет простого способа реализации на CSS. То есть не было.
Сделаем же это на CSS!
Реализация на CSS
Шаг 1: Разметка
Разметка практически не меняется. Это всё та же таблица, где ячейки — это дни, а ряды — это недели. Каждой ячейке в разметке нужно добавить CSS‑переменную с номером дня. Проще всего сделать это с помощью атрибута style:
<tr> <td class="day day-now" style="--day: 21">21</td> <td class="day day-now" style="--day: 22">22</td> ... </tr>
Да, приходится специально инлайнить стили, но это делается один раз при генерации шаблона.
Шаг 2: Переменные диапазона
Добавляем корневому элементу календаря CSS‑переменные со стартом и концом диапазона. Например, так:
.calendar { --day-start: 4; --day-end: 6; }
Шаг 3: Условная стилизация отдельных ячеек
Теперь самое интересное. Современный CSS позволяет писать условные выражения через if(). Проверка условий происходит внутри специальной конструкции style(), в соответствии с так называемым Range Syntax For Style Container Queries.
Благодаря Range Syntax можем сравнивать CSS‑переменные друг с другом, или CSS‑переменную с каким‑то значением. Причем мы можем использовать привычные операторы сравнения >, < или =.
У каждой ячейки с классом day-now есть CSS‑переменная --day с номером дня. Мы можем сравнить номер дня с начальным днём диапазона, который хранится в --day-start. И в зависимости от результата, задать ячейкам разный фон. Так выглядит сравнение:
.day-now { background-color: if( style(--day-start <= --day): #8b0000; else: rgba(255, 255, 255, 0.05); ); }
Ниже результат. Подкрасились все ячейки, день которых больше либо равен дню начала диапазона (4 число):

Шаг 4: Двойной диапазон
Мы можем использовать и двойной диапазон. То есть подсветить те ячейки, день которых одновременно больше или равен дню старта и меньше или равен дню конца:
.day-now { background-color: if( style(--day-start <= --day <= --day-end): #8b0000; else: rgba(255, 255, 255, 0.05); ); }
Результат:

Вот и всё. Решение полностью готово. С помощью одной строчки CSS. Осталось только протестировать, как всё работает. Давайте поменяем границы диапазона:
.calendar { --day-start: 2; --day-end: 20; }
Всё корректно:

Сравнение без включения границ диапазона
Естественно, можно включать или исключать границы диапазона. Для этого в зависимости от задачи используем <= и >= или < и >.
.calendar { --day-start: 2; --day-end: 20; } .day-now { background-color: if( style(--day-start < --day < --day-end): #8b0000; else: rgba(255, 255, 255, 0.05); ); }
Результат:

Диапазон в один день
Проверим, как работает сравнение, если границы диапазона совпадают:
.calendar { --day-start: 6; --day-end: 6; } .day-now { background-color: if( style(--day-start <= --day <= --day-end): #8b0000; else: rgba(255, 255, 255, 0.05); ); }
Всё корректно:

Смена месяца
Снова устанавливаем диапазон с 4 по 6 число и меняем месяц.
.calendar { --day-start: 4; --day-end: 6; }
Диапазон сохраняется, потому что логика завязана на значения переменных --day, а не на позицию в таблице. Естественно, разметка другого месяца должна быть корректной.

Вот так внезапно CSS‑превратился в язык с полноценной условной логикой, на котором действительно можно «программировать». Реализация сравнений оказалась на удивление простой и знакомой, а объём кода минимальным.
Что с поддержкой?
Единственная ложка дёгтя — это поддержка. В нашем случае придётся ждать как минимум двух последовательных событий:
Хорошей поддержки Style Container Queries. То есть самого механизма стилевых запросов. Здесь есть хорошие новости. Стилевые запросы добавили в интероп 2026, то есть в течение года планируют зарелизить во всех современных браузерах.
Хорошей поддержки Range Syntax For Style Container Queries. То есть продвинутого синтаксиса сравнений внутри стилевых запросов.
Если вам хочется узнать, в чём ценность нового подхода к стилизации, то можете сразу переходить к заключительной части статьи.
А если вы хотите использовать условную логику в CSS прямо сейчас, то читайте следующий раздел, в котором мы разберём фолбэк и его ограничения.
Фолбэк CSS-условий
Логику сравнений, включая сложные диапазонные сравнения, в CSS можно эмулировать с помощью математических функций и бинарной логики.
Для начала введём дополнительную переменную --gte-start и сохраним в неё результат вычитания номеров текущего и стартового дней:
Шаг 1. Вычитаем из номера текущего дня номер стартового
.calendar { --day-start: 10; --day-end: 12; } .day-now { --gte-start: calc(var(--day) - var(--day-start)); }
Возьмём десятое число как день старта. И выведем результат вычитания для каждой ячейки в правом нижнем углу. В днях до десятого получили отрицательный результат, в десятом дне — ноль, в днях после десятого — положительный результат:

--day-start из --day в каждой ячейке при --day-start: 10Шаг 2. Ограничиваем результат через clamp()
Теперь заменим обычное вычитание через calc() вычитанием через clamp(). Функция clamp() позволяет ограничивать выражение максимальным и минимальным значением. Зададим минимальное значение 0, а максимальное 1:
.day-now { --gte-start: clamp( 0, calc(var(--day) - var(--day-start)), 1 ); }
Теперь всё, что меньше 0 стало 0, всё, что больше 1 стало 1.

clamp()Шаг 3. Включаем стартовый день в диапазон
Для этого добавляем единицу к результату вычитания внутри clamp():
.day-now { --gte-start: clamp( 0, calc(var(--day) - var(--day-start) + 1), 1 ); }
Теперь стартовый день тоже даёт 1. Мы получили выражение, которое даёт результат аналогичный сравнению текущий день ≥ день старта.

Шаг 4. Добавляем вторую границу
По аналогии с первой границей диапазона добавим вторую, включающую дни которые меньше или равны конечному дню. Единственное отличие — это порядок вычитания. Теперь мы вычитаем не границу из дня, а день из границы:
.calendar { --day-start: 10; --day-end: 12; } .day-now { --gte-start: clamp(0, calc(var(--day) - var(--day-start) + 1), 1); --lte-end: clamp(0, calc(var(--day-end) - var(--day) + 1), 1); }
Второе выражение даёт результат аналогичный сравнению текущий день ≤ день конца. Вот такие значения будут в переменной --lte-end, если конечный день — 12.

--lte-end в каждой ячейке при --day-end: 12Шаг 5. Пересечение диапазонов
Используем умножение, чтобы получить логическое И:
1 × 1 = 1,
в остальных случаях = 0.
.day-now { --gte-start: clamp( 0, calc(var(--day) - var(--day-start) + 1), 1 ); --lte-end: clamp( 0, calc(var(--day-end) - var(--day) + 1), 1); --in-range: calc(var(--gte-start) * var(--lte-end)); }
Вот значения переменной --in-range. Единицы стоят у тех ячеек, которые попали в диапазон с 10 по 12 день включительно:

--in-range в каждой ячейке при --day-start: 10 и --day-end: 12Шаг 6. Зашиваем флаг в стили
Теперь у нас есть переменная, содержащая ноль в одних ячейках и единицу в других. Эти значения можно использовать в качестве компонента прозрачности цвета в фоновом изображении, которое сделано с помощью одноцветного градиента:
.day-now { background-image: linear-gradient( rgba(139, 0, 0, var(--in-range)), rgba(139, 0, 0, var(--in-range)) ); }
В ячейках, которые не попали в диапазон, фоновое изображение будет полностью прозрачным. В ячейках, которые попали в диапазон, получим заливку цветом:

Плюсы, минусы и ограничения фолбэка
Плюс фолбэка — это поддержка. Его можно использовать прямо сейчас.
Минус фолбэка — сложность. Мало кто захочет разбираться и поддерживать эту имитацию бинарной логики. Хотя запредельной эту сложность назвать нельзя.
Второй минус — ограничения по стилизации. Можно работать только с числовыми значениями CSS‑свойств, которые можно вычислять с помощью нуля и единицы. Например, удобно использовать прозрачность, толщину рамок или обводок, размер шрифта. А вот работать с перечисляемыми или строковыми значениями свойств не получится.
В чём смысл «программирования на CSS»?
Если вкратце, то всё делается ради слабой связанности aka «Loose Coupling».
Вспомните типичную реализацию на JS. Сколько всего надо знать скрипту, чтобы выполнить задачу? Перечислим:
особенности устройства разметки (плоский список или сложная таблица);
особенности использования CSS‑классов (как помечается день текущего месяца, а как смежного);
как устроена стилизация дней диапазона (имя класса, или дополнительный класс‑модификатор, или прямая стилизация через атрибут
styleс конкретным свойством и значением).
А не слишком ли много? Это и называется сильная связность.
А теперь посмотрим на реализацию с использованием CSS‑логики. В ней диапазон дат тоже задаётся скриптом. Но у скрипта есть лаконичный и понятный интерфейс в виде двух CSS‑переменных, которые он просто меняет:
.calendar { --day-start: <number>; --day-end: <number>; }
Этого интерфейса полностью достаточно для выполнения задачи. Скрипту не нужны знания о внутреннем устройстве разметки, именовании классов и особенностях стилизации.
Вся логика отображения изолирована внутри CSS.
Это и есть слабая связанность.
Это и есть следование заветам отцов‑основателей веба про разделение содержания, внешнего вида и поведения.
Скрытый текст
Подписывайтесь на мой телеграм‑канал «CSS Боль». Там собраны все материалы, видеоролики, ссылки на пошаговые демки и новости чемпионатов по фронтенду
Комментарии (47)

ImagineTables
25.02.2026 15:43Да, приходится специально инлайнить стили, но это делается один раз при генерации шаблона.
А нельзя:
Совать день в атрибут, рендерить через
contentи инициализировать переменную черезattr()?Использовать
sibling-index()(возможно, скрывая ненужное)?

AlexPershin Автор
25.02.2026 15:43Тут инлайнинг надёжнее. Ну или дата-атрибуты

ImagineTables
25.02.2026 15:43Инлайнинг всегда выглядит как хак. Поэтому я и спросил про дата-атрибуты (какие же ещё).
Я читал, что стилизация через содержимое почему-то считается авторами стандартов моветоном. Не понимаю, почему. Столько нагородили, а ведь можно было сделать диапазоны значений атрибутов в селекторах, насколько бы это лучше смотрелось.

AlexPershin Автор
25.02.2026 15:43Да в целом ту же логику можно и на data-атрибутах сделать, обновлённый attr то их умеет считывать. Тут ведь ещё какое дело — весь этот инлайнинг скорее всего будет делаться в рантайме на живом дом-дереве. Скрипт инициализирует компонент, пробежится по шаблону, проставит нужные атрибуты и будет себе их спокойно менять. И что он там проставил — дата-атрибуты или заинлайненные через style css-переменные — не особо и важно. Тем более, что и в традиционных реализациях на JS точно также дом-дерево дополнительно допиливается при инициализации, чтобы скрипту было удобнее.

AlexPershin Автор
25.02.2026 15:43Теперь отдельно про content. Наверное это можно, но мне тут больше нравится идея — оставить простой контент в разметке. И для доступности, и да и просто как-то логичнее. Таким образом мы дни внутри ячеек можем отображать, как нам больше нравится, хоть с тем же ведущим нулём. А уже в дата-атрибутах вынести в том виде, который удобнее для JS
По поводу сиблинг-индексов. Там мы упрёмся в ряды таблицы, они будут мешать. Либо, если делать плоской структурой, будем страдать с ситуациями, когда первый день месяца не совпадает с понедельником. И придётся вводить какое-то дополнительное смещение в каждом месяце, и вычитать его из значения sibling-index

winkyBrain
25.02.2026 15:43.calendar { --day-start: 4; --day-end: 6; }как же это прекрасно в сферическом вакууме) я так понимаю, с вашим датапикером пользователи не взаимодействуют и нужные дни сразу захардкожены в css? и передавать их не надо никуда впоследствии, верно? просто пользователь зашёл, увидел датапикер, в котором за него выбраны и подсвечены какие-то странные дни, порадовался и ушёл?

delphinpro
25.02.2026 15:43Эти свойства можно установить и с помощью javascript
element.style.setProperty('--day-start', 4)
winkyBrain
25.02.2026 15:43оу, пошли инлайновые стили, а сам подход ничем не отличается от смены класса. а месяц, а год? обычно в рамках подобных компонентов в js оперируют объектом Date целиком. при этом недостаточно же просто поставить куда-то в css значение 4, его в любом случае нужно хранить в рамках js, чтобы с помощью этого же js потом куда-то отдать.
вот и получается, что до этого всего у нас только js всем управлял, для подкрашивая жонглируя css-классами у элемента, а теперь мы вынесли логику подкрашивания в css, но нужно:
дублировать значения дней в css
всё равно менять не класс, так свойство у элемента
и ради чего?

delphinpro
25.02.2026 15:43Не нужно слепо бояться инлайн-стилей. Вот пример: в какой-то системе у пользователя есть возможность раскрашивать какие-то элементы. Совершенно не важно что это за элементы, просто есть возможность цветового выделения, для его удобства. Можно ограничиться каким-то фиксированным набором цветов и манипулировать классами, а можно предоставить полную свободу, и тогда вам придется в верстке раскрашивать этот блок инлайн-стилем с заданным пользователем цветом.
Мне думается, что в данном случае пример призван лишь продемонстрировать саму возможность использования новой css-фичи, а не призыв к конкретному практическому применению. Может быть быть календарь и не самый удачный выбор, но принцип работы имеет право на жизнь.

winkyBrain
25.02.2026 15:43Не нужно слепо бояться инлайн-стилей
эм...не нужно бояться js?)
не нужно выдумывать того, чего нет) лучше бы ответили на вопросы, которые вам задали.
с инлайн стилями же проблема в том, что они перемешивают в себе всё. с классами как - добавил класс .active, а в нём уже все необходимые свойства. теперь же у нас вместо .active прямо в стилях элемента какие-то свойства, не говорящие ничего о состоянии элемента, которое, кхм, active. а свойства эти вы кстати предлагаете добавлять наиболее неоптимизированным способом.
такой подход оправдан, когда нам нужно считывать позицию курсора и зашивать её в стиль элемента на лету. проще говоря там, где классами не обойтись. а здесь никакой проблемы буквально не решили, зато создали новых)

AlexPershin Автор
25.02.2026 15:43Естественно бизнес-логика крутится в JS. В исходном состоянии CSS-переменные в стилях можно инициализировать нулями и ничего не будет выделено
Когда диапазон выбран, просто устанавливаются значения переменных на корневом элементе. Можно сделать и через дата-атрибуты. Не надо ползти внутрь и в цикле вешать классы. То есть упрщается логика рендеринга. Да, вроде бы избавились всего от одного цикла, но для этого не надо писать тонну CSS, так как всё делается в одну строчку

ImagineTables
25.02.2026 15:43Что вы имеете против организации программного интерфейса элемента управления через CSS-переменные? Это распространённая практика. Пока вы думаете про против, я приведу аргументы за:
В отличие от свойств и атрибутов, CSS-переменные каскадны. Их можно собрать в одном месте, а потом менять внутреннюю структуру элемента управления, и ни о чём не думать.
С пассивными элементами управления (когда контроль над ними выносится во внешний по отношению к элементу управления код) работать зачастую удобнее.
Чем тоньше прослойка между стилизацией и кодом, тем лучше. Просто задать CSS-переменные это самая тонкая прослойка. И это лучше, чем писать циклы.
Наконец, чем меньше скриптов вообще, тем лучше.

alexchizik
25.02.2026 15:43Тоже об этом подумал. Оно вроде бы и красиво, но кажется, что пользоваться этим ещё не скоро начнут, потому что как минимум все привыкли это всё по другому реализовывать

LbISS
25.02.2026 15:43Проблема развития всех языков, что рано или поздно все думают - а наш язык самый лучший, чего он только занимается стилями? А почему бы ему не делать всё подряд? Или: а почему у нас в языке только X и Y, а в соседних языках есть Z! Давайте сделаем у нас Z!
И язык из чётко структурированного и рабочего для своей задачи превращается в гигантскую помойку, которая может всё, десятью способами и с кучей проблем и недостатков. Так было с С# после 7ой версии, которой превратили в не пойми что, где каждую семантичесеую единицу можно решить 10 способами. Примерно то же самое мне напоминает указанное решение в статье. Css переменные - прекрасная вещь, которая позволяет кастомизировать вид в рантайме и не дублировать правила. Css сам по себе заточен под стилизацию и прекрасно решает задачу.
Какие нафиг if-ы? Какие инлайн стили и вычисления? Процедурное ветвление? Зачем? Дайте JS решать задачу формирования данных, а css стилизации не надо мешать всё в кучу. Решение в статье в разы хуже одного цикла на JS. Ибо js всё равно понадобится для проставления начального и конечного дня, в итоге это просто дубликация логики в двух местах. Не считая проблем инлайн стилей, того, что переменные могут переопределяться вложенными элементами и т.п.

AlexPershin Автор
25.02.2026 15:43Тут всё-таки важно отличать, что предлагают тащить в CSS: всю бизнес-логику или сложную логику отображения. В данном случае речь о логике отображения.
И, да, стилезвые запросы и рейндж-синтаксис уже в спеках, уже в интеропах и уже в браузерах. Так что возможности есть, и использовать их будут. Вопрос, как именно.
То что решение вам кажется хуже, это нормально, у каждого своё мнение. Я считаю, что оно не хуже и не лучше, оно просто непривычное. Но с точки зрения разделения поведения и отображения — оно лучше. А вообще, помнится, мало кто протестовал, когда анимацию начали выносить в css, полосатые таблички тоже вынесли в css, и так далее

ImagineTables
25.02.2026 15:43Какие нафиг if-ы? Какие инлайн стили и вычисления? Процедурное ветвление? Зачем?
А ничего, что селекторы это и есть ветвления? А
if()в CSS это никакой неif, а инверсия селекторов? И если уж проводить параллели, это не процедурный подход, а функциональный, потому чтоif()— паттерн-матчинг, которому, как тому муравью, приделали ключевые слова из императивных ЯП. Не узнали его в гриме? ))Я, кстати, не одобряю этот чудовищный синтаксис, который придумали сортирователи гномиков из Гугла. Вместо этого я бы развивал DSL селекторов, и сделал что-то типа:
.calendar .day-now[data-day-number..=(var(--day-start), var(--day-end))] { background-color: var(--range-bg-color); }где оператор
..=(«лежит в диапазоне») дополняет операторы*=,~=,$=и прочие подобные. И может быть даже, сделал быvar()внутри этого оператора опциональным для идентификаторов, начинающихся с--(не зря же этот префикс зафорсили). Куда нагляднее, чем паттерн-матчинг при присвоении значений свойств. Но в Гугле давно разучились писать просто и понятно (если вообще когда-то умели), а после такого г. как visibility observer, который они выкатили, стало понятно, что калабуховский HTML окончательно пропал.Что касается любителей джаваскрипта, чего только от них не услышишь. В статье про «Если бы был жив flash» кто-то написал, что «все сложные UI делают на канвасе». Императивщик всегда остаётся императивщиком. Правда, непонятно, почему он пишет UI, вместо того, чтобы работать хлеборобом или наладчиком высоковольтных линий ))

AlexPershin Автор
25.02.2026 15:43с другой стороны, текущий подход к условной логике в CSS позволяет писать "тупой код", которой понятен многим. появляется возможность динамически вычислить какой-то промежуточный флаг и запульнуть его в стилевой запрос. а вот решение на сложных селекторах такой возможности не дало бы, да и очень многих отпугнуло сложностью
я из всех реакций на эту статью не вижу ни одной, где бы говорилось — "обожемой, какой сложный код, как в нём тяжело разобраться". в основном все пишут про непривычность подхода и про то, что "логике" в цсс не место. и это хороший знак. получается у ребят из гугла получилось сделать просто

ImagineTables
25.02.2026 15:43При всём к вам уважении (а я разделяю ваши подходы и, как видите, отстаиваю их), тут я не соглашусь.
Когда ветвление было вида «совпадает селектор? применяем ruleset!», вопросов ни у кого не возникало. А как часть этого ветвления перетащили из селекторов внутрь ruleset'а (я назвал этот подход «инверсией селекторов»), вот тут и возникли вопросы про непривычность подхода. Зачем было всё извращать, когда можно решить любой вопрос в рамках языка селекторов? Ведь если уже есть пяток операторов для проверки атрибутов, ещё один так и напрашивается. И никто бы ничего не сказал. Никто же не спрашивает, зачем нам оператор
$=, и никто не говорит, что это процедурное ветвление, не нужное в CSS.А во что это выльется, когда логику, ранее сосредоточенную внутри селекторов, разработчики в будущем размажут тонким слоем по ruleset'ам, я себе даже представить боюсь. Это же будет абсолютно неподдерживаемый код, ни разобраться, ни отладить. В одном месте классы вложат (nest) в темы оформления, а в другом — засунут тему в
if(), и кто будет проверять, нет ли тут дублирования и проверены ли все сочетания? Да даже вот: как это адекватно представить в DevTools? Постоянно смотреть в Computed? То ли дело как сейчас: выбрал элемент, и сразу видно список условий (селекторов), под которые он подпадает. Это не просто мелкое неудобство в инструментах разработчика, это сигнал о фундаментальных проблемах в выборе парадигмы.
AlexPershin Автор
25.02.2026 15:43Тут уже имеем, то что имеем. Авторы спеки решили сделать вот так. И обвязать всю логику вокруг CSS-переменных. Мне лично такой подход нравится, так как ложится в мой опыт работы с вёрсткой. Я вижу, как текущая реализация сочетается с другими нативными фичами. Возможно, если бы ушли в усложнение селекторов, было бы лучше, но кто уж теперь скажет.
Прикладываю скриншот того, как из этого же календаря можно сделать сложный индикатор, привязанный к этапам проведения какого-то мероприятия, причём вообще без JS. То есть крутим страницу и закрашиваются дни, соответствующие этапам, причём разные этапы можно подсветить по-разному.

vanxant
25.02.2026 15:43Дано: <input type="number">
Задача: если число отрицательное, выводить его красным и в скобках, но без минуса. Бухгалтерский стандарт-с.
Ну ладно, фиг с ним с минусом. Фиг с ним с инпутом, пусть будет td или span. Просто вывести красным, или полужирным, или на жёлтом фоне. Обычное условное форматирование из Excel-1995.
Можно такое сейчас сделать? Кажется, нет.
Гуглоидам очередной привет:)

AlexPershin Автор
25.02.2026 15:43Само число из инпута будет JS забирать и передавать куда-то в CSS. А вот может ли дальше CSS его отформатировать как вам надо? Кажется, что да, условной логикой проверяете отрицательное или нет, если отрицательное, то загоняете в
abs(), и выводите в псевдоэлемент черезcontent, там же можно и скобочки добавить, и перекрасить как вам нужно

ImagineTables
25.02.2026 15:43Через задницу всё можно ))
Меняем
<input type="number">на<input type="text">. Оттого, что вы напишете<input type="number">, браузер же не запретит вводить буквы (чтобы не обламывать вставку из буфера чисел в окружении текста). Он просто перестанет реагировать на стрелочки (если указанmin/max). А раз так, то потеря семантики не смертельна.Пишем в
patternрегулярку, которая определяет неотрицательные числа.Красим в красный:
input[type="text"]:not(:valid) { color: red; }Чтобы скринридеры и экранные клавиатуры вели себя как при прежнем режиме (с
<input type="number">), рассказываем браузеру при помощи accessibility-атрибутов, как всё обстоит с элементами на самом деле.
Таков путь, предложенный нам гуглоидами ))
А нормальный путь был бы:
Уравнять properties и attributes в праве находиться в селекторе
Развить инструменты парсинга тех и других. Может, регулярки это и отстой, но если они есть в
pattern, то должны симметрично быть и в селекторах.
Но пока HTML развивают в Гугле, такого, я уверен, не случится.
Что касается скобочек и убирания минуса, напрямую это делать всё равно нельзя, ибо content mutation может привести к закольцованности (это и на джаваскрипте не сделать, кстати говоря). Но можно отдельными элементами, например,
::before/::after. Да и с редактированием не очень понятно, как быть.
AlexPershin Автор
25.02.2026 15:43Только вот непонятна исходная задача. Допустим, отформатировать на цсс получилось и вывести через content тоже. Дальше то что с числом будет. Если нужно просто на него смотреть, то ок. Если копировать, то уже вроде как неудобно (хотя я мало работал с такими задачами).

vanxant
25.02.2026 15:43Ну для простоты задачу можно свести к имитации следующего формата ячеек в Excel (обратите внимание, что в ячейке число -12, а в таблице выглядит как "12 красное")


vanxant
25.02.2026 15:43::before, ::after и соответственно content не работают для самозакрытых тегов, таких как <br>, <img> и <input>. Можно обойти через заворачивание <input> внутрь <label>, как, собственно, и делают (label в отличие от других тегов гарантированно корректно транслирует "внутрь" своего input события ввода). Сам input вообще скрываем (но он чсх продолжает корректно работать со вводом!), всё рисуем в label::before и ::after.
Но всё равно, дотянуться до содержимого пропса input.value из CSS-стиля для label нельзя, нужен JavaScript. Так же как и для <td> нельзя привязать стиль в зависимости от содержимого (текста) ячейки.
На самом деле, стратегические последствия этого достаточно паршивые. Связка HTML+CSS+data-uri давно позволяет заменить PDF, она и машиночитаема, и адаптивна, и поддерживается на чтение любым пылесосом. Но всё это могло бы взлететь только при условии полного отказа от JS (введения доктайпа html standalone noscript), а его нельзя сделать из-за таких вот мелочей.
bakhirev
.day-now:nth-child(n+5):nth-child(-n+12) {background: red;
}
AlexPershin Автор
А как быть с диапазоном дней, который попадает в разные ряды таблицы?
bakhirev
на верстке я тоже сэкономил, и заверстал все в одном контейнере
AlexPershin Автор
Вот тут и начинается развлекуха – "А давайте вместо нормальной таблицы будем имитировать её плоской списочной структурой"
Но даже после замены таблицы плоским списком тегов остаются вопросы:
- А как удобно менять диапазоны дат? Селекторы с помощью JS ведь нельзя менять. - Как правильно вычислять коэффициенты внутри nth-child? Ведь надо ещё учитывать сдвиг первого числа месяца, когда первое число не попадает на понедельник.
И вы уверены, что вам за такую вёрстку ваш JS-разработчик потом скажет спасибо? =)
deamondz
чем плоха плоская списочная структура? a11y?
AlexPershin Автор
полностью теряется важная сущность — неделя, остаётся просто плоский список дней месяца
mityukov
Таблица нужна для семантики, где именно идут табличные данные какие-то, столбцы, строки, где это действительно важно. Для всего остального есть grid. В месяце 30 дней, которые идут один за другим. На недели мы их делим чисто для удобства и компактности отображения. Если это не "представление", то я хз, если честно. Здесь плоский список и должен быть, как по мне.
AlexPershin Автор
ну поживите без выходных и радостного ожидания пятницы, а потом обсудим ваш опыт =)
mityukov
Мне гораздо удобнее, когда разбито на недели, безусловно. Но к функционалу "date range picker" это никакого отношения не имеет. Если только там нет бизнес-правил, типа: "нельзя выбирать субботы и воскресенья". Но и это удобнее реализовать просто проверяя день недели каждого из дней в "плоском списке", чем оформлять неделю как дополнительный уровень в иерархии.
Но это все про представление. Тут нет табличной семантики, типа, в первом столбце у нас имена, во втором дни рождения и тп. Просто список дней с "переносом строки" перед каждым понедельником и другими удобными для конечного пользователя оформлениями :)
AlexPershin Автор
Так я выше задал два вопроса к решению на селекторе:
1) как в этом решении удобно двигать даты диапазона? селектор — штука статичная. сидеть генерить цсс правила и перезаписывать их в каком-то спецтеге стайл. не перебор ли?
2) как все эти смещения высчитывать внтри nth-child?
Понятно, что когда есть задача — выделить статичный диапазон — там и селектором можно. А если задача — сделать удобное апи для динамического изменения диапазона, то вряд ли селекторы будут хороши. А вот CSS-логика выглядит и простой, и удобной
oeditus
Любо-дорого наблюдать, как два программиста спорят о бизнес-сущностях :)
В США (наверное, где-то еще тоже, говорю, про что знаю) распространена практика вести учет чего угодно в системе координат с недельным индексом (там обычно фигугируют кварталы еще).
Совершенно нормально встретить в планах отгрузки что-то типа 2026/Q1/W6. Оператор ждёт, что когда он тырцнет мышкой в любое число с 22 февраля до 28 февраля — сбоку появится надпись Q1/W9.
Да, 22/02 в США — это 9-я неделя. Обсчитывать это каждый раз? А если надо показывать такой элемент управления и в Германии? А «через четыре недели»?
Наконец, аргумент, которому вам точно будет нечего противопоставить: подсветить четверги каждой третьей недели месяца.
dom1n1k
Всё это прекрасно, только разбиение на недели тут не помогает, потому что выше уровнем они ещё разбиты на месяцы - и часть недель оказывается разрезанными на куски. Так что какой-то простой селектор типа "get week #12" всё равно не прокатывает, всё равно нужна более сложная логика. И это нормально, потому что так более универсально.
dom1n1k
Плюсую, сплошной список в гриде выглядит и практичнее, и логичнее.
Логичнее, потому что время это и есть континуум, а неделя - это просто форма представления (даже одна из) и в разных странах она начинается с разных дней. А ещё в некоторых календарях недели ориентируют вертикально.
А вот как раз выбор и подсветка каких-то дней - это наоборот больше похоже на семантику и бизнес-логику. И я не уверен, что тут так уж необходимо pure css решение.
AlexPershin Автор
Хорошо, сделали списком. Что дальше? Как менять диапазон?
oeditus
Задача: подсветить все четные недели года, потому что так надо бизнесу.
dom1n1k
Здесь разбиение dom-а на недели будет не помогать, а наоборот мешать, потому что месяцы состоят из нецелого числа недель. Так-то много чего может быть, типа показать предпоследние четверги месяцев. Так что да, скорее всего, чистым css в реальности все равно не обойтись, нужно будет считать скриптами.
AlexPershin Автор
Тем не менее, в реальной жизни есть реальная сущность — неделя. Если эту реальную сущность явным образом зашить в разметку, работать с ней будет проще. Если не зашить в разметку и потом вычислять, то будет сложнее.
Ну и опять же, в чем смысл делать плоский список дней? Чисто ради сложно nth-child селектора? =)
dom1n1k
Нет, не ради
nth-child, это плохое решение. Я вообще считаю, что этот селектор для каких-то быстрых затычек, а в проде это обычно неудобно и негибко (за исключением некоторых тривиальных случаев).Аргументы за плоский дизайн были перечислены выше:
Можно настраивать день, с которого начинается неделя
Можно транспонировать календарь, делая недели вертикальными - это имеет смысл, когда месяцы идут слева направо, тогда недели естественно перетекают друг в друга.
Разбиение дом-дерева на недели в общем случае НЕ помогает, потому что неделя может быть разбита между двумя месяцами.
Лишнее дробление не мешает реализовывать любую другую логику - хоть по декадам, хоть как ещё.
В целом мне нравится выделение ячеек, как это описано в посте. Но вот логика вычисления переменных
--day-startи--day-endдолжна быть в JS - это будет гибче и универсальнее. Можно реализовывать любую бизнес логику и не бояться упереться в ограничения css-логики.AlexPershin Автор
Так у вас никто не отбирает логику вычисления переменных в JS – делайте с ними что хотите. Задача — упростить рендеринг. Она решается цсс-логикой. Но если хотите в цикле бегать по элементам — пожалуйста
dom1n1k
Я не про бег в цикле, а про вот эти "четные недели года" и "каждый второй понедельник месяца" - важно, чтобы всё это не протекало в css. А чисто рендеринг - да.
AlexPershin Автор
для примера из статьи всё будет ок. решение на цсс-логике всеядно к разметке, если номера дней размечены правильно (неважно, дата-атрибутами или заинлайненными переменными).
дискуссия ушла в сторону разметки, а цсс-логике то на разметку всё равно
ris58h
Там есть ещё реальная сущность - месяц. И реальная сущность - квартал.