НейроАгент

Селектор CSS :first-child не работает? Исправьте здесь

Узнайте, почему селектор CSS :first-child не может выбрать первые элементы с определенными классами и обнаружьте несколько решений, включая :nth-child(1 of .red), :first-of-type и подходы с использованием JavaScript. Исправьте ваши CSS-селекторы сегодня!

Вопрос

У меня есть несколько элементов с именем класса “red”, но я не могу выбрать первый элемент с class=“red” с помощью CSS-правила .home .red:first-child. Вот моя HTML-структура:

html
<div class="home">
    <span>blah</span>
    <p class="red">first</p>
    <p class="red">second</p>
    <p class="red">third</p>
    <p class="red">fourth</p>
</div>

Что не так с моим CSS-селектором и как мне его изменить, чтобы целенаправленно выбрать первый дочерний элемент с классом “red”?

НейроАгент

Проблема с вашим CSS-селектором .home .red:first-child заключается в том, что :first-child не выбирает первый элемент с классом “red” - он выбирает первый дочерний элемент родителя, только если этот элемент также имеет класс “red”. В вашем HTML первым дочерним элементом является <span>blah</span>, у которого нет класса “red”, поэтому селектор ничего не находит.

Чтобы целенаправленно выбрать первый элемент с class=“red”, вам нужно использовать другие CSS-псевдоклассы, которые соответствуют вашему желаемому поведению.


Содержание


Понимание проблемы с :first-child

Псевдокласс :first-child представляет первый элемент среди группы родственных элементов, но он выбирает элемент ТОЛЬКО если:

  1. Это первый дочерний элемент своего родителя, И
  2. Он соответствует остальной части селектора

В вашей структуре HTML:

html
<div class="home">
    <span>blah</span>          <!-- Это первый дочерний элемент -->
    <p class="red">first</p>   <!-- Это первый элемент с классом "red" -->
    <p class="red">second</p>
    <p class="red">third</p>
    <p class="red">fourth</p>
</div>

Селектор .home .red:first-child не работает, потому что первый дочерний элемент <span> не имеет класса “red”, поэтому условие не выполняется.

Ключевое замечание: Согласно Mozilla Developer Network, “:first-child выбирает первый элемент среди группы родственных элементов”, но только если он соответствует условиям селектора.


Решение 1: Использование :first-of-type

Псевдокласс :first-of-type выбирает первый элемент определенного типа внутри его родителя, независимо от того, есть ли перед ним другие элементы.

css
.home .red:first-of-type {
    color: red;
    /* другие стили */
}

Это работает, потому что :first-of-type ищет первый элемент <p> внутри .home, который также имеет класс “red”. Поскольку первый элемент <p> в вашей структуре имеет класс “red”, этот селектор его выберет.

Однако имейте в виду, что у :first-of-type есть ограничения - он основан на типе элемента (имени тега), а не на классе. Если у вас есть другие элементы <p> без класса “red” перед вашим первым “red” <p>, это не сработает как ожидается.


Решение 2: Использование синтаксиса CSS4 :nth-child()

Уровень 4 селекторов CSS ввел поддержку использования селекторов внутри :nth-child(). Это самый прямой способ решить вашу проблему:

css
.home :nth-child(1 of .red) {
    color: red;
    /* другие стили */
}

Этот синтаксис означает "выбрать 1-й дочерний элемент, который соответствует селектору .red внутри .home. Это именно то, что вы пытаетесь сделать.

Поддержка браузерами: Этот синтаксис поддерживается в современных браузерах, включая Chrome 88+, Firefox 75+, Safari 14.1+ и Edge 88+.

Для старых браузеров, которые не поддерживают этот синтаксис, можно использовать комбинированный подход:

css
/* Для современных браузеров */
.home :nth-child(1 of .red) {
    color: red;
}

/* Резервный вариант для старых браузеров */
.home .red:not(.home .red ~ .red) {
    color: red;
}

Решение 3: Использование комбинатора родственных элементов

