Comments 49
.day-now:nth-child(n+5):nth-child(-n+12) {
background: red;
}
А как быть с диапазоном дней, который попадает в разные ряды таблицы?
на верстке я тоже сэкономил, и заверстал все в одном контейнере

Вот тут и начинается развлекуха – "А давайте вместо нормальной таблицы будем имитировать её плоской списочной структурой"
Но даже после замены таблицы плоским списком тегов остаются вопросы:
- А как удобно менять диапазоны дат? Селекторы с помощью JS ведь нельзя менять. - Как правильно вычислять коэффициенты внутри nth-child? Ведь надо ещё учитывать сдвиг первого числа месяца, когда первое число не попадает на понедельник.
И вы уверены, что вам за такую вёрстку ваш JS-разработчик потом скажет спасибо? =)
чем плоха плоская списочная структура? a11y?
полностью теряется важная сущность — неделя, остаётся просто плоский список дней месяца
Таблица нужна для семантики, где именно идут табличные данные какие-то, столбцы, строки, где это действительно важно. Для всего остального есть grid. В месяце 30 дней, которые идут один за другим. На недели мы их делим чисто для удобства и компактности отображения. Если это не "представление", то я хз, если честно. Здесь плоский список и должен быть, как по мне.
ну поживите без выходных и радостного ожидания пятницы, а потом обсудим ваш опыт =)
Мне гораздо удобнее, когда разбито на недели, безусловно. Но к функционалу "date range picker" это никакого отношения не имеет. Если только там нет бизнес-правил, типа: "нельзя выбирать субботы и воскресенья". Но и это удобнее реализовать просто проверяя день недели каждого из дней в "плоском списке", чем оформлять неделю как дополнительный уровень в иерархии.
Но это все про представление. Тут нет табличной семантики, типа, в первом столбце у нас имена, во втором дни рождения и тп. Просто список дней с "переносом строки" перед каждым понедельником и другими удобными для конечного пользователя оформлениями :)
Так я выше задал два вопроса к решению на селекторе:
1) как в этом решении удобно двигать даты диапазона? селектор — штука статичная. сидеть генерить цсс правила и перезаписывать их в каком-то спецтеге стайл. не перебор ли?
2) как все эти смещения высчитывать внтри nth-child?
Понятно, что когда есть задача — выделить статичный диапазон — там и селектором можно. А если задача — сделать удобное апи для динамического изменения диапазона, то вряд ли селекторы будут хороши. А вот CSS-логика выглядит и простой, и удобной
Любо-дорого наблюдать, как два программиста спорят о бизнес-сущностях :)
В США (наверное, где-то еще тоже, говорю, про что знаю) распространена практика вести учет чего угодно в системе координат с недельным индексом (там обычно фигугируют кварталы еще).
Совершенно нормально встретить в планах отгрузки что-то типа 2026/Q1/W6. Оператор ждёт, что когда он тырцнет мышкой в любое число с 22 февраля до 28 февраля — сбоку появится надпись Q1/W9.
Да, 22/02 в США — это 9-я неделя. Обсчитывать это каждый раз? А если надо показывать такой элемент управления и в Германии? А «через четыре недели»?
Наконец, аргумент, которому вам точно будет нечего противопоставить: подсветить четверги каждой третьей недели месяца.
Всё это прекрасно, только разбиение на недели тут не помогает, потому что выше уровнем они ещё разбиты на месяцы - и часть недель оказывается разрезанными на куски. Так что какой-то простой селектор типа "get week #12" всё равно не прокатывает, всё равно нужна более сложная логика. И это нормально, потому что так более универсально.
Люди с графиком 2/2 не очень поняли, в чём сложность. Я, как человек, который часто откладывает пятничную работу на выходные, тоже не склонен сильно высоко их ценить.
Плюсую, сплошной список в гриде выглядит и практичнее, и логичнее.
Логичнее, потому что время это и есть континуум, а неделя - это просто форма представления (даже одна из) и в разных странах она начинается с разных дней. А ещё в некоторых календарях недели ориентируют вертикально.
А вот как раз выбор и подсветка каких-то дней - это наоборот больше похоже на семантику и бизнес-логику. И я не уверен, что тут так уж необходимо pure css решение.
Хорошо, сделали списком. Что дальше? Как менять диапазон?
Задача: подсветить все четные недели года, потому что так надо бизнесу.
все четные недели года
Здесь разбиение dom-а на недели будет не помогать, а наоборот мешать, потому что месяцы состоят из нецелого числа недель. Так-то много чего может быть, типа показать предпоследние четверги месяцев. Так что да, скорее всего, чистым css в реальности все равно не обойтись, нужно будет считать скриптами.
Тем не менее, в реальной жизни есть реальная сущность — неделя. Если эту реальную сущность явным образом зашить в разметку, работать с ней будет проще. Если не зашить в разметку и потом вычислять, то будет сложнее.
Ну и опять же, в чем смысл делать плоский список дней? Чисто ради сложно nth-child селектора? =)
Нет, не ради nth-child, это плохое решение. Я вообще считаю, что этот селектор для каких-то быстрых затычек, а в проде это обычно неудобно и негибко (за исключением некоторых тривиальных случаев).
Аргументы за плоский дизайн были перечислены выше:
Можно настраивать день, с которого начинается неделя
Можно транспонировать календарь, делая недели вертикальными - это имеет смысл, когда месяцы идут слева направо, тогда недели естественно перетекают друг в друга.
Разбиение дом-дерева на недели в общем случае НЕ помогает, потому что неделя может быть разбита между двумя месяцами.
Лишнее дробление не мешает реализовывать любую другую логику - хоть по декадам, хоть как ещё.
В целом мне нравится выделение ячеек, как это описано в посте. Но вот логика вычисления переменных --day-start и --day-end должна быть в JS - это будет гибче и универсальнее. Можно реализовывать любую бизнес логику и не бояться упереться в ограничения css-логики.
Так у вас никто не отбирает логику вычисления переменных в JS – делайте с ними что хотите. Задача — упростить рендеринг. Она решается цсс-логикой. Но если хотите в цикле бегать по элементам — пожалуйста
Я не про бег в цикле, а про вот эти "четные недели года" и "каждый второй понедельник месяца" - важно, чтобы всё это не протекало в css. А чисто рендеринг - да.
Там есть ещё реальная сущность - месяц. И реальная сущность - квартал.
Смысл ещё и в том, что бэкендеру будет проще это формировать, нежели гонять цикл 1..7 от 4 до 6 раз.
Да, приходится специально инлайнить стили, но это делается один раз при генерации шаблона.
А нельзя:
Совать день в атрибут, рендерить через
contentи инициализировать переменную черезattr()?Использовать
sibling-index()(возможно, скрывая ненужное)?
Тут инлайнинг надёжнее. Ну или дата-атрибуты
Инлайнинг всегда выглядит как хак. Поэтому я и спросил про дата-атрибуты (какие же ещё).
Я читал, что стилизация через содержимое почему-то считается авторами стандартов моветоном. Не понимаю, почему. Столько нагородили, а ведь можно было сделать диапазоны значений атрибутов в селекторах, насколько бы это лучше смотрелось.
Да в целом ту же логику можно и на data-атрибутах сделать, обновлённый attr то их умеет считывать. Тут ведь ещё какое дело — весь этот инлайнинг скорее всего будет делаться в рантайме на живом дом-дереве. Скрипт инициализирует компонент, пробежится по шаблону, проставит нужные атрибуты и будет себе их спокойно менять. И что он там проставил — дата-атрибуты или заинлайненные через style css-переменные — не особо и важно. Тем более, что и в традиционных реализациях на JS точно также дом-дерево дополнительно допиливается при инициализации, чтобы скрипту было удобнее.
Теперь отдельно про content. Наверное это можно, но мне тут больше нравится идея — оставить простой контент в разметке. И для доступности, и да и просто как-то логичнее. Таким образом мы дни внутри ячеек можем отображать, как нам больше нравится, хоть с тем же ведущим нулём. А уже в дата-атрибутах вынести в том виде, который удобнее для JS
По поводу сиблинг-индексов. Там мы упрёмся в ряды таблицы, они будут мешать. Либо, если делать плоской структурой, будем страдать с ситуациями, когда первый день месяца не совпадает с понедельником. И придётся вводить какое-то дополнительное смещение в каждом месяце, и вычитать его из значения sibling-index
.calendar {
--day-start: 4;
--day-end: 6;
}как же это прекрасно в сферическом вакууме) я так понимаю, с вашим датапикером пользователи не взаимодействуют и нужные дни сразу захардкожены в css? и передавать их не надо никуда впоследствии, верно? просто пользователь зашёл, увидел датапикер, в котором за него выбраны и подсвечены какие-то странные дни, порадовался и ушёл?
Эти свойства можно установить и с помощью javascript
element.style.setProperty('--day-start', 4)
оу, пошли инлайновые стили, а сам подход ничем не отличается от смены класса. а месяц, а год? обычно в рамках подобных компонентов в js оперируют объектом Date целиком. при этом недостаточно же просто поставить куда-то в css значение 4, его в любом случае нужно хранить в рамках js, чтобы с помощью этого же js потом куда-то отдать.
вот и получается, что до этого всего у нас только js всем управлял, для подкрашивая жонглируя css-классами у элемента, а теперь мы вынесли логику подкрашивания в css, но нужно:
дублировать значения дней в css
всё равно менять не класс, так свойство у элемента
и ради чего?
Не нужно слепо бояться инлайн-стилей. Вот пример: в какой-то системе у пользователя есть возможность раскрашивать какие-то элементы. Совершенно не важно что это за элементы, просто есть возможность цветового выделения, для его удобства. Можно ограничиться каким-то фиксированным набором цветов и манипулировать классами, а можно предоставить полную свободу, и тогда вам придется в верстке раскрашивать этот блок инлайн-стилем с заданным пользователем цветом.
Мне думается, что в данном случае пример призван лишь продемонстрировать саму возможность использования новой css-фичи, а не призыв к конкретному практическому применению. Может быть быть календарь и не самый удачный выбор, но принцип работы имеет право на жизнь.
Не нужно слепо бояться инлайн-стилей
эм...не нужно бояться js?)
не нужно выдумывать того, чего нет) лучше бы ответили на вопросы, которые вам задали.
с инлайн стилями же проблема в том, что они перемешивают в себе всё. с классами как - добавил класс .active, а в нём уже все необходимые свойства. теперь же у нас вместо .active прямо в стилях элемента какие-то свойства, не говорящие ничего о состоянии элемента, которое, кхм, active. а свойства эти вы кстати предлагаете добавлять наиболее неоптимизированным способом.
такой подход оправдан, когда нам нужно считывать позицию курсора и зашивать её в стиль элемента на лету. проще говоря там, где классами не обойтись. а здесь никакой проблемы буквально не решили, зато создали новых)
Естественно бизнес-логика крутится в JS. В исходном состоянии CSS-переменные в стилях можно инициализировать нулями и ничего не будет выделено
Когда диапазон выбран, просто устанавливаются значения переменных на корневом элементе. Можно сделать и через дата-атрибуты. Не надо ползти внутрь и в цикле вешать классы. То есть упрщается логика рендеринга. Да, вроде бы избавились всего от одного цикла, но для этого не надо писать тонну CSS, так как всё делается в одну строчку
Что вы имеете против организации программного интерфейса элемента управления через CSS-переменные? Это распространённая практика. Пока вы думаете про против, я приведу аргументы за:
В отличие от свойств и атрибутов, CSS-переменные каскадны. Их можно собрать в одном месте, а потом менять внутреннюю структуру элемента управления, и ни о чём не думать.
С пассивными элементами управления (когда контроль над ними выносится во внешний по отношению к элементу управления код) работать зачастую удобнее.
Чем тоньше прослойка между стилизацией и кодом, тем лучше. Просто задать CSS-переменные это самая тонкая прослойка. И это лучше, чем писать циклы.
Наконец, чем меньше скриптов вообще, тем лучше.
Тоже об этом подумал. Оно вроде бы и красиво, но кажется, что пользоваться этим ещё не скоро начнут, потому что как минимум все привыкли это всё по другому реализовывать
Проблема развития всех языков, что рано или поздно все думают - а наш язык самый лучший, чего он только занимается стилями? А почему бы ему не делать всё подряд? Или: а почему у нас в языке только X и Y, а в соседних языках есть Z! Давайте сделаем у нас Z!
И язык из чётко структурированного и рабочего для своей задачи превращается в гигантскую помойку, которая может всё, десятью способами и с кучей проблем и недостатков. Так было с С# после 7ой версии, которой превратили в не пойми что, где каждую семантичесеую единицу можно решить 10 способами. Примерно то же самое мне напоминает указанное решение в статье. Css переменные - прекрасная вещь, которая позволяет кастомизировать вид в рантайме и не дублировать правила. Css сам по себе заточен под стилизацию и прекрасно решает задачу.
Какие нафиг if-ы? Какие инлайн стили и вычисления? Процедурное ветвление? Зачем? Дайте JS решать задачу формирования данных, а css стилизации не надо мешать всё в кучу. Решение в статье в разы хуже одного цикла на JS. Ибо js всё равно понадобится для проставления начального и конечного дня, в итоге это просто дубликация логики в двух местах. Не считая проблем инлайн стилей, того, что переменные могут переопределяться вложенными элементами и т.п.
Тут всё-таки важно отличать, что предлагают тащить в CSS: всю бизнес-логику или сложную логику отображения. В данном случае речь о логике отображения.
И, да, стилезвые запросы и рейндж-синтаксис уже в спеках, уже в интеропах и уже в браузерах. Так что возможности есть, и использовать их будут. Вопрос, как именно.
То что решение вам кажется хуже, это нормально, у каждого своё мнение. Я считаю, что оно не хуже и не лучше, оно просто непривычное. Но с точки зрения разделения поведения и отображения — оно лучше. А вообще, помнится, мало кто протестовал, когда анимацию начали выносить в css, полосатые таблички тоже вынесли в css, и так далее
Какие нафиг 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, вместо того, чтобы работать хлеборобом или наладчиком высоковольтных линий ))
с другой стороны, текущий подход к условной логике в CSS позволяет писать "тупой код", которой понятен многим. появляется возможность динамически вычислить какой-то промежуточный флаг и запульнуть его в стилевой запрос. а вот решение на сложных селекторах такой возможности не дало бы, да и очень многих отпугнуло сложностью
я из всех реакций на эту статью не вижу ни одной, где бы говорилось — "обожемой, какой сложный код, как в нём тяжело разобраться". в основном все пишут про непривычность подхода и про то, что "логике" в цсс не место. и это хороший знак. получается у ребят из гугла получилось сделать просто
При всём к вам уважении (а я разделяю ваши подходы и, как видите, отстаиваю их), тут я не соглашусь.
Когда ветвление было вида «совпадает селектор? применяем ruleset!», вопросов ни у кого не возникало. А как часть этого ветвления перетащили из селекторов внутрь ruleset'а (я назвал этот подход «инверсией селекторов»), вот тут и возникли вопросы про непривычность подхода. Зачем было всё извращать, когда можно решить любой вопрос в рамках языка селекторов? Ведь если уже есть пяток операторов для проверки атрибутов, ещё один так и напрашивается. И никто бы ничего не сказал. Никто же не спрашивает, зачем нам оператор $=, и никто не говорит, что это процедурное ветвление, не нужное в CSS.
А во что это выльется, когда логику, ранее сосредоточенную внутри селекторов, разработчики в будущем размажут тонким слоем по ruleset'ам, я себе даже представить боюсь. Это же будет абсолютно неподдерживаемый код, ни разобраться, ни отладить. В одном месте классы вложат (nest) в темы оформления, а в другом — засунут тему в if(), и кто будет проверять, нет ли тут дублирования и проверены ли все сочетания? Да даже вот: как это адекватно представить в DevTools? Постоянно смотреть в Computed? То ли дело как сейчас: выбрал элемент, и сразу видно список условий (селекторов), под которые он подпадает. Это не просто мелкое неудобство в инструментах разработчика, это сигнал о фундаментальных проблемах в выборе парадигмы.
Тут уже имеем, то что имеем. Авторы спеки решили сделать вот так. И обвязать всю логику вокруг CSS-переменных. Мне лично такой подход нравится, так как ложится в мой опыт работы с вёрсткой. Я вижу, как текущая реализация сочетается с другими нативными фичами. Возможно, если бы ушли в усложнение селекторов, было бы лучше, но кто уж теперь скажет.
Прикладываю скриншот того, как из этого же календаря можно сделать сложный индикатор, привязанный к этапам проведения какого-то мероприятия, причём вообще без JS. То есть крутим страницу и закрашиваются дни, соответствующие этапам, причём разные этапы можно подсветить по-разному.

Дано: <input type="number">
Задача: если число отрицательное, выводить его красным и в скобках, но без минуса. Бухгалтерский стандарт-с.
Ну ладно, фиг с ним с минусом. Фиг с ним с инпутом, пусть будет td или span. Просто вывести красным, или полужирным, или на жёлтом фоне. Обычное условное форматирование из Excel-1995.
Можно такое сейчас сделать? Кажется, нет.
Гуглоидам очередной привет:)
Само число из инпута будет JS забирать и передавать куда-то в CSS. А вот может ли дальше CSS его отформатировать как вам надо? Кажется, что да, условной логикой проверяете отрицательное или нет, если отрицательное, то загоняете в abs() , и выводите в псевдоэлемент через content, там же можно и скобочки добавить, и перекрасить как вам нужно
Через задницу всё можно ))
Меняем
<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. Да и с редактированием не очень понятно, как быть.
Только вот непонятна исходная задача. Допустим, отформатировать на цсс получилось и вывести через content тоже. Дальше то что с числом будет. Если нужно просто на него смотреть, то ок. Если копировать, то уже вроде как неудобно (хотя я мало работал с такими задачами).
::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), а его нельзя сделать из-за таких вот мелочей.

Восхитительный Range Syntax в CSS