CSS селектор для первого элемента с классом

947

У меня есть набор элементов с именем класса red, но я не могу выбрать первый элемент с class="red"использованием следующего правила CSS:

.red:first-child {
    border: 5px solid red;
}
<p class="red"></p>
<div class="red"></div>

Что не так в этом селекторе и как мне его исправить?

Благодаря комментариям я понял, что элемент должен быть первым потомком своего родителя, чтобы быть выбранным, что не так, как у меня. У меня есть следующая структура, и это правило не выполняется, как указано в комментариях:

.home .red:first-child {
    border: 1px solid red;
}
<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>

Как я могу нацелиться на первого ребенка в классе red?

Раджу
источник
для тех, кто запутался из-за различных типов элементов в моем примере (p, div), их создание также не работает, и проблема все еще существует.
Раджат
4
Я думаю, именно так должен был работать селектор «первый ребенок» ...
Феликс Ив
28
: первый ребенок не был бы очень хорошим именем тогда. Если бы у тебя был сын, а потом и дочь, ты бы не назвал свою дочь своим первенцем. Точно так же первый .home> .red не является первым потомком .home, поэтому было бы неуместно называть его таковым.
BoltClock
Нет, именно так и должен был работать
Эван Томпсон,
@EvanThompson Вот как :first-of-type это работает.
TylerH

Ответы:

1427

Это один из самых известных примеров недопонимания авторами того, как :first-childработает. Представленный в CSS2 , :first-childпсевдокласс представляет самого первого потомка своего родителя . Вот и все. Существует очень распространенное заблуждение, что он выбирает тот дочерний элемент, который первым соответствует условиям, заданным остальной частью составного селектора. Из - за способа селекторов работы (см здесь для объяснения), что просто не соответствует действительности.

Селектор 3-го уровня представляет :first-of-typeпсевдокласс , который представляет первый элемент среди братьев и сестер своего типа. Этот ответ с иллюстрациями объясняет разницу между :first-childи :first-of-type. Однако, как и в случае :first-child, он не смотрит на какие-либо другие условия или атрибуты. В HTML тип элемента представлен именем тега. В вопросе этот тип есть p.

К сожалению, не существует аналогичного :first-of-classпсевдокласса для сопоставления первого дочернего элемента данного класса. Один из обходных путей, который мы с Леа Вероу придумали для этого (хотя и совершенно независимо), заключается в том, чтобы сначала применить желаемые стили ко всем элементам этого класса:

/* 
 * Select all .red children of .home, including the first one,
 * and give them a border.
 */
.home > .red {
    border: 1px solid red;
}

... затем "отменим" стили для элементов с классом, которые идут после первого , используя общий братский комбинатор~ в главном правиле:

/* 
 * Select all but the first .red child of .home,
 * and remove the border from the previous rule.
 */
.home > .red ~ .red {
    border: none;
}

Теперь только первый элемент с class="red"будет иметь границу.

Вот иллюстрация того, как применяются правила:

<div class="home">
  <span>blah</span>         <!-- [1] -->
  <p class="red">first</p>  <!-- [2] -->
  <p class="red">second</p> <!-- [3] -->
  <p class="red">third</p>  <!-- [3] -->
  <p class="red">fourth</p> <!-- [3] -->
</div>
  1. Правила не применяются; Граница не отображается
    Этот элемент не имеет класса red, поэтому он пропущен.

  2. Применяется только первое правило; красная граница отображается.
    Этот элемент имеет класс red, но ему не предшествуют элементы с классом redв родительском элементе . Таким образом, второе правило не применяется, только первое, и элемент сохраняет свою границу.

  3. Оба правила применяются; Граница не отображается
    Этот элемент имеет класс red. Ему также предшествует хотя бы еще один элемент класса red. Таким образом, оба правила применяются, и второе borderобъявление отменяет первое, тем самым «отменяя» его, так сказать.

В качестве бонуса, хотя она была введена в селекторов 3, общий родственный комбинатор на самом деле очень хорошо поддерживается IE7 и выше, в отличие :first-of-typeи :nth-of-type()которые поддерживаются только IE9 вперед. Если вам нужна хорошая поддержка браузера, вам повезло.