Вы можете использовать комбинатор родственных элементов (~), чтобы выбрать первый элемент с определенным классом, исключив все последующие родственные элементы с тем же классом:

css
.home .red:not(.home .red ~ .red) {
    color: red;
    /* другие стили */
}

Это работает потому, что:

  • .home .red выбирает все элементы с классом “red” внутри “.home”
  • .home .red ~ .red выбирает все элементы с классом “red”, которые идут после первого
  • :not() исключает эти последующие элементы
  • В результате остается только первый элемент с классом “red”

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


Решение 4: Программное добавление класса

Иногда самое простое решение - добавить определенный класс к первому элементу программно, либо через JavaScript, либо изменив ваш HTML:

Модификация HTML:

html
<div class="home">
    <span>blah</span>
    <p class="red first-red">first</p>
    <p class="red">second</p>
    <p class="red">third</p>
    <p class="red">fourth</p>
</div>

CSS:

css
.home .first-red {
    color: red;
    /* другие стили */
}

Подход с JavaScript (если нельзя изменить HTML):

javascript
// Это выполнится при загрузке страницы
document.addEventListener('DOMContentLoaded', function() {
    const firstRed = document.querySelector('.home .red');
    if (firstRed) {
        firstRed.classList.add('first-red');
    }
});

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


Сравнение решений

Решение Поддержка браузерами Производительность Читаемость Гибкость
.red:first-of-type Отличная Хорошая Хорошая Ограниченная (основана на типе)
:nth-child(1 of .red) Хорошая (современные браузеры) Отличная Отличная Отличная
.red:not(.red ~ .red) Отличная Плохая Средняя Хорошая
Добавление класса Отличная Отличная Отличная Отличная

Лучшие практики и рекомендации

  1. Для современных проектов: Используйте :nth-child(1 of .red) как наиболее семантически верное и читаемое решение.

  2. Для максимальной совместимости браузеров: Добавляйте класс программно к первому элементу с помощью JavaScript.

  3. Для простых случаев: Используйте :first-of-type, если вы работаете только с типами элементов и не требуется выбор по классу.

  4. Избегайте: Подхода с комбинатором родственных элементов (~) из-за проблем с производительностью и плохой читаемостью.

  5. Учитывайте доступность: При стилизации первого элемента по-разному убедитесь, что вы не нарушаете визуальный поток и не создаете проблем с доступностью.

  6. Тщательно тестируйте: Разные решения могут работать лучше в разных контекстах, поэтому тестируйте выбранный подход с вашей конкретной HTML-структурой.

Ключевой вывод - понимание того, что :first-child работает не так, как многие разработчики интуитивно ожидают - он не выбирает первый элемент, соответствующий условиям вашего селектора, а выбирает первый дочерний элемент, только если он случайно соответствует условиям вашего селектора.


Источники

  1. MDN Web Docs - псевдокласс :first-child
  2. MDN Web Docs - псевдокласс :first-of-type
  3. Stack Overflow - CSS-селектор для первого элемента с классом
  4. Руководство BrowserStack - CSS First Item Selector
  5. CSS-Tricks - :first-of-type
  6. Weekend Projects - CSS :first-child не работает правильно

Заключение

Селектор .home .red:first-child не работает, потому что :first-child соответствует элементам только если они являются одновременно первым дочерним элементом своего родителя И соответствуют остальной части селектора. В вашем случае первым дочерним элементом является <span> без класса “red”.

Чтобы целенаправленно выбрать первый элемент с class=“red”, у вас есть несколько эффективных вариантов:

  • Используйте :nth-child(1 of .red) для самого прямого и читаемого решения
  • Добавляйте класс программно для максимального контроля и совместимости
  • Используйте :first-of-type, если вы работаете с типами элементов, а не с классами
  • Избегайте сложных комбинаций селекторов, которые снижают производительность

Понимание того, как работают CSS-псевдоклассы - а именно, что они оценивают элемент по условиям селектора, а не фильтруют элементы и затем применяют псевдоклассы - является ключевым для написания эффективных CSS-селекторов.