Смежные селекторы предшествующих элементов CSS и способы их имитации
От автора: если вы когда-либо использовали смежные селекторы CSS одного уровня, вы знаете, что их всего два. Комбинатор + выбирает первое соответствие, которое находит сразу после, а комбинатор ~ выбирает все последующие.
Но у нас нет способа выбрать те, которые расположены раньше. Либо родительские селекторы, либо предыдущие селекторные одного уровня — такого просто нет.
Я знаю, что вы этого хотите, вы знаете, что я этого хочу, но суровая правда в том, что они не существуют (и, вероятно, никогда не будут). Есть миллион сообщений «Почему?». Есть даже предложения о том, как их реализовать. Но мы застреваем на однонаправленной обработке правил CSS — это делается, скорее всего, чтобы защитить нас от «плохого опыта», связанного с неправильным течением потока обработки или даже бесконечными циклами.
К счастью, как и в случае большинства ограничений CSS, мы можем имитировать это. Первое, что нужно учитывать — это то, для чего нам нужны предыдущие одноуровневые элементы. Существуют два случая:
Нам нужно выбрать все элементы одного уровня с элементом, а комбинатор ~ выбирает только те, которые расположены после.
Онлайн курс по JavaScript
Научитесь создавать приложения со сложными интерфейсами
Это основной язык для современной веб-разработки — почти 100% сайтов работает на JavaScript. Освойте его с нуля всего за 4 месяца, и вы сможете зарабатывать от 70 000 рублей.
Нам нужно выбрать только элементы одного уровня, которые расположены раньше
1. Выбор всех элементов одного уровня
Иногда нам нужно выбрать как предыдущие, так и последующие элементы одного уровня. Для этого мы можем выбрать родительский элемент и использовать некоторые хитрости.
Например, чтобы выбрать все span в следующей структуре, когда мы наводим указатель мыши на любой из них, мы могли бы просто использовать селектор дочерних элементов для родителя. Нам нужно переключить pointer-events с родителя на дочерние элементы. Таким образом, любое действие, которое мы хотим осуществить, будет срабатывать только при вводе для дочернего элемента, а не самого родителя.
/*или что угодно, что вы хотите сделать с со всеми элементами одного уровня, когда вы наводите мышь на один из них */
Если вам нужно выбрать все элементы одного уровня, кроме того, на который был наведен курсор, вы можете совместить предыдущий метод с селектором :not, чтобы исключить его. Стандартным примером для этого является меню:
В приведенном выше коде будет переключаться непрозрачность всех элементов li, кроме того, что на который наведен курсор.
Кроме того, вы можете использовать селекторы type и nth, чтобы дополнительно отфильтровать нужные элементы. Задав определенные стили, мы можем получить следующее:
Обратите внимание: если вы хотите использовать подход pointer-events:none, помните, что это может нарушить порядок стекирования (возможно, вы выберете элементы, которые «ниже» в порядке стекирования). Это также не будет работать в IE10 и ниже, если только вам не нужны указатели события для чего-то другого. Поэтому будьте очень осторожны при использовании.
2. Выбор предыдущих элементов
Для этого варианта использования мы можем изменить в обратном направлении порядок сортировки в HTML, а затем отсортировать элементы обратно в CSS и использовать селекторы ~ и +. Таким образом, мы будем выбирать следующие элементы, но самом деле это будут предыдущие.
Существует несколько способов сделать это. Самый простой и, вероятно, самый старый — это изменение направления написания нашего контейнера:
Если ваши элементы должны отображать фактический текст, вы всегда можете отменить это обратно:
Но во многих случаях это может быть неудобно. К счастью, современный инструментарий CSS позволяет сделать это намного проще и безопаснее. Мы можем просто использовать для контейнера Flexbox и изменить порядок с помощью flex-direction: row-reverse:
Лучшее в этом подходе то, что мы не вносим путаницу в направление написания. Нам не нужно перезагружать дочерние элементы, и все гораздо более предсказуемо.
Использование «предыдущих элементов одного уровня» для создания системы звезд-рейтингов на чистом CSS
Семантически, рейтинговую систему можно рассматривать как простой список радио-кнопок с соответствующими метками. Это позволит нам использовать проверенный псевдо-селектор :checked для изменения элементов одного уровня. Итак, давайте начнем с этого:
Как мы рассматривали ранее, элементы находятся в обратном порядке тому, который позволяет нам применить селектор «предыдущий элемент одного уровня». Обратите внимание, что мы используем для представления пустых звезд символ юникода “white star” (U + 2606).
Давайте отобразим их рядом друг с другом, в правильном (обратном) порядке:
Теперь скроем сами переключатели, никому не нужно их видеть:
И применим некоторые стили к символам звездочек:
Единственная действительно важная строка — это position: relative. Это позволит нам по абсолютно позиционировать псевдо-элемент с закрашенной звездой (U + 2605), который будет изначально скрыт.
Когда мы наводим указатель на звездочку, псевдо-элемент закрашенной звездный должен стать видимым для нее и всех предыдущих одноуровневых элементов.
То же делается для выбранного рейтинга, через сопоставление всех меток, которые находятся перед выбранной радио-кнопкой:
Помните, что использование флага !important прямо противоположно хорошей практике. Я делаю это здесь, так как другого способа реализовать данный функционал нет.
И последнее, но не менее важное: нам нужно «запомнить» текущий рейтинг, на случай, если пользователь захочет его изменить. Например, если он выбрал пять звезд и по какой-либо причине хочет изменить их на четыре, мы должны отображать звезды с 1 по 4, как заполненные, а пятую — полупрозрачной при наведении указателя на четвертую.
Это может быть достигнуто путем изменения при наведении курсора на контейнер непрозрачности предыдущих элементов одного уровня выбранного ввода:
Вот для чего нам нужно pacity:1 !important в начальном объявлении наведения. В противном случае это последнее правило переопределило бы другие в соответствии со специфичностью и применило полупрозрачную заливку ко всему.
И там у нас есть это, кроссбраузерная, полностью функциональная система звезд-рейтингов с использованием только селекторов «предыдущие элементы одного уровня».
Как вы можете видеть, просто потому, что «это невозможно» не означает, что вы не должны пытаться. Программирование — это раздвижение границ. Поэтому каждый раз, когда вы упираетесь в стену, просто попробуйте надавить немного сильнее. Или лучшей аналогией, я думаю, будет — найдите свой обходной путь? … в любом случае, вы понимаете, что я имею в виду. Продолжайте взламывать!
Замечания относительно доступности
Предыдущий фрагмент — это упрощение для лучшего понимания. Это не то, что я бы рекомендовал использовать в реальной среде из-за многих ограничений доступности.
Чтобы сделать сниппет немного более доступным, первым делом нужно было бы скрыть радио-кнопки с помощью другого способа, а не display: none, чтобы сделать их фокусируемыми. Мы также должны добавить кольцо фокусировки на весь фрагмент звёзд, когда любой элемент внутри выделен фокусом, это делается через псевдо-селектор :focus-in.
Метки «звезды» не имеют смысла для экранных дикторов, поэтому наилучшим подходом будет наличие внутри метки span с текстом «n Stars», который будет скрыт от видящих пользователей.
Кроме того, подход с обратным порядком в HTML-источнике + display:row-reverse делает клавиатуру неудобной для выставления рейтингов. Доступность Flexbox и клавиатуры — довольно сложная тема, но ближе всего к решению подход, когда для каждого элемента добавляется тег aria-flowtotag, что, по крайней мере, устраняет проблему для некоторых экранных дикторов + комбинации браузеров.
Более доступный сниппет (использующий альтернативную технику изменения следующих элементов одного уровня, которые выглядят пустыми) вы можете найти у Патрика Коула, как описано в комментариях ниже.
Автор: Facundo Corradini
Онлайн курс по JavaScript
Научитесь создавать приложения со сложными интерфейсами
Это основной язык для современной веб-разработки — почти 100% сайтов работает на JavaScript. Освойте его с нуля всего за 4 месяца, и вы сможете зарабатывать от 70 000 рублей.
Редакция: Команда webformyself.
Соседние селекторы
Соседними называются элементы веб-страницы, когда они следуют непосредственно друг за другом в коде документа. Рассмотрим несколько примеров отношения элементов.
Lorem ipsum dolor sit amet.
В этом примере тег является дочерним по отношению к тегу
, поскольку он находится внутри этого контейнера. Соответственно
выступает в качестве родителя .
Lorem ipsum dolor sit amet.
Здесь теги и никак не перекрываются и представляют собой соседние элементы. То, что они расположены внутри контейнера
, никак не влияет на их отношение.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Соседними здесь являются теги и , а также и . При этом и к соседним элементам не относятся из-за того, что между ними расположен контейнер .
Для управления стилем соседних элементов используется символ плюса (+), который устанавливается между двумя селекторами. Общий синтаксис следующий.
Пробелы вокруг плюса не обязательны, стиль при такой записи применяется к Селектору 2, но только в том случае, если он является соседним для Селектора 1 и следует сразу после него.
В примере 11.1 показана структура взаимодействия тегов между собой.
Пример 11.1. Использование соседних селекторов
HTML5 CSS 2.1 IE Cr Op Sa Fx
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Результат примера показан на рис. 11.1.
Рис. 11.1. Выделение текста цветом при помощи соседних селекторов
В данном примере происходит изменение цвета текста для содержимого контейнера , когда он располагается сразу после контейнера . В первом абзаце такая ситуация реализована, поэтому слово «consectetuer» в браузере отображается красным цветом. Во втором абзаце, хотя и присутствует тег , но по соседству никакого тега нет, так что стиль к этому контейнеру не применяется.
Разберем более практичный пример. Часто возникает необходимость в текст статьи включать различные сноски и примечания. Обычно для этой цели создают новый стилевой класс и применяют его к абзацу, таким способом можно легко изменить вид текста. Но мы пойдем другим путём и воспользуемся соседними селекторами. Для выделения замечаний создадим новый класс, назовём его sic , и станем применять его к тегу . Первый абзац после такого заголовка выделяется цветом фона и отступом (пример 11.2). Вид остальных абзацев останется неизменным.
Пример 11.2. Изменение стиля абзаца
HTML5 CSS 2.1 IE Cr Op Sa Fx
Методы ловли льва в пустыне
Метод последовательного перебора
Пусть лев имеет габаритные размеры L x W x H, где L - длина льва от кончика носа до кисточки хвоста, W - ширина льва, а H - его высота. После чего пустыню разбиваем на ряд элементарных прямоугольников, размер которых совпадает с шириной и длиной льва. Учитывая, что лев может находиться не строго на заданном участке, а одновременно на двух из них, клетку для ловли следует делать повышенной площади, а именно 2L x 2W. Благодаря этому мы избежим ошибки, когда в клетке окажется пойманным лишь половина льва или, что хуже, только его хвост.
Для упрощения расчетов хвост в качестве погрешности измерения можно отбросить и не принимать во внимание.
Далее последовательно накрываем каждый из размеченных прямоугольников пустыни клеткой и проверяем, пойман лев или нет. Как только лев окажется в клетке, процедура поимки считается завершенной.
Результат данного примера показан на рис. 11.2.
Рис. 11.2. Изменение вида абзаца за счёт использования соседних селекторов
В данном примере текст отформатирован с применением абзацев (тег
), но запись H2.sic + P устанавливает стиль только для первого абзаца идущего после тега , у которого добавлен класс с именем sic .
Соседние селекторы удобно использовать для тех тегов, к которым автоматически добавляются отступы, чтобы самостоятельно регулировать величину отбивки. Например, если подряд идут теги и , то расстояние между ними легко регулировать как раз с помощью соседних селекторов. Аналогично дело обстоит и для идущих подряд тегов и
, а также в других подобных случаях. В примере 11.3 таким манером изменяется величина отступов между указанными тегами.
Пример 11.3. Отступы между заголовками и текстом
HTML5 CSS 2.1 IE Cr Op Sa Fx
Заголовок 1
Заголовок 2
Абзац!
Поскольку при использовании соседних селекторов стиль применяется только ко второму элементу, то размер отступов уменьшается за счёт включения отрицательного значения у свойства margin-top . При этом текст поднимается вверх, ближе к предыдущему элементу.
Вопросы для проверки
1. Какие теги в данном коде являются соседними?
2. Имеется следующий код HTML:
Какой текст выделится красным цветом с помощью стиля SUP + SUP < color: red; >?