Как стать автором
Обновить

Понять комбинаторные селекторы и селекторы потомков в CSS

Уровень сложностиПростой
Время на прочтение3 мин
Количество просмотров5.7K

Периодически я сталкиваюсь с проблемой - не хочу ставить лишний класс элементу внутри различных кнопок, ссылок и label-ов. Зачастую это текст, который нужно подсветить или галочка чекбокса или маленькая иконка.

Как же справиться с такой проблемой? Тут самым простым и понятным решением будет наследование. Возьмём код ссылки с иконкой, которую нужно анимировать:

<a href="#" class="text_arrow-btn">
  <span>Все товары</span>
  <svg width="37" height="15" viewBox="0 0 37 15" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M0 7.5H36M36 7.5L31.1538 0.5M36 7.5L31.1538 14.5" stroke="#323F4C"></path>
  </svg>
</a>

Сделать это несложно, достаточно просто прописать несколько правил:

/*БАЗОВЫЕ ПРАВИЛА*/
a {
  text-decoration: none;
  color: inherit;
  font-family: sans-serif;
}

.text_arrow-btn {
  display: flex;
  align-items: center;
  font-size: 22px;
  line-height: 142%;
}

/*ИСПОЛЬЗОВАНИЕ НАСЛЕДОВАНИЯ*/
.text_arrow-btn span { /*Для span которые внутри ссылки*/
  margin-right: 16px;
}

.text_arrow-btn svg { /*Для svg которые внутри ссылки*/
  transition: transform 0.3s;
  width: 36px;
  height: 14px;
}

.text_arrow-btn:hover span {
  text-decoration: underline;
}

.text_arrow-btn:hover svg {
  transform: translateX(12px);
}

Пробел обращается ко всем детям элемента с подходящим селектором. Символ "больше" > обратится только к прямому потомку.

Да, в CSS выглядет не очень, но в SASS всё уже немного приятнее:

a 
  text-decoration: none
  color: inherit
  font-family: sans-serif
  color: #323F4C


.text_arrow-btn
   display: flex
   align-items: center
   span
      margin-right: 16px
   svg
      transition: transform 0.3s
      width: 36px
      height: 14px
   path
      transition: stroke 0.3s
   &:hover
      svg
         transform: translateX(12px)
      span
         text-decoration: underline
   &:active
      color: #B6B5B5
      path
         stroke: #B6B5B5

Думаю что этим я глаза никому не открыл - вполне стандартная история.

Соседний комбинатор - "+"

Однако, на этом мы не останавливаемся. Теперь другая задача - стилизация чекбокса. Если вы хоть раз сталкивались с этой проблемой, то вы знаете лицо боли. Потому что убрать стандартные стили просто так не получится, получится только убрать чекбокс к чёртовой бабушке и стилизовать заново из div или span. Но чтобы добавить неинтерактивным элементам интерактивности придётся использовать JS. Или не придётся?..

Тут нам поможет волшебный + - это комбинатор родственных элементов. Он объединяет два элемента, находящихся на одном уровне, и второй должен следовать СРАЗУ за первым.

Звучит сложно - работает просто. Выбирается следующий сразу за элементом селектор. Вот так:

<label class="main-checkbox">
  <input type="checkbox">
  <span>
    <svg width="13" height="10" viewBox="0 0 13 10" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path d="M1 3.85714L5.30435 9L12 1" stroke="#323F4C"></path>
    </svg>
  </span>
</label>
.main-checkbox
   cursor: pointer
   span
      display: inline-block
      width: 24px
      height: 24px
      background: #F8F8F8
      display: flex
      align-items: center
      justify-content: center
      transition: background 0.3s
      svg
         width: 12px
         height: 9px
         opacity: 0
         transition: opacity 0.3s
   &:hover
      span
         background: #EBEBEB
   input
      display: none
      &:checked+span /*вот он*/
         background: #F8F8F8
         svg
            opacity: 1

Обращаем внимание на: &:checked+span тут "+" говорит нам о том, что будет выбран следующий за чекнутым input span. И вуаля - чекбокс работает как часы и он стилизован.

Родственный комбинатор - "~"

Но мы не останавливаемся. Имеем ещё одну задачу: чекбокс у которого внутри идёт span и svg одновременно и нужно при наведении изменить цвет и текста и svg. Да, можно обернуть элементы в div и использовать +, но фу, лишний тег - это полный отстой.

Тут нам поможет тильда ~ (не путать с тильтом). Этот символ не выражает усталость и безысходность - совсем наоборот. Он даёт нам выбрать теги, находящиеся на одном уровне с элементом.

Вот наш чекбокс с иконкой:

 <label class="radio-sort">
   <input type="checkbox">
   <span>По возрастанию цены</span>
   <svg width="11" height="14" viewBox="0 0 11 14" fill="none" xmlns="http://www.w3.org/2000/svg">
     <path d="M5.5 14V1M5.5 1L10 5.78947M5.5 1L1 5.78947" stroke="#323F4C" />
   </svg>
</label>

И вот стили:

.radio-sort
   font-family: sans-serif
   margin-right: 48px
   cursor: pointer
   display: flex
   align-items: center
   &:last-child
      margin-right: 0
   input
      display: none
   span
      display: inline-block
   svg
      width: 10px
      height: 14px
      display: inline-block
      margin-left: 12px
   input:checked + span
      font-weight: 800
   input:hover + span
      color: #1eaf9f
   input:hover ~ svg
      path
         stroke: #1eaf9f

тильда выберет следующий за span svg - очень удобно!

Итак, подведём итог.

Пробел - выберет все дочерние элементы, соответствующие селектору:

Знак больше > выберет только дочерние элементы, являющиеся прямыми потомками:

Знак + выберет следующего за элементом потомка:

Тильда ~ выберет всех одноуровневых потомков:

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Использовали ли вы раньше + или ~?
63.16% Да36
28.07% Нет, но буду16
8.77% Нет, мне это не нужно5
Проголосовали 57 пользователей. Воздержались 3 пользователя.
Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
0
Комментарии0

Публикации

Истории

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн