learning-front

Nivel 1 · HTML y CSS: la estructura y la piel

Selectores CSS

Antes de dar estilo a un elemento hay que saber apuntarle. Este capítulo cubre los selectores que usarás a diario: tipo, clase e ID; agrupación; combinadores descendiente e hijo; y las pseudo-clases :hover y :focus. Con ellos puedes decirle al navegador exactamente qué cambiar y cuándo.

En el capítulo anterior aprendiste qué es una regla CSS y cómo escribirla: selector { propiedad: valor; }. El selector era el nombre de la etiquetap, h1— y funcionaba, pero de forma muy poco precisa. Si estilabas p dabas estilo a todos los párrafos de la página, aunque solo quisieras cambiar uno.

Los selectores son la forma de apuntarle al navegador exactamente al elemento que quieres cambiar. Con ellos puedes decir “este <p> concreto”, “todos los <a> que estén dentro de la cabecera” o “el enlace cuando el usuario pasa el ratón”. Esa precisión es lo que separa un CSS que crece limpio de uno que se convierte en un enredo de reglas que se machacan unas a otras.

Seguimos con el Overwatch Team Builder. El HTML de la cabecera y las cartas de héroe ya está hecho. En este capítulo le damos estilo apuntando con precisión: cada selector afecta exactamente a lo que queremos, y nada más.

Selector de tipo, de clase y de ID#

Ya conoces los tres básicos del capítulo anterior. Vale la pena tenerlos claros antes de avanzar:

css
/* Tipo: afecta a todos los <p> de la página */
p {
  color: #5b5966;
}

/* Clase: afecta a todos los elementos con class="hero-card" */
.hero-card {
  background: white;
  border: 1px solid #e6e3ee;
}

/* ID: afecta al único elemento con id="cabecera" */
#cabecera {
  background: #1c1b22;
}

La regla práctica que aplica la industria:

  • Selector de tipo para resets y normalizaciones que de verdad afectan a todos los elementos de ese tipo: quitar el margen de body, o el padding y el list-style de todos los ul.
  • Clase para prácticamente todo lo demás. Es reutilizable (varios elementos pueden tener la misma clase), fácil de sobrescribir cuando hace falta y no añade especificidad excesiva.
  • ID para anclar enlaces dentro de la página (href="#cabecera"), no para dar estilo. Los ID tienen mayor especificidad que las clases y son difíciles de sobrescribir. En la práctica, casi nunca merece la pena usarlos en CSS.

Agrupación: un bloque para varios selectores#

Si h1, h2 y h3 comparten el mismo font-family, no tiene sentido escribir tres reglas idénticas. La coma agrupa selectores que comparten las mismas declaraciones:

css
h1,
h2,
h3 {
  font-family: system-ui, sans-serif;
}

Esto es equivalente a tres reglas separadas, pero si cambia la fuente solo hay que tocar un lugar. En el Team Builder, el brand de la cabecera y los enlaces del nav comparten el mismo color blanco: se agrupan y se declaran una vez.

Combinadores: relaciones entre elementos#

Un combinador es un símbolo entre dos selectores que describe la relación entre el padre y el hijo. Los dos que vas a usar más:

Combinador descendiente (el espacio)#

css
.hero-card p {
  color: #5b5966;
}

El espacio entre .hero-card y p significa “un <p> en cualquier punto del interior de .hero-card”, por muy anidado que esté. Selecciona descendientes a cualquier nivel.

Combinador hijo directo (>)#

css
.hero-list > li {
  margin-bottom: 1rem;
}

El > es más estricto: solo afecta a los hijos inmediatos. En el Team Builder, .hero-list contiene <li> con las cartas, pero cada carta tiene a su vez una .hero-stats que también es una <ul> con sus propios <li>. Con el espacio (descendiente), el estilo llegaría a todos; con >, solo a los hijos directos de .hero-list.

La diferencia importa cuando tienes listas anidadas o cualquier estructura donde el mismo tipo de elemento aparece en varios niveles del árbol.