Фактически, тот факт, что родственный комбинатор является единственным важным компонентом в этой технике, и он имеет такую ​​удивительную поддержку браузера, делает эту технику очень универсальной - вы можете адаптировать ее для фильтрации элементов другими вещами, кроме селекторов классов:

  • Вы можете использовать это для обхода :first-of-typeв IE7 и IE8, просто предоставив селектор типа вместо селектора класса (опять же, больше о его неправильном использовании здесь в следующем разделе):

    article > p {
        /* Apply styles to article > p:first-of-type, which may or may not be :first-child */
    }
    
    article > p ~ p {
        /* Undo the above styles for every subsequent article > p */
    }
  • Вы можете фильтровать по селекторам атрибутов или любым другим простым селекторам вместо классов.

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

Обратите внимание, что для того, чтобы это работало, вам нужно заранее знать, какими будут стили по умолчанию для других элементов вашего брата, чтобы вы могли переопределить первое правило. Кроме того, так как это включает в себя переопределение правил в CSS, вы не можете добиться того же с помощью одного селектора для использования с API селекторов или CSS-локаторами Selenium .

Стоит отметить, что в Selectors 4 введено расширение для :nth-child()обозначения (изначально это был совершенно новый псевдокласс :nth-match()), которое позволит вам использовать что-то вроде :nth-child(1 of .red)гипотетического .red:first-of-class. Это сравнительно недавнее предложение, поэтому недостаточно совместимых реализаций, чтобы его можно было использовать на производственных площадках. Надеюсь, это скоро изменится. В то же время предложенный мной обходной путь должен работать в большинстве случаев.

Имейте в виду, что этот ответ предполагает, что вопрос ищет каждый первый дочерний элемент, который имеет данный класс. Не существует ни псевдокласса, ни даже общего CSS-решения для n-го совпадения сложного селектора по всему документу - вопрос о том, существует ли решение, сильно зависит от структуры документа. JQuery предоставляет :eq(), :first, :lastи многое другое для этой цели, но еще раз отметить , что они работают очень по- разному с :nth-child()соавт . Используя API селекторов, вы можете использовать document.querySelector()для получения самого первого соответствия:

var first = document.querySelector('.home > .red');

Или используйте document.querySelectorAll()с индексатором, чтобы выбрать любое конкретное совпадение:

var redElements = document.querySelectorAll('.home > .red');
var first = redElements[0];
var second = redElements[1];
// etc

Хотя .red:nth-of-type(1)решение в первоначальном принятом ответе Филиппа Добмайера работает (которое изначально было написано Мартином, но с тех пор удалено), оно не ведет себя так, как вы ожидаете.

Например, если вы хотите выбрать только pисходную разметку:

<p class="red"></p>
<div class="red"></div>

... тогда вы не можете использовать .red:first-of-type(эквивалентно .red:nth-of-type(1)), потому что каждый элемент является первым (и единственным) одним из его типов ( pи divсоответственно), поэтому селектор будет сопоставлять оба элемента .

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

<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>

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

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

... селектор немедленно потерпит неудачу, потому что первый .redэлемент теперь является вторым p элементом.

