Seletor CSS para o primeiro elemento com classe

947

Eu tenho vários elementos com um nome de classe red, mas não consigo selecionar o primeiro elemento class="red"usando a seguinte regra CSS:

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

O que há de errado nesse seletor e como corrigi-lo?

Graças aos comentários, descobri que o elemento precisa ser o primeiro filho de seu pai para ser selecionado, o que não é o caso que tenho. Eu tenho a seguinte estrutura e esta regra falha conforme mencionado nos comentários:

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

Como posso segmentar o primeiro filho da turma red?

Rajat
fonte
para aqueles que estão ficando confusos por causa de diferentes tipos de elementos no meu exemplo (p, div), torná-los iguais também não funciona e o problema ainda existe.
Rajat
4
Penso que esta é a forma como o: selector de primeira criança deve ter trabalhado ...
Felix Eve
28
: primeiro filho não seria um nome muito bom então. Se você tivesse um filho e depois uma filha, não chamaria sua filha de primogênita. Da mesma forma, o primeiro .home> .red não é o primeiro filho de .home, portanto, seria inadequado chamá-lo como tal.
BoltClock
Não, é a forma como a: tipo de primeira-deveria ter funcionado
Evan Thompson
@EvanThompson É assim :first-of-type que funciona.
TylerH 25/03

Respostas:

1427

Este é um dos exemplos mais conhecidos de autores que não entendem como :first-childfunciona. Introduzida no CSS2 , a :first-childpseudo-classe representa o primeiro filho de seu pai . É isso aí. Há um equívoco muito comum de que ele seleciona o elemento filho o primeiro a corresponder às condições especificadas pelo restante do seletor composto. Devido à maneira como os seletores funcionam (veja aqui uma explicação), isso simplesmente não é verdade.

Os seletores de nível 3 introduzem uma :first-of-typepseudo-classe , que representa o primeiro elemento entre irmãos de seu tipo de elemento. Esta resposta explica, com ilustrações, a diferença entre :first-childe :first-of-type. No entanto, assim como :first-childacontece, ele não analisa outras condições ou atributos. Em HTML, o tipo de elemento é representado pelo nome da marca. Na pergunta, esse tipo é p.

Infelizmente, não há :first-of-classpseudo-classe semelhante para corresponder ao primeiro elemento filho de uma determinada classe. Uma solução alternativa que Lea Verou e eu propusemos para isso (embora de forma totalmente independente) é primeiro aplicar os estilos desejados a todos os seus elementos com essa classe:

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

... então "desfaça" os estilos dos elementos da classe que se seguem ao primeiro , usando o combinador geral de irmãos~ em uma regra primordial:

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

Agora, apenas o primeiro elemento com class="red"terá uma borda.

Aqui está uma ilustração de como as regras são aplicadas:

<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. Nenhuma regra é aplicada; nenhuma borda é renderizada.
    Este elemento não possui a classe red, por isso é ignorado.

  2. Somente a primeira regra é aplicada; uma borda vermelha é renderizada.
    Este elemento tem a classe red, mas não é precedido por nenhum elemento com a classe redem seu pai. Assim, a segunda regra não é aplicada, apenas a primeira, e o elemento mantém sua borda.

  3. Ambas as regras são aplicadas; nenhuma borda é renderizada.
    Este elemento tem a classe red. Também é precedida por, pelo menos, um outro elemento com a classe red. Assim, ambas as regras são aplicadas e a segunda borderdeclaração substitui a primeira, "desfazendo-a", por assim dizer.

Como um bônus, embora tenha sido introduzido nos Seletores 3, o combinador geral de irmãos é realmente muito bem suportado pelo IE7 e mais recente, ao contrário :first-of-typee :nth-of-type()que são suportados apenas pelo IE9 em diante. Se você precisar de um bom suporte ao navegador, está com sorte.

De fato, o fato de o combinador de irmãos ser o único componente importante nessa técnica, e ter um suporte incrível ao navegador, torna essa técnica muito versátil - você pode adaptá-lo para filtrar elementos por outras coisas, além dos seletores de classe:

  • Você pode usar isso para contornar o :first-of-typeIE7 e o IE8, simplesmente fornecendo um seletor de tipo em vez de um seletor de classe (novamente, mais sobre o uso incorreto aqui em uma seção posterior):

    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 */
    }
    
  • Você pode filtrar por seletores de atributos ou quaisquer outros seletores simples em vez de classes.

  • Você também pode combinar essa técnica de substituição com pseudoelementos, mesmo que tecnicamente os pseudoelementos não sejam seletores simples.

