У меня есть несколько элементов с именем класса “red”, но я не могу выбрать первый элемент с class=“red” с помощью CSS-правила .home .red:first-child. Вот моя 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
- Решение 1: Использование :first-of-type
- Решение 2: Использование синтаксиса CSS4 :nth-child()
- Решение 3: Использование комбинатора родственных элементов
- Решение 4: Программное добавление класса
- Сравнение решений
- Лучшие практики и рекомендации
Понимание проблемы с :first-child
Псевдокласс :first-child представляет первый элемент среди группы родственных элементов, но он выбирает элемент ТОЛЬКО если:
- Это первый дочерний элемент своего родителя, И
- Он соответствует остальной части селектора
В вашей структуре 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 выбирает первый элемент определенного типа внутри его родителя, независимо от того, есть ли перед ним другие элементы.
.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(). Это самый прямой способ решить вашу проблему:
.home :nth-child(1 of .red) {
color: red;
/* другие стили */
}
Этот синтаксис означает "выбрать 1-й дочерний элемент, который соответствует селектору .red внутри .home. Это именно то, что вы пытаетесь сделать.
Поддержка браузерами: Этот синтаксис поддерживается в современных браузерах, включая Chrome 88+, Firefox 75+, Safari 14.1+ и Edge 88+.
Для старых браузеров, которые не поддерживают этот синтаксис, можно использовать комбинированный подход:
/* Для современных браузеров */
.home :nth-child(1 of .red) {
color: red;
}
/* Резервный вариант для старых браузеров */
.home .red:not(.home .red ~ .red) {
color: red;
}
Решение 3: Использование комбинатора родственных элементов
Вы можете использовать комбинатор родственных элементов (~), чтобы выбрать первый элемент с определенным классом, исключив все последующие родственные элементы с тем же классом:
.home .red:not(.home .red ~ .red) {
color: red;
/* другие стили */
}
Это работает потому, что:
.home .redвыбирает все элементы с классом “red” внутри “.home”.home .red ~ .redвыбирает все элементы с классом “red”, которые идут после первого:not()исключает эти последующие элементы- В результате остается только первый элемент с классом “red”
Хотя это работает, это может быть менее производительным, чем другие методы, и может быть сложнее для чтения и поддержки.
Решение 4: Программное добавление класса
Иногда самое простое решение - добавить определенный класс к первому элементу программно, либо через JavaScript, либо изменив ваш 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:
.home .first-red {
color: red;
/* другие стили */
}
Подход с JavaScript (если нельзя изменить HTML):
// Это выполнится при загрузке страницы
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) |
Отличная | Плохая | Средняя | Хорошая |
| Добавление класса | Отличная | Отличная | Отличная | Отличная |
Лучшие практики и рекомендации
-
Для современных проектов: Используйте
:nth-child(1 of .red)как наиболее семантически верное и читаемое решение. -
Для максимальной совместимости браузеров: Добавляйте класс программно к первому элементу с помощью JavaScript.
-
Для простых случаев: Используйте
:first-of-type, если вы работаете только с типами элементов и не требуется выбор по классу. -
Избегайте: Подхода с комбинатором родственных элементов (
~) из-за проблем с производительностью и плохой читаемостью. -
Учитывайте доступность: При стилизации первого элемента по-разному убедитесь, что вы не нарушаете визуальный поток и не создаете проблем с доступностью.
-
Тщательно тестируйте: Разные решения могут работать лучше в разных контекстах, поэтому тестируйте выбранный подход с вашей конкретной HTML-структурой.
Ключевой вывод - понимание того, что :first-child работает не так, как многие разработчики интуитивно ожидают - он не выбирает первый элемент, соответствующий условиям вашего селектора, а выбирает первый дочерний элемент, только если он случайно соответствует условиям вашего селектора.
Источники
- MDN Web Docs - псевдокласс :first-child
- MDN Web Docs - псевдокласс :first-of-type
- Stack Overflow - CSS-селектор для первого элемента с классом
- Руководство BrowserStack - CSS First Item Selector
- CSS-Tricks - :first-of-type
- 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-селекторов.