Селектор CSS для першого елемента з класом


944

У мене є купа елементів з назвою класу 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

Відповіді:


1423

Це один із найвідоміших прикладів непорозуміння авторів, як це :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 Selectors або з CSS-локаторами Selenium .

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

Майте на увазі, що ця відповідь передбачає, що питання шукає кожен перший дочірній елемент, який має даний клас. Не існує ані псевдокласу, ані навіть загального CSS рішення для n-го збігу складного селектора у всьому документі - чи існує рішення сильно залежить від структури документа. JQuery надає :eq(), :first, :lastі багато іншого для цієї мети, але ще раз відзначити , що вони працюють дуже по- різному з :nth-child()співавт . Використовуючи API Selectors, ви можете або скористатися 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 елемент.


15
Отже, чи є можливість наслідувати :last-of-class? Виберіть останній елемент класу.
Ракета Хазмат

1
@Rocket: Не те, що я бачу :(
BoltClock

4
Гарна техніка з братами. Можливо, варто відзначити, що це працює і з кількома комбінаторами побратимів, наприклад, p ~ p ~ p обере третій пункт і далі: jsfiddle.net/zpnnvedm/1
Legolas

2
@BoltClock Так, вибачте, я прийшов сюди за рішенням, і я не так сильно переймався конкретним випадком роботи з ОП. Я насправді не можу зрозуміти, чому це general sibling selector ~працює як :not(:first-of-*)для певного типу, я вважаю, що воно має застосовувати правило до кожного відповідного елемента, але воно застосовується лише для першого збігу, навіть якщо є 3 і більше можливих збігів.
Джерард Речес

2
За caniuse на :nth-child(1 of .foo)розширення вже був реалізований на Safari 9.1+. (Я ще не перевіряв)
Даніелд,

329

: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.
Már Örlygsson

25
Я трохи розгубився, читаючи це. Суворо .red:nth-of-type(1)вибере будь-який елемент, який (a) є першим дочірнім елементом свого типу, і (b) має клас "червоний". Тож якби у прикладі першого <p> не було класу "червоний", його не було б вибрано. Крім того, якщо у <span> і першого <p> було клас "червоний", вони обидва будуть обрані. jsfiddle.net/fvAxn
Девід

7
@Dan Mundy: :first-of-typeеквівалентно :nth-of-type(1), так що, звичайно, це теж працює. Він також може провалитися аналогічно з тієї ж причини, що вказана у моїй відповіді.
BoltClock

4
@David Я впевнений, що :nth-of-typeозначає "елемент / тег", коли він пише "тип". Тож він розглядає лише елемент, а не речі, як класи.
gcampbell

2
@gcampbell: Так, саме це означає і саме ця відповідь є хибною. Причина вибору слова "type" полягає в тому, щоб не з’єднувати селектори з HTML / XML, оскільки не всі мови мають поняття "теги", які визначають елементи.
BoltClock

74

Правильна відповідь:

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

Частина I: Якщо елемент спочатку є його батьківським і має клас "червоний", він повинен отримати межу.
Частина II: Якщо елемент ".red" не є першим своїм батьківським, але одразу слідує за елементом без класу ".red", він також заслуговує на честь зазначеного кордону.

Фіддл чи цього не сталося.

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

РЕДАКТИРУЙТЕ: Якщо у вас кілька разів "червоний" слідує за не червоним, кожен "перший" червоний отримає кордон. Щоб цього не допустити, потрібно було б використовувати відповідь BoltClock. Дивіться скрипку


2
Відповідь на це питання не так, селектор є правильним для даної розмітки, але я повинен повторити , що ситуація згадується в редагуванні причина , чому я стверджую , що перевизначення необхідно , по крайней мере , коли ви не можеш гарантувати структуру розмітки - тільки тому, що .redвипливає, :not(.red)що не завжди робить його першим .redсеред своїх побратимів. І якщо кордон потрібно успадковувати, це просто питання декларування border: inheritзамість border: noneправила переопределення.
BoltClock

3
Це рішення є найкращим ІМО, оскільки ви можете легко зробити те ж саме для останньої дитини.
A1rPun

@ A1rPun Як змінити це для останньої дитини?
Віллем

@Willem Просто перейдіть first-childна last-child, але після тестування я бачу, що це не завжди допомагає .
A1rPun

3
Вибачте, але він не відповідає "першому дочірньому елементу, який має клас .red", натомість він відповідає "першому елементу, якщо він має клас .red і перший .red елемент після не .red елемента". Ці два не є рівнозначними. Fiddle
Gunchars

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>


6
Це не спрацює, якщо у вас <p></p>між класом spanта вашим першим pелементом є redклас. Подивіться на цей JSFiddle .
Франциско Ромеро

1
Тепер я бачив, що він відтворює в останньому прикладі його відповіді ту саму поведінку, яку я вказував тут. Коли я спробував ваш приклад і трохи «зіграв», я помітив цю поведінку, і хотів вказати, щоб майбутні читачі знали про це.
Франциско Ромеро

13

Наведені вище відповіді занадто складні.

.class:first-of-type { }

Це дозволить вибрати клас першого типу. Джерело MDN


4
Я не можу знайти посилання на перший тип, і перший тип застосовується лише до імені тегів; ви впевнені, що ця відповідь правильна?
Метт Броат


7
З класами це не працює. Ось так і має працювати, бо вибір n-го класу був би кориснішим, ніж вибір n-го тегу. Але ': first-of-type' працював лише tagName. Якщо так трапляється, що "першокласник" і "перший тег" посилаються на один і той же елемент, що вони часто роблять, легко заплутати себе в думці, що це працює так; а потім цікаво, що зламається, коли ти приходиш до справи, в якій вони цього не роблять.
Еван Томпсон

2
Не впевнений, чому це не обрана відповідь. Це саме те, про що просив ОП, і працює чудово. SMH.
Бернесто

1
@ Bernesto, коли у вас є випадок, коли у вас є кілька елементів одного "типу", давайте скажемо <span>, і декілька мають клас highlight. .highlight:first-of-typeСелектор буде вибрати перший екземпляр «типу» з обраним класом, в цьому прикладі перший <span>і не перший екземпляр класу highlight. Стиль буде реалізований лише в тому випадку, якщо цей перший екземпляр прольоту також має виділення класу. ( 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;
    }

Тут буде обрано домашній клас , потім проміжок елементів і, нарешті, всі .red елементи , розміщені одразу після елементів.

Довідка: http://www.w3schools.com/cssref/css_selectors.asp


3

Ви можете використовувати nth-типу (1), але будьте впевнені, що сайту не потрібно підтримувати IE7 тощо, якщо це так, використовуйте jQuery для додавання класу body, а потім знайдіть елемент через клас тіла IE7, потім ім'я елемента, а потім додайте в стилі n-ї дитини до нього.


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

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 class="class_name">First content that need to be styled</div>ваш вибір не збігається, оскільки це не справжня перша дитина.
j08691

Я не думаю, що це так прямо вперед для того, кому потрібна інформація. І так, ви маєте рацію щодо справи. Це служить більш конкретному випадку. Ось чому я подумав, що це може бути корисним.
Явор Іванов

Це саме те, що мені було потрібно, точне і стисло. Дякую @YavorIvanov
Quantme

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-селектор для першого елемента з назвою тега ".
ГерольдБрозер повертає Моніку
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.