Pregunta Selector de CSS para el primer elemento con clase


Tengo un montón de elementos con un nombre de clase red, pero parece que no puedo seleccionar el primer elemento con class="red" usando la siguiente regla CSS:

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

¿Qué hay de malo en este selector y cómo lo corrijo?

Gracias a los comentarios, descubrí que el elemento tiene que ser el primer hijo de su padre para ser seleccionado, que no es el caso que tengo. Tengo la siguiente estructura, y esta regla falla como se menciona en los comentarios:

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

¿Cómo puedo apuntar al primer niño con clase red?


700
2018-04-26 22:51


origen


Respuestas:


Este es uno de los ejemplos más conocidos de autores que malinterpretan cómo :first-child trabajos. Introducido en CSS2, el :first-child pseudo-clase representa el primer hijo de su padre. Eso es. Existe una idea errónea muy común de que selecciona el elemento secundario que coincide con las condiciones especificadas por el resto del selector compuesto. Debido a la forma en que funcionan los selectores (ver aquí para una explicación), eso simplemente no es verdad.

Selectores nivel 3 introduce un :first-of-type pseudo-clase, que representa el primer elemento entre los hermanos de su tipo de elemento. Esta respuesta explica, con ilustraciones, la diferencia entre :first-child y :first-of-type. Sin embargo, como con :first-child, no mira ninguna otra condición o atributo. En HTML, el tipo de elemento está representado por el nombre de la etiqueta. En la pregunta, ese tipo es p.

Desafortunadamente, no hay similar :first-of-class pseudoclase para hacer coincidir el primer elemento secundario de una clase determinada. Una solución que Lea Verou y se me ocurrió esto (aunque de manera totalmente independiente) es aplicar primero los estilos deseados a todas tus elementos con esa clase:

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

... luego "deshacer" los estilos de los elementos con la clase que ven después del primero, utilizando el combinador hermano general ~ en una regla primordial:

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

Ahora solo el primer elemento con class="red" tendrá un borde.

Aquí hay una ilustración de cómo se aplican las reglas:

<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. No se aplican reglas; no se da borde
    Este elemento no tiene la clase red, así que se salta.

  2. Solo se aplica la primera regla; se renderiza un borde rojo.
    Este elemento tiene la clase red, pero no está precedido de ningún elemento con la clase red en su padre Por lo tanto, la segunda regla no se aplica, solo la primera y el elemento mantiene su borde.

  3. Ambas reglas son aplicadas; no se da borde
    Este elemento tiene la clase red. También está precedido por al menos otro elemento con la clase red. Por lo tanto, se aplican ambas reglas, y el segundo border la declaración anula la primera, por lo tanto, "deshacerla", por así decirlo.

Como beneficio adicional, a pesar de que se introdujo en Selectores 3, el combinador de hermanos en general es bastante bien compatible con IE7 y más reciente, a diferencia :first-of-type y :nth-of-type() que solo son compatibles con IE9 en adelante. Si necesita un buen soporte de navegador, tiene suerte.

De hecho, el hecho de que el combinador de hermanos es el único componente importante en esta técnica, y tiene un soporte de navegador tan increíble que hace que esta técnica sea muy versátil; puedes adaptarla para filtrar elementos por otras cosas, además de los selectores de clase:

  • Puedes usar esto para evitar :first-of-type en IE7 e IE8, simplemente suministrando un selector de tipo en lugar de un selector de clase (de nuevo, más sobre su uso incorrecto aquí en una sección 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 */
    }
    
  • Puedes filtrar por selectores de atributos o cualquier otro selector simple en lugar de clases.

  • También puede combinar esta técnica primordial con pseudo-elementos a pesar de que los pseudo-elementos técnicamente no son simples selectores.

Tenga en cuenta que para que esto funcione, necesitará saber de antemano cuáles serán los estilos predeterminados para sus otros elementos hermanos para que pueda anular la primera regla. Además, como esto implica reglas primordiales en CSS, no puede lograr lo mismo con un solo selector para usar con el API de selectores, o Seleniolocalizadores de CSS.

Vale la pena mencionar que Selectors 4 presenta una extensión a la :nth-child() notación (originalmente una pseudo-clase completamente nueva llamada :nth-match()), lo que te permitirá usar algo como :nth-child(1 of .red) en lugar de un hipotético .red:first-of-class. Al tratarse de una propuesta relativamente reciente, aún no hay suficientes implementaciones interoperables para poder utilizarlas en los sitios de producción. Espero que esto cambie pronto. Mientras tanto, la solución alternativa que sugerí debería funcionar para la mayoría de los casos.

Tenga en cuenta que esta respuesta asume que la pregunta busca cada primer elemento secundario que tiene una clase determinada. No hay una pseudoclase ni una solución de CSS genérica para la enésima coincidencia de un selector complejo en todo el documento - Si existe una solución depende en gran medida de la estructura del documento. jQuery proporciona :eq(), :first, :last y más para este propósito, pero tenga en cuenta una vez más que funcionan de manera muy diferente a :nth-child() et al. Usando la API de Selectores, puede usar document.querySelector() para obtener el primer partido:

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

