Как получить соседние элементы без jQuery

В jQuery есть метод siblings(), который позволяет получить соседние элементы. В этой статье посмотрим, как добиться того же результата на чистом JavaScript.

Имея доступ до соседних элементов, можно получить довольно интересные эффекты

Посмотреть результат в живую можно на Codepen

Создаём структуру

Если вы подписаны на telegram-канал блога, то этот пример будет уже знаком. Если не подписаны, то присоединяйтесь

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Practice</title>
    <link rel="stylesheet" href="css/bootstrap-reboot.min.css"/>
    <link rel="preconnect" href="https://fonts.gstatic.com"/>
    <link href="https://fonts.googleapis.com/css2?family=Lora:wght@700&amp;family=Roboto:wght@300;400&amp;display=swap" rel="stylesheet"/>
    <link rel="stylesheet" href="css/main.css"/>
  </head>
  <body>
    <section class="cards">
      <div class="container">
        <div class="cards__grid">
          <div class="cards__card card">
            <div class="card__image"><img src="img/image1.jpg" alt=""/></div>
            <div class="card__body">
              <div class="card__category">Fruits</div>
              <div class="card__grow">
                <div class="card__title"><a href="">Red Dragonfruit</a></div>
                <div class="card__text">These fruits are commonly known in English as "dragon fruit", a name used since around 1963, apparently resulting from the leather-like skin and prominent scaly spikes on the fruit exterior. English as "dragon fruit", a name used since around 1963.</div>
              </div>
              <div class="card__bottom">
                <div class="card__author card-author">
                  <div class="card-author__avatar"><img src="img/avatar1.png" alt=""/></div>
                  <div class="card-author__name">Anny</div>
                </div>
                <div class="card__time card-time">
                  <div class="card-time__icon">
                    <svg class="icon">
                      <use xlink:href="#time"></use>
                    </svg>
                  </div>
                  <div class="card-time__value">5 min read</div>
                </div>
              </div>
            </div>
          </div>
          <div class="cards__card card card_accent">
            <div class="card__image"><img src="img/image2.jpg" alt=""/></div>
            <div class="card__body">
              <div class="card__category">Fruits</div>
              <div class="card__grow">
                <div class="card__title"><a href="">Violet Fruit</a></div>
                <div class="card__text">These fruits are commonly known in English as "dragon fruit", a name used since around 1963, apparently resulting</div>
              </div>
              <div class="card__bottom">
                <div class="card__author card-author">
                  <div class="card-author__avatar"><img src="img/avatar2.png" alt=""/></div>
                  <div class="card-author__name">Den</div>
                </div>
                <div class="card__time card-time">
                  <div class="card-time__icon">
                    <svg class="icon">
                      <use xlink:href="#time"></use>
                    </svg>
                  </div>
                  <div class="card-time__value">3 min read</div>
                </div>
              </div>
            </div>
          </div>
          <div class="cards__card card">
            <div class="card__image"><img src="img/image3.jpg" alt=""/></div>
            <div class="card__body">
              <div class="card__category">Fruits</div>
              <div class="card__grow">
                <div class="card__title"><a href="">Very loooong orange title in two lines</a></div>
                <div class="card__text">These fruits are commonly known in English as "dragon fruit", a name used since around 1963, apparently resulting from the leather-like skin and prominent scaly spikes on the fruit exterior.</div>
              </div>
              <div class="card__bottom">
                <div class="card__author card-author">
                  <div class="card-author__avatar"><img src="img/avatar3.png" alt=""/></div>
                  <div class="card-author__name">Peter</div>
                </div>
                <div class="card__time card-time">
                  <div class="card-time__icon">
                    <svg class="icon">
                      <use xlink:href="#time"></use>
                    </svg>
                  </div>
                  <div class="card-time__value">11 min read</div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
    <svg class="hidden" width="0" height="0">
      <symbol id="time" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
        <path d="M9.992 1.667c-4.6 0-8.325 3.733-8.325 8.333s3.725 8.333 8.325 8.333c4.608 0 8.341-3.733 8.341-8.333S14.6 1.667 9.992 1.667zm.008 15A6.665 6.665 0 013.333 10 6.665 6.665 0 0110 3.333 6.665 6.665 0 0116.667 10 6.665 6.665 0 0110 16.667z"></path>
        <path d="M10.417 5.833h-1.25v5l4.375 2.625.625-1.025-3.75-2.225V5.833z"></path>
      </symbol>
    </svg>
    <script src="js/main.js"></script>
  </body>
