NTH-CHILD – селекторы

Вступление.

CSS это не язык программирования, но очень мощный инструмент. Причём чем больше «примочек» у этого инструмента, тем сильнее и гибче он становится. Некоторые «примочки» встречаются не так часто, но без них вёрстка становится сложнее. Про некоторые из них я уже говорил, селекторы по атрибутам, дочерние, соседские, братские, родительские...

Но что если необходимо выбрать первый или последний элемент в блоке? При этом он может меняться? А если нужно выбрать каждый второй или третий? При помощи JavaScript его найти? Вот тут и начинается магия CSS.

видео

NTH-CHILD – селекторы

Первый и последний элементы.

Первые селекторы, о которых я расскажу, это псевдоклассы :first-child и :last-child. Что они делают? Выбирают первый и последний элемент в блоке, который соответствуют селектору. То есть элемент должен соответствовать селектору и быть первым в родительском блоке.

Допустим, у нас есть блок с набором простого текста заключённого в теге <p>. Первому параграфу нужно сбросить верхний отступ, второму нижний.

HTML

<div class="container">
  <p>Съешь ещё этих мягких французских булок, да выпей [же] чаю. 1234567890.</p>
  <p>Завершён ежегодный съезд эрудированных школьников, мечтающих глубоко проникнуть в тайны физических явлений и химических
  реакций.</p>
  <p>Всё ускоряющаяся эволюция компьютерных технологий предъявила жёсткие требования к производителям как собственно
  вычислительной техники, так и периферийных устройств.</p>
  <p>Официально заявляю читающим: даёшь подъем операции Ы! Хуже с ёлкой бог экспериментирует.</p>
</div>

С помощью этих псевдоклассов можно сбросить ненужные отступы.

CSS

p:first-child {
  margin-top: 0;
}

p:last-child {
  margin-bottom: 0;
}
Четыре параграфа с текстом, первый и последний подсвечены
у первого параграфа видно что есть только нижний отступ, у последнего есть только верхний отступ.

Есть ещё два похожих псевдокласса :first-of-type и :last-of-type. Эти псевдоклассы работают похожим образом, но есть различия. К примеру, если перед элементом <p> поставить любой другой, то псевдокласс :first-child не будет работать.

HTML

<div class="container">
  <h1>Панграммы</h1>
  <style>
    p:first-child {
      color: tomato;
    }
  </style>
  <p>Эх, жирафы честно в цель шагают, да щук объять за память ёлкой...</p>
  <p>Расчешись! Объявляю: туфли у камина, где этот хищный ёж цаплю задел.</p>
</div>
Скриншот браузера, сверху заголовок, ниже два параграфа, открыт девтулз
:last-of-type не применил стили к первому параграфу.

При этом псевдокласс :first-of-type справится с этой задачей:

HTML

<div class="container">
  <h1>Панграммы</h1>
  <style>
    p:first-of-type {
      color: tomato;
    }
  </style>
  <p>Эх, жирафы честно в цель шагают, да щук объять за память ёлкой...</p>
  <p>Расчешись! Объявляю: туфли у камина, где этот хищный ёж цаплю задел.</p>
</div>
Скриншот браузера, сверху заголовок, ниже два параграфа, открыт девтулз
С псевдоклассом :first-of-type параграф выбран и стили к нему применились.

Отличие селектора :first-of-type от :first-child в том, что он выбирает первый элемент, соответствующий селектору. При этом перед ним может быть любой другой элемент. Точно такая же разница между псевдоклассами :last-child и last-of-type.

Выбираем элементы по формуле.

Иногда можно встретить большие таблицы на сайте. Когда в таких таблицах много данных, читать их становится сложно. Дизайнеры могут сделать эту таблицу «полосатой». С одной стороны можно добавить различные классы поочерёдно строкам. А если динамически добавятся элементы? При этом в начало таблицы? Как поменять классы и не запутаться? Согласитесь что это не очень удобно?

Придумаем небольшую таблицу:

HTML

<table>
  <caption>
    Front-end web developer course 2021
  </caption>
  <tr>
    <th>Person</th>
    <th>Most interest in</th>
    <th>Age</th>
  </tr>
  <tr>
    <th>Chris</th>
    <td>HTML tables</td>
    <td>22</td>
  </tr>
  <tr>
    <th>Dennis</th>
    <td>Web accessibility</td>
    <td>45</td>
  </tr>
  <tr>
    <th>Sarah</th>
    <td>JavaScript frameworks</td>
    <td>29</td>
  </tr>
  <tr>
    <th>Karen</th>
    <td>Web performance</td>
    <td>36</td>
  </tr>
  <tr>
    <th colspan="2">Average age</th>
    <td>33</td>
  </tr>
</table>

CSS

th,
td {
  padding: 5px;
  border: 1px solid tomato;
}
th,
td {
  padding: 5px 15px;
  text-align: left;
}

[colspan="2"] {
  text-align: center;
}

Что бы «сделать зебру», достаточно применить псевдокласс :nth-child(). Это не просто псевдокласс, это функция, внутри которой можно рассчитать какие элементы нужно выбирать. К примеру, выбрать каждый второй можно с помощью вот такого псевдокласса :nth-child(2n), каждый третий с помощью :nth-child(3n). Кроме того эта функция может принимать и ключевые слова: even чётные и odd не чётные элементы.

Ну и для того, что бы окрасить поочерёдно строки в таблице достаточно применить такое правило:

CSS

tr:nth-child(odd) {
  background-color: rgba(255, 99, 71, 0.3);
}
Таблица
У таблицы строки поочерёдно окрашены.

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

Немного примеров.

Как я написал выше, :nth-child() это функция. А значит может выбирать не только каждый второй, третий, четвёртый... элементы, но и по интересным формулам. Ниже несколько примеров, а результаты работы это не скриншоты.

Первые пять элементов:nth-child(-n+5)
Начиная с пятого элемента:nth-child(n+5)
Каждый второй начиная с пятого элемента:nth-child(2n+5)
Чётные кроме скрытых:nth-child(even of :not(.hidden))

В последнем примере псевдокласс :nth-child() содержит в себе конструкцию of S, это фильтр. Только S это какой-то селектор. В моём случае этот селектор :not(.hidden) исключает элементы с классом .hidden.

Подобным образом работает :nth-last-child(), но только отсчёт начнётся уже не с первого, а с последнего элемента в блоке.

Специфичность.

При написании кода важно обращать внимание на специфичность селекторов. Специфичность псевдоклассов о которых я рассказал такая же, как и у классов. То есть tr.my_class == tr:nth-*.

Итоги

Про эти псевдоклассы можно рассказывать много и долго, так как есть другие похожие. Все они работают похожим образом, и с похожими различиями. Таким образом :first-child и :first-of-type имеют такую же разницу как :nth-child() :nth-of-type().

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

Объявление

Нравится фронтенд — попробуйте самые подробные интерактивные тренажёры от HTML Academy бесплатно. Подойдут и действующим разработчикам, чтобы подтянуть навыки вёрстки.