Як зробити неможливе можливим у CSS, додавши трохи творчості

Якщо ви коли-небудь використовували селектори CSS для братів і сестер, ви знаєте, що їх всього два. +Родинний Combinator вибирає перший матч , який приходить відразу після того, як , і ~наступні-споріднений комбінатор відповідає всім ті , які приходять після.

Але немає можливості вибрати те, що було раніше. Або батьківські селектори, або попередні селектори братів і сестер просто не є річчю.

Я знаю, що ти цього хочеш, ти знаєш, що я цього хочу, але сувора правда полягає в тому, що їх не існує (і, мабуть, ніколи не буде). Є мільйон постів про те, чому. Є навіть пропозиції щодо того, як їх реалізувати. Але ми застрягли в односпрямованій обробці правил CSS, швидше за все, щоб захистити нас від нашої «недостатньої кваліфікації», що застряє в повторних потоках і навіть нескінченних циклах.

На щастя, як і більшість обмежень CSS, ми можемо підробити .

Перше, що слід врахувати, це те, чому ми хочемо, щоб попередні брати і сестри почали з того.

Пам’ятаються два випадки:

  1. Нам потрібно вибрати всіх братів і сестер певного елемента, а ~наступний комбінатор братів і сестер лише вибирає тих, які приходять після.
  2. Нам потрібно відібрати лише братів і сестер, які були раніше

1. Вибір усіх братів і сестер

Іноді нам потрібно відібрати як попередніх, так і наступних братів і сестер. Для цього ми можемо фактично вибрати батька та скористатися деякими хитрощами навколо нього.

Наприклад, щоб вибрати всі прольоти в такій структурі, коли ми наводимо будь-який з них, ми могли б просто використовувати дочірній селектор на батьківському наведенні. Ми обов’язково відключаємо pointer-eventsбатьківський і повертаємо його до дітей. Тож, які б дії ми не хотіли, відбуватимуться лише тоді, коли ми увійдемо до дитини, а не до самого батька.

Якщо вам потрібно вибрати всіх братів і сестер, крім того, що наводиться, ви можете поєднати попередню техніку з :notселектором, щоб виключити її.

Типовим варіантом використання для цього є меню:

Наведений вище код буде зменшіть непрозорість всіх <li> Ель Мент s , але одне істоти парило.

Крім того, ви можете використовувати фільтри, такі як тип і n-й селектори, щоб бути надзвичайно точними щодо братів і сестер, на яких ви хочете вплинути.

З деяким стилем він повинен працювати так:

Зверніть увагу : якщо ви збираєтеся запустити pointer-events:noneпідхід, майте на увазі, що він може зіпсуватись з укладанням (можливо, ви зможете вибрати елементи, які знаходяться внизу в порядку укладання). Це також не буде працювати в IE10 і нижче, крім наслідків того, що вам можуть знадобитися події вказівника для чогось іншого. Тож будьте дуже обережні при його використанні.

2. Вибір того, що було раніше

У цьому випадку ми можемо змінити порядок у HTML, потім відсортувати його назад у CSS і використати ~наступний комбінатор братів або +сестер або сусідній селектор сестер. Таким чином ми будемо відбирати наступних братів і сестер, але це буде виглядати так, ніби ми обираємо попередніх.

Для цього існує кілька способів. Найпростішим і, мабуть, найстарішим є зміна напрямку написання нашого контейнера:

Якщо ваші елементи повинні відображати фактичний текст, ви завжди можете повернути його назад:

Але це може вийти з-під контролю багатьма способами. На щастя, сучасний набір інструментів CSS робить його набагато простішим та безпечнішим. Ми можемо просто використовувати Flexbox на контейнері і змінити порядок за допомогою flex-direction:row-reverse:

Найкраще у підході Flexbox - це те, що ми не балуємося з напрямком написання. Нам не потрібно перезавантажувати дітей, і все набагато передбачуваніше.