</html>


Добавим стилей

Стилизуем структуру, используя БЭМ, CSS-переменные, CSS Grid Layout, SVG Sprite, Flexbox и так далее

body {
  font-family: 'Roboto', sans-serif;
}
.container {
  max-width: 1120px;
  padding: 0 32px;
  margin: 0 auto;
}
.cards {
  padding: 96px 0;
  background: #484c56;
}
.cards__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  grid-gap: 64px 32px;
  gap: 64px 32px;
}
.card {
  --dark-gray: #484c56;
  --light-gray: #9ca9b9;
  --orange: #cc5a53;
  --white: #f6f5f5;
  display: flex;
  flex-direction: column;
  align-items: center;
  border-radius: 8px;
  background: var(--white);
  transition: 0.24s;
}
.card:hover {
  transform: scale(1.04);
}
.card_sibling {
  transform: scale(0.96);
  opacity: 0.8;
  -webkit-filter: grayscale(64%);
  filter: grayscale(64%);
}
.card__image {
  width: calc(100% - 32px);
  border-radius: 8px;
  overflow: hidden;
  margin-top: -32px;
  box-shadow: 0 8px 16px rgba(0,0,0,0.5);
  height: 220px;
}
.card__image img {
  display: block;
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
  object-fit: cover;
}
.card__body {
  flex: 1;
  padding: 24px;
  display: flex;
  flex-direction: column;
}
.card__category {
  font-size: 12px;
  line-height: 1.333333333333333;
  text-transform: uppercase;
  margin-bottom: 12px;
  color: var(--orange);
}
.card__grow {
  flex: 1;
  margin-bottom: 32px;
}
.card__title {
  line-height: 1.333333333333333;
  margin-bottom: 12px;
}
.card__title a {
  font-weight: 700;
  font-size: 18px;
  text-decoration: none;
  color: var(--dark-gray);
  font-family: 'Lora', serif;
  transition: 0.24s;
}
.card__title a:hover {
  color: var(--orange);
}
.card__text {
  font-size: 14px;
  line-height: 1.428571428571429;
  font-weight: 300;
  color: var(--dark-gray);
}
.card__bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.card-author {
  display: flex;
  align-items: center;
}
.card-author__avatar {
  margin-right: 8px;
  height: 32px;
  width: 32px;
  border-radius: 50%;
  overflow: hidden;
}
.card-author__avatar img {
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
  object-fit: cover;
  display: block;
}
.card-author__name {
  font-size: 14px;
  color: var(--light-gray);
}
.card-time {
  display: flex;
  align-items: center;
  font-size: 14px;
  line-height: 1.428571428571429;
  color: var(--light-gray);
}
.card-time__icon {
  margin-right: 8px;
}
.card-time__icon svg.icon {
  width: 20px;
  height: 20px;
  fill: var(--light-gray);
}
.card_accent {
  --dark-gray: #f6f5f5;
  --light-gray: #f6f5f5;
  --orange: #f6f5f5;
  --white: #cc5a53;
}
.hidden {
  display: none;
}


Пишем логику на JavaScript

За поиск соседних элементов будет отвечать функция всего лишь в одну строку

const siblings = el => [].slice.call(el.parentNode.children).filter(child => (child !== el));


Теперь посмотрим, как применить эту функцию на практике

document.addEventListener('DOMContentLoaded', () => {

  const siblings = el => [].slice.call(el.parentNode.children).filter(child => (child !== el)); // объявляем функцию, которая будет возвращать соседние элементы

  const cards = document.querySelectorAll('.card') // получаем все карточки

  cards.forEach(card => { // для каждой карточки
    card.addEventListener('mouseenter', () => { // при наведении на карточку
      siblings(card).forEach(el => { // для каждого соседнего элемента
        el.classList.add('card_sibling') // добавляем активный класс, который визуально ставит соседние карточки на задний план
      })
    })
    card.addEventListener('mouseleave', () => { // если убираем курсор с карточки
      siblings(card).forEach(el => { // для каждого соседнего элемента
        el.classList.remove('card_sibling') // удаляем активный класс
      })
    })
  })

})

Посмотреть результат в живую можно на Codepen




Итоги

Теперь, чтобы получить соседние элементы на чистом JavaScript, вы знаете как это сделать ;)

Буду рад, если статья оказалась полезной

Спасибо за ваше внимание и уделённое время!