Pseudo-clases: el estado del elemento#

Una pseudo-clase selecciona un elemento en un estado concreto. Se escribe con dos puntos después del selector:

css
.hero-link:hover {
  text-decoration: underline;
}

Las dos pseudo-clases que más vas a usar en este nivel:

  • :hover — cuando el puntero del ratón está sobre el elemento. Funciona en cualquier elemento, no solo en enlaces.
  • :focus — cuando el elemento recibe el foco: al hacer clic en él, pero también al llegar a él navegando con la tecla Tab. Es la contrapartida de :hover para el teclado.

Escríbelas siempre juntas en los elementos interactivos:

css
.site-nav a:hover,
.site-nav a:focus {
  color: #b8336a;
}

Ignorar :focus es uno de los errores de accesibilidad más habituales. Quien usa el teclado para navegar —personas con movilidad reducida, usuarios de lectores de pantalla, cualquiera que prefiera no soltar las manos del teclado— necesita saber en qué enlace está. Si solo hay :hover, el indicador visual desaparece para ellos.

El selector universal *#

El asterisco selecciona todos los elementos del documento:

css
* {
  box-sizing: border-box;
}

Úsalo con cuidado. Tiene sentido para resets que de verdad deben afectar a cada elemento de la página (el reset de box-sizing, que verás en el capítulo de Box model, es el caso clásico). Para colores, fuentes o espaciado hay opciones más precisas: body para propiedades que los hijos heredan, o clases para elementos concretos.

Una nota sobre la especificidad#

Como viste en el capítulo “Qué es CSS”, los selectores tienen distinto peso. La regla de oro en proyectos reales: usa la especificidad mínima suficiente. No encadenes cinco selectores para sobrescribir otro, y no tires de ID para ganar por fuerza bruta. Si necesitas veinte selectores encadenados para que una regla “gane”, algo está mal en la arquitectura del CSS, no en el selector que intentas añadir.

El objetivo es que el CSS sea predecible: sabes que .hero-name afecta a los nombres de los héroes, y solo a ellos. Sin sorpresas.

Los colores y unidades de los ejemplos —#b8336a, 1rem, 0.9rem— los verás en detalle en el siguiente capítulo. Las propiedades de caja como margin, padding o border, que dan espacio y separación a los elementos, las verás en Box model y Flexbox. Por ahora vale con entender que son valores válidos; no hace falta memorizarlos todavía.

Pruébalo#

La cabecera y las cartas del Team Builder con los selectores del capítulo aplicados. Abre la pestaña /styles.css y prueba a:

  • Cambiar .hero-name por h2 y observar qué h2 más aparece afectado (ninguno en este HTML, pero en uno con cabecera con un h2 se vería enseguida).
  • Cambiar .hero-list > li por .hero-list li (sin >) y ver si hay diferencia visible. En este HTML no la hay, pero si abres las DevTools y miras los .stat, sí que la encontrarás.
  • Pasar el ratón sobre un enlace (:hover) y luego navegar con Tab hasta él (:focus).

Comprueba lo que sabes#

Pregunta 1 de 5

Tienes varias cartas de héroe en la página. ¿Qué selector es más adecuado para darles estilo?

Tu turno#

El HTML está completo. Tu tarea es escribir el CSS usando los selectores vistos en el capítulo, aquí mismo. Los comentarios TODO del starter te guían sobre qué selector practicar en cada bloque. Edita el CSS en el playground; cuando creas que lo tienes, despliega las soluciones y compáralas con la tuya.

Ejercicio · en esta página

Dale estilo a la ficha del equipo con los selectores correctos

El HTML de la página ya está hecho: una cabecera con navegación, una lista de tres cartas de héroe y un pie. Tu tarea es escribir el CSS en styles.css usando la variedad de selectores vista en el capítulo. Los comentarios TODO te indican qué selector practicar en cada bloque.

Paso 1: Que se vea

  • La página tiene estilos visibles: cabecera con fondo oscuro, cartas con fondo blanco y borde.
  • Vale aunque use ID para la cabecera y selectores de tipo donde deberían ir clases.
  • Los enlaces cambian al pasar el ratón (aunque falte :focus).