Observe que, para que isso funcione, você precisará saber com antecedência quais serão os estilos padrão para os outros elementos irmãos, para que você possa substituir a primeira regra. Além disso, como isso envolve a substituição de regras no CSS, você não pode conseguir a mesma coisa com um único seletor para usar com a API Selectors ou com os localizadores CSS do Selenium .

Vale ressaltar que os Seletores 4 introduzem uma extensão da :nth-child()notação (originalmente uma pseudo classe totalmente nova chamada :nth-match()), que permitirá que você use algo como um :nth-child(1 of .red)substituto hipotético .red:first-of-class. Sendo uma proposta relativamente recente, ainda não há implementações interoperáveis ​​suficientes para que possam ser utilizadas em locais de produção. Espero que isso mude em breve. Enquanto isso, a solução que sugeri deve funcionar na maioria dos casos.

Lembre-se de que esta resposta pressupõe que a pergunta esteja procurando por todos os elementos do primeiro filho que tenham uma determinada classe. Não existe uma pseudo-classe nem mesmo uma solução CSS genérica para a enésima correspondência de um seletor complexo em todo o documento - se uma solução existe depende muito da estrutura do documento. jQuery fornece :eq(), :first, :laste mais para o efeito, mas nota mais uma vez que eles funcionam de forma muito diferente de :nth-child()et al . Usando a API Selectors, você pode usar document.querySelector()para obter a primeira correspondência:

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

Ou use document.querySelectorAll()com um indexador para escolher qualquer correspondência específica:

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

Embora a .red:nth-of-type(1)solução na resposta original aceita por Philip Daubmeier funcione (que foi originalmente escrita por Martyn, mas excluída desde então), ela não se comporta da maneira que você esperaria.

Por exemplo, se você deseja apenas selecionar a pmarcação original:

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

... então você não pode usar .red:first-of-type(equivalente a .red:nth-of-type(1)), porque cada elemento é o primeiro (e somente) um de seu tipo ( pe divrespectivamente), para que ambos sejam correspondidos pelo seletor.

Quando o primeiro elemento de uma determinada classe também é o primeiro de seu tipo , a pseudo-classe funciona, mas isso acontece apenas por coincidência . Esse comportamento é demonstrado na resposta de Philip. No momento em que você colar um elemento do mesmo tipo antes desse elemento, o seletor falhará. Tomando a marcação atualizada:

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

A aplicação de uma regra com .red:first-of-typefuncionará, mas depois de adicionar outra psem a classe:

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

... o seletor falhará imediatamente, porque o primeiro .redelemento agora é o segundo p .