BoltClock
источник
15
Так есть ли способ подражать :last-of-class? Выберите последний элемент класса.
Ракета Хазмат
1
@Rocket: Не то, чтобы я мог видеть :(
BoltClock
4
Хорошая техника с родным братом. Возможно, стоит отметить, что это работает и с несколькими одноуровневыми комбинаторами, например, p ~ p ~ p выберет третий элемент и далее: jsfiddle.net/zpnnvedm/1
Legolas
2
@BoltClock Да, извините, я пришел сюда для решения, и меня не особо волновало конкретное дело ОП. Я на самом деле не могу понять, почему general sibling selector ~работает как a :not(:first-of-*)для определенного типа, я предполагаю, что оно должно применять правило для каждого соответствующего элемента, но оно применяется только для первого соответствия, даже когда есть 3 или более возможных совпадений.
Джерард Речес
2
По caniuse на :nth-child(1 of .foo)расширение уже был реализован на Safari 9.1+. (Я не проверял, хотя)
Данилд
330

:first-childСелектор предназначен, как говорит название, чтобы выбрать первый ребенок родительского тега. Дочерние элементы должны быть встроены в один родительский тег. Ваш точный пример будет работать (только что попробовал здесь ):

<body>
    <p class="red">first</p>
    <div class="red">second</div>
</body>

Может быть, вы вложили свои теги в разные родительские теги? Ваши теги класса redдействительно первые теги под родителем?

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

<div>
    <p class="red">first</p>
    <div class="red">second</div>
</div>
<div>
    <p class="red">third</p>
    <div class="red">fourth</div>
</div>

firstи thirdбудет красным тогда.

Обновить:

Я не знаю, почему Мартин удалил свой ответ, но у него было решение, :nth-of-typeселектор:

.red:nth-of-type(1)
{
    border:5px solid red;
} 
<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 3, поэтому не все браузеры распознают его (например, IE8 или старше).

Филипп Добмайер
источник
Возможно, это была моя вина - как я указывал Мартыну, что селектор CSS3, как и у него, :nth-of-typeсталкивается с небольшой проблемой - он вообще не работает ни в одной текущей версии IE.
Мар Эрлигссон,
25
Я немного запутался, читая это. Строго .red:nth-of-type(1)выберет любой элемент, который (а) является первым потомком своего типа элемента, а (б) имеет класс «красный». Так что, если в примере первый <p> не имеет класса «красный», он не будет выбран. В качестве альтернативы, если <span> и первый <p> оба имеют класс «красный», они оба будут выбраны. jsfiddle.net/fvAxn
Дэвид
7
@Dan Mundy: :first-of-typeэквивалентно :nth-of-type(1), так что, конечно, это тоже работает. Он также может потерпеть неудачу также, по той же причине, которая указана в моем ответе.
BoltClock
4
@ Давид, я уверен, :nth-of-typeозначает «элемент / тег», когда он говорит «тип». Таким образом, он рассматривает только элемент, а не такие вещи, как классы.
gcampbell
2
@gcampbell: Да, это именно то, что это значит, и именно поэтому этот ответ ошибочен. Причина, по которой слово «тип» было выбрано, заключается в том, чтобы не связывать селекторы с HTML / XML, поскольку не все языки имеют понятие «теги», которые определяют элементы.
BoltClock
74

Правильный ответ:

.red:first-child, :not(.red) + .red { border:5px solid red }

Часть I: Если элемент является первым по отношению к своему родителю и имеет класс «красный», он получает границу.
Часть II: Если элемент «.red» не является первым по отношению к своему родительскому элементу, но сразу же следует за элементом без класса «.red», он также должен заслужить честь упомянутой границы.

Скрипка или этого не случилось.

Ответ Филиппа Добмайера, хотя и принят, неверен - см. Прилагаемую скрипку.
Ответ BoltClock будет работать, но излишне определяет и перезаписывает стили
(особенно проблема, когда в противном случае он наследовал бы другую границу - вы не хотите объявлять другую границу: нет)

РЕДАКТИРОВАТЬ: В случае, если у вас есть «красный» после не красный несколько раз, каждый «первый» красный получит границу. Чтобы предотвратить это, нужно будет использовать ответ BoltClock. Смотри скрипку

SamGoody
источник
2
Этот ответ не является неправильным, селектор является правильным для данной разметки, но я должен повторить, что ситуация, упомянутая в редактировании, является причиной, почему я утверждаю, что переопределение необходимо, по крайней мере, когда вы не можете гарантировать структуру разметки - просто потому, что .redследует :not(.red)не всегда делает его первым .redсреди своих братьев и сестер. И если граница должна быть унаследована, это просто вопрос объявления, border: inheritа не border: noneправила переопределения.
BoltClock
3
Это лучшее решение для ИМО, потому что вы легко можете сделать то же самое для последнего ребенка.
A1rPun
@ A1rPun Как вы измените это для последнего ребенка?
Виллем
@ Виллем Просто поменяйте first-childна last-child, но после тестирования я вижу, что это не всегда помогает.
A1rPun
3
Извините, но он не соответствует «первому дочернему элементу, который имеет класс .red», вместо этого он соответствует «первому элементу, если он имеет класс .red и первый элемент .red после элемента .red». Эти два не эквивалентны. Скрипка: jsfiddle.net/Vq8PB/166
Гунчары
19

Вы могли бы использовать first-of-typeилиnth-of-type(1)

.red {
  color: green;  
}

/* .red:nth-of-type(1) */
.red:first-of-type {
  color: red;  
}
<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>

Nerdroid
источник
6
Это не будет работать , если у вас есть <p></p>между spanи ваш первый pэлемент с redклассом. Посмотрите на это JSFiddle .
Франциско Ромеро
1
Теперь я увидел, что в последнем примере его ответа он воспроизводит то же поведение, которое я указал здесь. Когда я попробовал ваш пример и немного «поиграл», я заметил это поведение и хотел указать, чтобы будущие читатели знали об этом.
Франциско Ромеро
13

Приведенные выше ответы слишком сложны.

.class:first-of-type { }

Это выберет первый тип класса. MDN Source

Габриэль Ярмарка
источник
4
Я не могу найти ссылку на первый тип, и первый тип относится только к имени тега; Вы уверены, что этот ответ правильный?
Мэтт Броатч
1
first-type был переименован в first-of-type
Габриэль Ярмарка
7
Это не работает с классами. Вот как это должно работать, потому что выбор n-го класса будет более полезным, чем выбор n-го тега. Но ': first-of-type' только когда-либо работал tagName. Если так получилось, что «first-of-class» и «first-of-tag» ссылаются на один и тот же элемент, что они часто делают, легко запутать себя в мысли, что это работает именно так; а потом интересно, что сломалось, когда вы пришли к делу, в котором они не делают.
Эван Томпсон
2
Не уверен, почему это не выбранный ответ. Это делает именно то, о чем просил ОП, и отлично работает. SMH.
Бернесто,
1
@Bernesto, когда у вас есть случай, когда у вас есть несколько элементов одного «типа», скажем <span>, и у нескольких есть класс highlight. .highlight:first-of-typeСелектор будет выбрать первый экземпляр «типа» с выбранным классом, в этом примере первый <span>и не первый экземпляр класса highlight. Стиль будет реализован только в том случае, если этот первый экземпляр span также будет выделен классом. ( codepen.io/andrewRmillar/pen/poJKJdJ )
Sl4rtib4rtf4st
9

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

<div>
    <span class="red"> <!-- MATCH -->
</div>

<div>
    <span>Blah</span>
    <p class="red"> <!-- NO MATCH -->
</div>

<div>
    <span>Blah</span>
    <div><p class="red"></div> <!-- MATCH -->
</div>
Четан Шастри
источник
это правильно, и это кажется моей проблемой, но есть ли способ выбрать первый элемент с классом, независимо от того, предшествует ли ему другие элементы?
Раджат
Если вы смотрели на ответ Мартинов, вам не нужно было спрашивать об этом :)
Филипп Добмайер
9

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

  1. Присвойте firstкласс элементу при его создании, например так:

    <p class="red first"></p>
    <div class="red"></div>

    CSS:

    .first.red {
      border:5px solid red;
    }

    Этот CSS соответствует только элементы с обоих first и redклассами.

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

    $(".red:first").addClass("first");