Використання “попередніх братів і сестер” для створення системи оцінки зірок лише для CSS

Семантично систему оцінювання можна сприймати як простий перелік перемикачів із відповідними позначками. Це стане в нагоді, оскільки це дозволить нам використовувати :checkedпсевдоселектор для модифікації братів і сестер.

Отже, почнемо звідти:

Як ми вже обговорювали раніше, елементи розташовані в зворотному порядку, щоб дозволити селектор "попереднього брата". Зверніть увагу, що ми використовуємо символ “біла зірка” в унікоді (U + 2606) для представлення порожніх зірок.

Давайте відобразимо їх поруч, у правильному (зворотному) порядку:

Тепер приховуйте самі перемикачі, ніхто не хоче бачити, що:

І застосуйте стилістика до зіркових персонажів:

Єдиною справді важливою лінією є position:relative. Це дозволить нам абсолютно позиціонувати заповнений зірковий (U + 2605) псевдоелемент поверх нього, який спочатку буде прихований.

Коли ми наводимо курсор на зірку, заповнений псевдоелемент зірки повинен стати видимим для нього та всіх попередніх братів і сестер.

Те саме для вибраного рейтингу, зіставляючи всі мітки, що стоять перед позначеним перемикачем:

Пам'ятайте , що використання! Важливий прапора є точно протилежністю доброї практики. Я роблю це тут, оскільки немає іншого способу досягти додаткової функціональності, обговореної в наступному розділі, без неї.

І останнє, але не менш важливе, нам потрібно «запам’ятати» поточний рейтинг, на випадок, якщо користувач захоче його змінити. Наприклад, якщо вони вибрали п’ять зірок і з якоїсь причини хочуть змінити їх на чотири, ми повинні показати зірки від 1 до 4 як заповнені, а п’яту як напівпрозорі, коли наводимо курсор на четверту.

Цього можна досягти, змінивши непрозорість попередніх побратимів перевіреного вводу при наведенні на контейнер:

Ось чому нам також знадобилося opacity:1 !importantв початковій декларації наведення. Інакше це останнє правило виграло б конкурс специфіки та застосувало б напівпрозору заливку до всього.

І ось у нас є - крос-браузерна, повнофункціональна система оцінки зірок, що має лише CSS, що використовує селектори “попередніх братів і сестер”.

Як бачите, те, що “це неможливо”, не означає, що вам не слід намагатися. Програмування - це розсування меж. Тому щоразу, коли ви б’єтеся об стіну, просто натискайте трохи сильніше. Або, мабуть, знаходження вашого шляху навколо цього може бути кращою аналогією? ... у будь-якому випадку, ви розумієте, що я маю на увазі. Продовжуйте злом!

Примітка щодо доступності

Попередній фрагмент - це спрощення, щоб полегшити його розуміння. Це не те, що я рекомендував би використовувати у виробництві через багато обмежень доступності.

Для того, щоб зробити фрагмент трохи доступнішим, першим ділом було б приховати перемикачі майже будь-якою технікою, крім того, display:noneщоб зробити їх цілеспрямованими. Ми також повинні додати кільце фокусування на фрагмент цілих зірок, коли будь-який елемент всередині сфокусований за допомогою псевдоселектора :focus-within.

Ідентичні позначки "☆" не мають сенсу для зчитувачів екрану, тому найкращим підходом буде наявність an> inside the label with “n Stars” text, that will be hidden from sighted users .

Also the reverse HTML source + display:row-reverse approach makes keyboard rating awkward, as it doesn’t get reversed back. Flexbox and keyboard accessibility is quite a messy topic, but closest thing to a solution for that one is adding aria-flowtotag to each element, which at least fixes the issue for some screen readers + browser combinations.

For a more accessible snippet (using an alternative technique of modifying next siblings to look empty instead of trying to asses previous ones) check Patrick Cole’s, as we discussed in the answers below.

Original text