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

У меня есть куча элементов с именем класса 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?

27 ответов

Решение

Это один из самых известных примеров недопонимания авторами того, как :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 Декларация отменяет первое, тем самым "уничтожая" ее, так сказать.

В качестве бонуса, хотя он был представлен в Selectors 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) Решение в оригинальном принятом ответе произведений Филиппа Добмайера (которое изначально было написано Martyn, но удалено с тех пор), оно не ведет себя так, как вы ожидаете.

Например, если вы хотите выбрать 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 элемент.

: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 селектор:

<html>
<head>
<style type="text/css">
.red:nth-of-type(1)
{
    border:5px solid red;
} 
</style>
</head>

<body>
    <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>
</body>
</html>

Кредиты Martyn. Больше информации, например, здесь. Имейте в виду, что это селектор CSS 3, поэтому не все браузеры распознают его (например, IE8 или старше).

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

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

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

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

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

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

Я удивлен, что никто не упомянул самое чистое решение:

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

.class:first-of-type { }

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

Вы могли бы использовать 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>

Чтобы соответствовать вашему селектору, элемент должен иметь имя класса 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>

Поскольку другие ответы охватывают, что с ним не так, я попробую другую половину, как это исправить. К сожалению, я не знаю, что у вас есть решение только для 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");
    

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

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>

Я использую ниже 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>

С последним n-м ребенком of <selector>синтаксис, вы можете сделать это, чтобы достичь того, чего хотите.

Надеюсь, вам понравится.

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

<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 и, наконец, все элементы.red, которые будут размещены сразу после элементов span.

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

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

Следующий код определенно будет хорошо работать везде.
это просто и коротко.

      <div class="home">
    <span>blah</span>
    <p class="blue"> first-blue  </p>
    <p class="blue"> second-blue </p>
    <p class="blue"> third-blue  </p>

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

    <p class="pink"> first-pink  </p>
    <p class="pink"> second-pink </p>

    <p class="red">  new-first-red   </p>
    <p class="red">  new-second-red  </p>
</div>

мы можем выбратьfirst-redс:

      .home .red:not(.home .red ~ .red) {
    background-color: blue;
}

если вы хотите выбратьnew-first-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>

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

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

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

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

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

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

    .class_name > *:first-child {
        border: 1px solid red;
    }

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

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

Быстрое и грязное решение jQuery для маркировки первого и последнего элемента в группе элементов с одинаковыми именами классов:

Нужно только первый и только один абзац сделать красным. Как?

<!DOCTYPE html><html><head><style>

article p:nth-child(1){background: red}
article p:first-child{background: red}

</style></head><body>

<p style="color:blue">Needed only first and only one paragraph had red. How?</p>

<article>
<p>The first paragraph.</p>
<div><p>The second paragraph.</p></div>
<p>The third paragraph.</p>
<div><p>The fourth paragraph.</p></div>
</article>

</body></html>

просто используйте

      .home > .red ~ .red{
 border: 1px solid red;
}

это будет работать.

Я просто использовал :first как селектор CSS.

.red:first

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

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

.home p:first-of-type

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

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

В общем, после прочтения этой и других страниц, а также большого количества документации. Вот краткое изложение:

  • Для первого / последнего ребенка: теперь безопасно использовать (поддерживается всеми современными браузерами)
  • : nth-child () Теперь также безопасно использовать (поддерживается всеми современными браузерами). Но будьте осторожны, учитываются даже братья и сестры! Итак, следующее не будет работать должным образом:

         /* This should select the first 2 element with class display_class
* but it will NOT WORK Because the nth-child count even siblings 
* including the first div skip_class
*/
.display_class:nth-child(-n+2){ 
    background-color:green; 
}
         <ul>
   <li class="skip_class">test 1</li>
   <li class="display_class">test 2 should be in green</li>
   <li class="display_class">test 3 should be in green</li>
   <li class="display_class">test 4</li>
 </ul>

В настоящее время существует селектор:nth-child(-n+2 of .foo), который поддерживает выбор по классу, но не поддерживается современными браузерами, поэтому бесполезен.

Итак, у нас остается решение Javascript (мы исправим приведенный выше пример):

         // Here we'll go through the elements with the targeted class
// and add our classmodifer to only the first 2 elements!


[...document.querySelectorAll('.display_class')].forEach((element,index) => {
  if (index < 2) element.classList.add('display_class--green');
});
         .display_class--green {
    background-color:green;
}
         <ul>
   <li class="skip_class">test 1</li>
   <li class="display_class">test 2 should be in green</li>
   <li class="display_class">test 3 should be in green</li>
   <li class="display_class">test 4</li>
 </ul>

Не могли бы вы попробовать что-то вроде этого:

.red:first-of-type {
    border: 5px solid red;
}

вы также можете использовать это для последнего элемента (если он вам нужен):

.red:last-of-type {
    border: 5px solid red;
}

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

      .home > .red:first-child {
    /* put your styling here */
}

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

 .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 ссылка

Другие вопросы по тегам