Ник Крейвер
источник
Я придумал CSS решения только некоторое время назад ; Я воспроизвел это здесь как канонический ответ.
BoltClock
1
Пока ничего подобного :first-of-class, я бы также предложил добавить дополнительный класс к первому элементу. Кажется, самое простое решение на данный момент.
Кай Ноак,
7

Я получил это в моем проекте.

div > .b ~ .b:not(:first-child) {
	background: none;
}
div > .b {
    background: red;
}
<div>
      <p class="a">The first paragraph.</p>
      <p class="a">The second paragraph.</p>
      <p class="b">The third paragraph.</p>
      <p class="b">The fourth paragraph.</p>
  </div>

Йенер Эрер
источник
5

Согласно вашей обновленной проблеме

<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>

как насчет

.home span + .red{
      border:1px solid red;
    }

Это выберет класс home , затем span span и, наконец, все .red элементы , которые размещаются сразу после элементов span.

Ссылка: http://www.w3schools.com/cssref/css_selectors.asp

StinkyCat
источник
3

Вы можете использовать nth-of-type (1), но убедитесь, что сайту не требуется поддержка IE7 и т. Д. В этом случае используйте jQuery для добавления класса тела, затем найдите элемент через класс тела IE7, затем имя элемента, затем добавьте в стиле nth-child к нему.

