Как выбрать исключительно первые три элемента (ребёнка) у родительского элемента?
Задача состоит в том, чтобы выбрать исключительно первые три элемента у родителя, конечно же можно написать так: div > :nth-child(1), div > :nth-child(2), div > :nth-child(3), но мы ведь не ищем лёгких путей, так? (Мой ответ ищите ниже, в секции ответов)
Условия:
- Нужно сделать так, чтобы первые три элемента у родителя имели красный задний фон
- Никакого JavaScript, только CSS, только хардкор (тестирование селекторов разрешено, но получение элементов с помощью JavaScript нет)
- Не нарушаем принципы DRY (Конкретней, не нарушать их в CSS селекторах)
- Ответ обязан быть универсальным и должен работать не только на этом примере, но и на тех пример, где элементов может быть в разы больше.
Вот пример кода для ваших ответов:
div > YOUR_SELECTOR {
background-color: red;
}
<div>
<p>Этот элемент должен иметь красный задний фон</p>
<p>Этот элемент должен иметь красный задний фон</p>
<p>Этот элемент должен иметь красный задний фон</p>
<p>У этого элемента не должно быть красного заднего фона</p>
<p>У этого элемента не должно быть красного заднего фона</p>
<p>У этого элемента не должно быть красного заднего фона</p>
<p>У этого элемента не должно быть красного заднего фона</p>
<p>У этого элемента не должно быть красного заднего фона</p>
</div>
Ответы (1 шт):
Решения
Все элементы до третьего:
div > :nth-child(-1n+3)
Все элементы которые НЕ 4-ые и выше:
div > :not(:nth-child(n+4))
Также, у наших коллег на Хабре есть решение задачи, но какое-то странное:
div > :nth-child(-1n+3):nth-child(-n+8)
И ещё один ответ, чисто технически он не нарушает никакой из условий, но его применение довольно нежелательно, возможны серьёзные проблемы с совместимостью:
div > :where(:nth-child(1), :nth-child(2), :nth-child(3))
Тестирование
Проведём также тесты всех селекторов на работоспособность, будем проверять по 1000 раз со случайным кол-во'м элементов (минимум 3, максимум 1000). Для примера также добавил неправильный селектор.
let selectors = ['div > :nth-child(-1n+3)', 'div > :not(:nth-child(n+4))', 'div > :nth-child(-1n+3):nth-child(-n+8)', 'div > :where(:nth-child(1), :nth-child(2), :nth-child(3))', 'div > *']
function test(selector) {
for (let i = 0; i < 1000; i++) {
let elementsAmount = Math.floor(Math.random() * 1000) + 3
let parent = document.createElement('div')
for (let j = 0; j < elementsAmount; j++) {
let element = document.createElement('p')
element.dataset.isCorrect = j < 3 ? 1 : 0
parent.appendChild(element)
}
try {
let queried = parent.querySelectorAll(selector)
if (queried.length < 4) {
return true
}
return false
} catch(_) {
return false
}
}
}
function log(selector) {
console.log(selector, '\nPASSED?', test(selector))
}
for (let i = 0; i < selectors.length; i++) {
let selector = selectors[i]
log(selector)
}
P.S. Я знаю что в одном случае из 997 последний "неправильный" вариант сработает.