O usar document.querySelectorAll() con un indexador para elegir cualquier coincidencia específica:

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

Aunque el .red:nth-of-type(1) solución en la respuesta original aceptada por Philip Daubmeier trabajos (que fue escrito originalmente por Martyn pero eliminado desde), no se comporta de la manera que esperaría.

Por ejemplo, si solo desea seleccionar el p en su marcado original:

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

... entonces no puedes usar .red:first-of-type (equivalente a .red:nth-of-type(1)), porque cada elemento es el primero (y único) uno de su tipo (p y div respectivamente), entonces ambos será igualado por el selector.

Cuando el primer elemento de una cierta clase es también el primero de su tipo, la pseudo-clase funcionará, pero esto sucede solo por coincidencia. Este comportamiento se demuestra en la respuesta de Felipe. En el momento en que inserte un elemento del mismo tipo antes de este elemento, el selector fallará. Tomando el marcado actualizado:

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

Aplicando una regla con .red:first-of-type funcionará, pero una vez que agregue otro p sin la clase:

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

... el selector fallará inmediatamente, porque la primera .red elemento es ahora el segundo  p elemento.


1142
2017-12-16 19:21



los :first-child selector está destinado, como su nombre lo dice, para seleccionar el primer hijo de una etiqueta principal. Los niños deben estar incrustados en la misma etiqueta principal. Tu ejemplo exacto funcionará (solo lo probé aquí)

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

¿Tal vez has anidado tus etiquetas en diferentes etiquetas padre? Son tus etiquetas de clase red realmente las primeras etiquetas bajo el padre?

Tenga en cuenta también que esto no solo se aplica a la primera etiqueta de este tipo en todo el documento, sino cada vez que un nuevo padre se adapta a ella, 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>

first y third será rojo entonces.

Actualizar:

No sé por qué Martyn eliminó su respuesta, pero tenía la solución, la :nth-of-type selector:

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

Créditos para Martyn. Más información, por ejemplo aquí. Tenga en cuenta que este es un selector de CSS 3, por lo tanto, no todos los navegadores lo reconocerán (por ejemplo, IE8 o anterior).


304
2018-04-26 22:58



La respuesta correcta es:

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

Parte I: si el elemento es primero para su elemento primario y tiene una clase "roja", tendrá borde.
Parte II: Si el elemento ".red" no es primero para su elemento primario, sino que está siguiendo inmediatamente un elemento sin clase ".red", también deberá merecer el honor de dicho borde.

Violín o no sucedió.

La respuesta de Philip Daubmeier, si bien es aceptada, no es correcta, vea el violín adjunto.
La respuesta de BoltClock funcionaría, pero define y sobrescribe innecesariamente los estilos
(particularmente un problema donde de otra manera heredaría un borde diferente - no desea declarar otro al borde: ninguno)

EDITAR: En el caso de que tenga "rojo" seguido de no rojo varias veces, cada "primer" rojo obtendrá el borde. Para evitar eso, uno necesitaría usar la respuesta de BoltClock. Ver violín


58
2017-11-08 11:15



podrías usar first-of-type o 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>


13
2018-01-13 00:57



Para que coincida con su selector, el elemento debe tener un nombre de clase de red y debe ser el primer hijo de su padre.

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

8
2018-04-26 23:04



Dado que las otras respuestas cubren lo que es incorrecto con eso, probaré la otra mitad, cómo solucionarlo. Desafortunadamente, no sé que tienes una Solo CSS solución aquí, al menos No es que yo pueda pensar. Aunque hay otras opciones ...

  1. Asignar un first clasifica al elemento cuando lo generas, así:

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

    CSS:

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

    Este CSS solo combina elementos con ambos  first y red clases

  2. Alternativamente, haga lo mismo en JavaScript, por ejemplo, aquí está lo que jQuery usaría para hacer esto, usando el mismo CSS que el anterior:

    $(".red:first").addClass("first");
    

6
2018-04-26 23:13



De acuerdo con tu problema actualizado

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

qué tal si

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

Esto seleccionará casa de clase, entonces el elemento lapso y finalmente todo elementos .red que se colocan inmediatamente después de los elementos del tramo.

Referencia: http://www.w3schools.com/cssref/css_selectors.asp


5
2018-01-21 11:49



Puede cambiar su código a algo así para que funcione

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

Esto hace el trabajo por ti

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

Aquí hay una referencia de CSS de SnoopCode sobre eso.


3
2017-10-14 10:15



Estoy usando debajo de CSS para tener una imagen de fondo para la 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>


3
2018-06-27 20:25



Puede usar nth-of-type (1) pero asegúrese de que el sitio no necesite soportar IE7 etc., si este es el caso use jQuery para agregar body class luego encuentre element mediante IE7 body class luego el nombre del elemento, luego agregue en el estilo n-child a él.


2
2018-06-03 12:59



Prueba esto :

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

2
2017-08-04 22:06