BoltClock
fonte
15
Então, existe alguma maneira de emular :last-of-class? Selecione o último elemento de uma classe.
Rocket Hazmat
1
@Rocket: Não que eu possa ver :(
BoltClock
4
Boa técnica com o irmão. Vale a pena notar que isso também funciona com vários combinadores de irmãos, por exemplo, p ~ p ~ p selecionará o terceiro item e além: jsfiddle.net/zpnnvedm/1
Legolas
2
@BoltClock Sim, desculpe, eu vim aqui para uma solução e não me importei tanto com o caso específico do OP. Na verdade, não consigo entender por que general sibling selector ~funciona como a :not(:first-of-*)para um tipo específico, presumo que ela deva aplicar a regra a cada elemento correspondente, mas é aplicada apenas para a primeira correspondência, mesmo quando houver três ou mais correspondências possíveis.
Gerard Reches
2
Segundo caniuse, a :nth-child(1 of .foo)extensão já foi implementada no Safari 9.1+. (Eu não tenho verificado embora)
DanielD
330

O :first-childseletor deve, como o nome diz, selecionar o primeiro filho de uma tag pai. Os filhos precisam ser incorporados na mesma tag pai. Seu exemplo exato funcionará (tentei aqui ):

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

Talvez você tenha aninhado suas tags em diferentes tags principais? Suas tags de classe são redrealmente as primeiras sob o pai?

Observe também que isso não se aplica apenas à primeira marca desse documento em todo o documento, mas sempre que um novo pai é envolvido, como:

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

firste thirdserá vermelho então.

Atualizar:

Não sei por que o martyn excluiu sua resposta, mas ele tinha a solução, o :nth-of-typeseletor:

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

Créditos a Martyn . Mais informações, por exemplo, aqui . Esteja ciente de que este é um seletor CSS 3, portanto, nem todos os navegadores o reconhecerão (por exemplo, IE8 ou mais antigo).

Philip Daubmeier
fonte
Pode ter sido minha culpa - como eu havia apontado para Martyn que um seletor de CSS3 :nth-of-typesofre o pequeno problema de não funcionar em nenhuma versão atual do IE.
Már Örlygsson
25
Fiquei um pouco confuso ao ler isso. Estritamente .red:nth-of-type(1)selecionará qualquer elemento que (a) seja o primeiro filho do seu tipo de elemento e (b) tenha a classe "vermelho". Portanto, se, no exemplo, o primeiro <p> não tivesse a classe "vermelho", ele não seria selecionado. Como alternativa, se a <span> e a primeira <p> tivessem a classe "vermelho", elas seriam selecionadas. jsfiddle.net/fvAxn
David
7
@ Dan Mundy: :first-of-typeé equivalente a :nth-of-type(1), então é claro que também funciona. Também pode falhar, da mesma maneira, pela mesma razão indicada na minha resposta.
BoltClock
4
@ David, tenho certeza que :nth-of-typesignifica "elemento / tag" quando diz "type". Portanto, ele considera apenas o elemento, não coisas como classes.
gcampbell
2
@ gcampbell: Sim, é exatamente isso que significa, e é por isso que esta resposta é falha. A razão pela qual a palavra "tipo" foi escolhida é para não acoplar seletores com HTML / XML, pois nem todos os idiomas têm um conceito de "tags" que definem elementos.
BoltClock
74

A resposta correta é:

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

Parte I: Se o elemento for o primeiro de seu pai e tiver a classe "red", ele deverá obter uma borda.
Parte II: Se o elemento ".red" não for o primeiro a seu pai, mas seguir imediatamente um elemento sem a classe ".red", ele também merecerá a honra da referida borda.

Fiddle ou não aconteceu.

A resposta de Philip Daubmeier, embora aceita, não está correta - veja o violino em anexo.
A resposta do BoltClock funcionaria, mas desnecessariamente define e substitui estilos
(particularmente um problema em que ela herdaria uma borda diferente - você não deseja declarar outra borda: none)

EDIT: No caso de você ter "vermelho" depois de não vermelho várias vezes, cada "primeiro" vermelho receberá a borda. Para evitar isso, seria necessário usar a resposta de BoltClock. Veja violino

SamGoody
fonte
2
Essa resposta não está errada, o seletor está correto para a marcação especificada, mas devo reiterar que a situação mencionada na edição é a razão pela qual declaro que uma substituição é necessária pelo menos quando você não pode garantir a estrutura da marcação - apenas porque .redsegue um :not(.red)nem sempre o torna o primeiro .redentre seus irmãos. E se a borda precisar ser herdada, é simplesmente uma questão de declarar, e border: inheritnão border: nonena regra de substituição.
BoltClock
3
Esta solução é a melhor IMO porque você pode facilmente fazer o mesmo para o último filho.
A1rPun
@ A1rPun Como você muda isso para o último filho?
Willem
@ William Basta mudar first-childpara last-child, mas vejo após o teste que isso nem sempre funciona.
precisa saber é o seguinte
3
Sinto muito, mas não corresponde ao "primeiro elemento filho que possui a classe .red"; em vez disso, corresponde ao "primeiro elemento se tiver a classe .red e o primeiro .red elemento após um elemento não .red". Esses dois não são equivalentes. Fiddle: jsfiddle.net/Vq8PB/166
Gunchars
19

você poderia usar first-of-typeounth-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
fonte
6
Não funcionará se você tiver um <p></p>entre o spane seu primeiro pelemento com redclasse. Veja este JSFiddle .
Francisco Romero
1
Vi agora que ele reproduz no último exemplo de sua resposta o mesmo comportamento que apontei aqui. Quando experimentei o seu exemplo e "toquei" um pouco, notei esse comportamento e queria apontar para que os futuros leitores estejam cientes.
Francisco Romero
13

As respostas acima são muito complexas.

.class:first-of-type { }

Isso selecionará o primeiro tipo de classe. Origem MDN

Gabriel Fair
fonte
4
Não consigo encontrar nenhuma referência ao primeiro tipo, e o primeiro do tipo se aplica apenas ao nome da tag; você tem certeza de que esta resposta está correta?
Matt Broatch
1
first-type foi renomeado para first-of-type
Gabriel Fair
7
Não funciona com classes. É assim que deve funcionar, porque selecionar o enésimo de uma classe seria mais útil do que selecionar o enésimo de uma tag. Mas ': first-of-type' só funcionou por tagName. Se acontecer que 'first-class-class' e 'first-of-tag' se refiram ao mesmo elemento, o que geralmente fazem, é fácil confundir-se pensando que funciona dessa maneira; e depois se perguntando o que está quebrado quando você chega a um caso em que não.
Evan Thompson
2
Não sei por que essa não é a resposta selecionada. Isso faz exatamente o que o OP estava pedindo e funciona perfeitamente. SMH.
Bernesto 30/09/19
1
@ Bernesto, quando você tem um caso em que você tem vários elementos do mesmo "tipo", digamos <span>, e alguns têm a classe highlight. O .highlight:first-of-typeseletor selecionará a primeira instância do "tipo" com a classe selecionada, neste exemplo a primeira <span>e não a primeira instância da classe highlight. Somente se a primeira instância do span também tiver o destaque da classe, o estilo será implementado. ( codepen.io/andrewRmillar/pen/poJKJdJ )
Sl4rtib4rtf4st
9

Para corresponder ao seu seletor, o elemento deve ter um nome de classe rede deve ser o primeiro filho de seu pai.

<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>
Chetan Sastry
fonte
isso está correto e esse parece ser o meu problema, mas existe uma maneira de selecionar o primeiro elemento com uma classe, independentemente de ser precedido por outros elementos?
quer
Se você tivesse olhado para resposta Martyns você não tinha que perguntar isso :)
Philip Daubmeier
9