Джейми Патерсон
источник
3

Вы можете изменить свой код на что-то вроде этого, чтобы заставить его работать

<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>

Это делает работу за вас

.home span + .red{
      border:3px solid green;
    }

Вот ссылка CSS от SnoopCode об этом.

Прабхакар Ундурти
источник
3

Я использую ниже CSS, чтобы иметь фоновое изображение для списка ul li

#footer .module:nth-of-type(1)>.menu>li:nth-of-type(1){
  background-position: center;
  background-image: url(http://monagentvoyagessuperprix.j3.voyagesendirect.com/images/stories/images_monagentvoyagessuperprix/layout/icon-home.png);
  background-repeat: no-repeat;
}
<footer id="footer">
  <div class="module">
    <ul class="menu ">
      <li class="level1 item308 active current"></li>
      <li> </li>
    </ul> 
  </div>
  <div class="module">
    <ul class="menu "><li></li>
      <li></li> 
    </ul>
  </div>
  <div class="module">
    <ul class="menu ">
      <li></li>
      <li></li>
    </ul>
  </div>
</footer>

Ли Бин Чжао
источник
2

Попробуй это :

    .class_name > *:first-child {
        border: 1px solid red;
    }
Loy
источник
2

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

#element_id > .class_name:first-child

Все приведенные выше ответы потерпят неудачу, если вы захотите применить стиль только к первому дочернему классу в этом коде.

<aside id="element_id">
  Content
  <div class="class_name">First content that need to be styled</div>
  <div class="class_name">
    Second content that don't need to be styled
    <div>
      <div>
        <div class="class_name">deep content - no style</div>
        <div class="class_name">deep content - no style</div>
        <div>
          <div class="class_name">deep content - no style</div>
        </div>
      </div>
    </div>
  </div>
</aside>
Явор Иванов
источник
1
Ваш ответ, по сути, уже содержится в двух лучших ответах на этот вопрос и ничего не добавляет. Кроме того, использование вами :first-childпсевдокласса вводит в заблуждение, поскольку он добавляет, .class_nameпрежде чем он не изменит способ его работы, а просто заставит его действовать как фильтр. Если у вас есть div раньше, <div class="class_name">First content that need to be styled</div>ваш селектор не будет совпадать, поскольку он не является первым дочерним элементом.
j08691
Я не думаю, что это так просто для того, кому нужна информация. И да, вы правы по этому поводу. Это служит более конкретному случаю. Вот почему я подумал, что это может быть полезно.
Явор Иванов
Это именно то, что мне нужно, точное и сжатое. Спасибо @YavorIvanov
количество
1

Попробуйте это просто и эффективно

 .home > span + .red{
      border:1px solid red;
    }
друг
источник
-1

Я считаю, что с помощью относительного селектора + для выбора элементов, размещенных сразу после, работает здесь лучше всего (как предлагалось ранее).

В этом случае также возможно использовать этот селектор

.home p:first-of-type

но это селектор элемента, а не класс.

Вот хороший список селекторов CSS: https://kolosek.com/css-selectors/

Неша Зорич
источник
-2

Попробуйте это решение:

 .home p:first-of-type {
  border:5px solid red;
  width:100%;
  display:block;
}
<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>

CodePen ссылка

Сантош Халсе
источник
Вопрос « CSS-селектор для первого элемента с классом », а не « CSS-селектор для первого элемента с именем тега ».
GeroldBroser восстанавливает Монику