Ver soluciones
/* =============================================================================
   NIVEL OK — "funciona y se ve"
   =============================================================================
   Resuelve el ejercicio y la página se ve. Ese es el objetivo mínimo.

   Sus límites (lo que arregla el nivel "Mejor"):
     - Estila los <h2> de toda la página con selector de tipo: si más adelante
       añades un h2 en la cabecera o el pie, se estilará igual que los nombres
       de héroe, sin que lo hayas pedido.
     - Usa el ID #cabecera para el fondo oscuro de la cabecera. Los ID tienen
       mayor especificidad que las clases y son difíciles de sobrescribir.
     - Reglas repetidas: el color del brand y el color de los enlaces del nav
       se declaran por separado, aunque son idénticos.
     - Sin :focus en los enlaces: quien navega con teclado no ve qué enlace
       tiene el foco.
   Aun así: todo se ve correctamente. Es un buen punto de partida.
   ============================================================================= */

body {
  margin: 0;
  font-family: system-ui, sans-serif;
}

ul {
  padding: 0;
  list-style: none;
}

/* Usa el ID en lugar de la clase */
#cabecera {
  background: #1c1b22;
  color: #f7f6fb;
  padding: 0.75rem 1.5rem;
}

/* Selector de tipo: afecta a todos los <a> de la página */
a {
  color: #f7f6fb;
  text-decoration: none;
}

/* Repetición: el brand se redeclara por separado */
.brand {
  font-size: 1.2rem;
  font-weight: 700;
  color: #f7f6fb;
}

.brand-accent {
  color: #b8336a;
}

.site-nav a {
  font-size: 0.9rem;
}

.site-nav a:hover {
  color: #b8336a;
}

/* Sin :focus */

.page {
  max-width: 52rem;
  margin: 0 auto;
  padding: 2rem 1.5rem;
}

.intro {
  color: #5b5966;
}

/* Selector de tipo: afecta a TODOS los <li>, no solo a los de .hero-list */
li {
  margin-bottom: 1rem;
}

.hero-card {
  background: #fff;
  border: 1px solid #e6e3ee;
  border-radius: 10px;
  padding: 1.25rem;
}

/* Selector de tipo: si añades un h2 fuera de la carta, recibirá estos estilos */
h2 {
  font-size: 1.1rem;
  margin: 0;
}

.hero-role {
  color: #5b5966;
  font-size: 0.8rem;
  text-transform: uppercase;
}

.stat-label {
  font-size: 0.72rem;
  color: #5b5966;
}

.stat-value {
  font-weight: 600;
}

.hero-link {
  color: #b8336a;
  text-decoration: none;
}

.hero-link:hover {
  text-decoration: underline;
}

/* Sin :focus */

.site-footer {
  margin-top: 2rem;
  padding: 1rem 1.5rem;
  border-top: 1px solid #e6e3ee;
  color: #5b5966;
  font-size: 0.85rem;
}

Por qué este nivel

  • La página se ve: cabecera oscura, cartas con fondo blanco y bordes redondeados, enlaces que cambian al pasar el ratón. Ese es el objetivo mínimo.
  • Usa `#cabecera` (ID) para el fondo oscuro de la cabecera. Los ID tienen mayor especificidad que las clases y son difíciles de sobrescribir. Si en el futuro necesitas cambiar ese fondo en un contexto distinto, te costará más trabajo.
  • El selector `h2 { ... }` apunta a todos los encabezados de nivel 2 del documento. Si la página crece y aparece un h2 en la cabecera o el pie, recibirá los mismos estilos que el nombre del héroe, sin que lo hayas pedido.
  • El `li { ... }` afecta a todos los `<li>` de la página, incluidos los de `.hero-stats`. El margin-bottom acaba aplicándose también a cada estadística dentro de la carta.
  • Falta `:focus` en los enlaces: quien navega con el teclado no ve qué enlace tiene el foco.