Como as outras respostas cobrem o que há de errado , tentarei a outra metade, como corrigi-lo. Infelizmente, não sei se você tem uma solução somente CSS aqui, pelo menos não que eu possa pensar . Existem algumas outras opções embora ....

  1. Atribua uma firstclasse ao elemento ao gerá-lo, assim:

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

    CSS:

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

    Este CSS corresponde apenas aos elementos com as classes firste red.

  2. Como alternativa, faça o mesmo em JavaScript, por exemplo, aqui está o jQuery que você usaria para fazer isso, usando o mesmo CSS acima:

    $(".red:first").addClass("first");
Nick Craver
fonte
Eu vim com uma solução somente CSS há um tempo atrás ; Eu o reproduzi aqui como uma resposta canônica.
BoltClock
1
Desde que não exista nada :first-of-class, eu também sugeriria adicionar uma classe extra ao primeiro elemento. Parece a solução mais fácil por enquanto.
Kai Noack 26/09
7

Eu tenho esse aqui no meu projeto.

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>

Yener Örer
fonte
5

De acordo com o seu problema atualizado

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

e quanto a

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

Isso selecionará a home da classe e , em seguida, o elemento span e, finalmente, todos os elementos .red que são colocados imediatamente após os elementos span.

Referência: http://www.w3schools.com/cssref/css_selectors.asp

StinkyCat
fonte
3

Você pode usar o enésimo tipo (1), mas certifique-se de que o site não precise oferecer suporte ao IE7, etc. no enésimo filho-estilo.

Jamie Paterson
fonte
3

Você pode alterar seu código para algo assim para fazê-lo funcionar

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

Isso faz o trabalho para você

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

Aqui está uma referência CSS do SnoopCode sobre isso.

Prabhakar Undurthi
fonte
3

Estou usando o CSS abaixo para ter uma imagem de plano de fundo para a lista 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>

li bing zhao
fonte
2

Tente o seguinte:

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

Por alguma razão, nenhuma das respostas acima parecia abordar o caso do primeiro e único filho real dos pais.

#element_id > .class_name:first-child

Todas as respostas acima falharão se você deseja aplicar o estilo somente ao filho de primeira classe desse código.

<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>
Yavor Ivanov
fonte
1
Sua resposta já está essencialmente contida nas duas principais respostas mais altas a esta pergunta e não acrescenta nada. Além disso, seu uso da :first-childpseudo-classe é enganoso, uma vez que a adição .class_nameantes não altera a forma como funciona e apenas a faz agir como um filtro. Se você tiver um div antes <div class="class_name">First content that need to be styled</div>, seu seletor não corresponderá, pois não é o primeiro filho real.
J08691
Não acho que seja tão simples para alguém que precisa das informações. E sim, você está certo sobre o caso. Isso serve para um caso mais específico. É por isso que pensei que poderia ser útil.
precisa saber é o seguinte
Era exatamente isso que eu precisava, preciso e conciso. Obrigado @YavorIvanov
quantme
1

Experimente isto simples e eficaz

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

Acredito que o uso do seletor relativo +para selecionar elementos colocados imediatamente depois funcione aqui da melhor maneira (como poucos sugeriram antes).

Também é possível, neste caso, usar esse seletor

.home p:first-of-type

mas esse é o seletor de elementos, não a classe um.

Aqui você tem uma boa lista de seletores de CSS: https://kolosek.com/css-selectors/

Nesha Zoric
fonte
-2

Experimente esta solução:

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

Link CodePen

Santosh Khalse
fonte
A pergunta é " seletor de CSS para o primeiro elemento com a classe ", não " seletor de CSS para o primeiro elemento com o nome da tag ".
GeroldBroser restabelece Monica