Tres horas. Media hora para entender cómo se enlaza una hoja, cómo se elige un selector y qué decide un conflicto entre dos reglas, y dos horas y media dando estilo a tu sitio y diagnosticando quién gana.
Hoy · Hoja de ruta
- 1. Aprende: Cómo se enlaza una hoja de estilos, de qué partes se compone una regla, qué familias de selectores existen y qué decide cuál de dos reglas en conflicto se aplica.
- 2. Haz: Crea tu hoja, dale el primer estilo al sitio, elige el selector correcto para cinco requisitos y resuelve un conflicto sin
!important. - 3. Comprueba: Sabes leer en DevTools qué regla ha ganado y por qué, y no queda un solo
!importanten tu hoja.
Antes de empezar · 5 minutos, sin apuntes
- ¿Qué información pertenece a HTML y cuál esperas que pertenezca a CSS?
- ¿Qué ventaja tiene conservar el mismo HTML cuando cambia el diseño?
- Señala qué cambiarías para presentar un título en azul sin alterar su significado.
Se explica
25 minutos · conceptos y demostración
Hoy entra el lenguaje entero en su forma mínima: una hoja, una regla, un selector y un criterio para decidir quién gana cuando dos reglas se contradicen. El catálogo de selectores queda como material de consulta dentro del paso que lo usa.
El navegador ya estaba aplicando CSS
Cuando escribiste esto en la UD1:
<h1>PixelStore</h1>
el título se veía grande y en negrita. Eso no es «lo natural»: es una hoja de estilos que trae el navegador de fábrica, la hoja de usuario-agente. Nunca has trabajado sin CSS. Lo que vamos a hacer es tomar el control.
Las tres formas, y por qué usamos una
| Forma | Cómo se escribe | Cuándo |
|---|---|---|
| Hoja externa | Un archivo .css enlazado con link |
Siempre, en esta unidad y en la práctica profesional |
| Hoja interna | Un bloque style en el head |
Casos muy puntuales, como un correo electrónico |
| En línea | Un atributo style en el elemento |
Prácticamente nunca a mano |
La hoja externa gana por tres razones concretas: una sola definición sirve para las cuatro páginas, el navegador se la guarda en caché y no vuelve a descargarla, y el estilo queda separado del contenido, que es la idea entera de estas dos unidades.
<link rel="stylesheet" href="css/styles.css">
Fíjate en que es una ruta relativa, como las de la UD1. Si una página estuviera dentro de una carpeta, sería ../css/styles.css.
Cómo funciona una regla
h1 {
color: navy;
}
h1 selector a qué elementos afecta
color propiedad qué característica cambio
navy valor qué valor le doy
La regla se lee así: «selecciona todos los h1 y cambia su propiedad color». Al conjunto de propiedad y valor se le llama declaración, y van separadas por punto y coma:
body {
font-family: system-ui, sans-serif;
line-height: 1.6;
color: #222;
}
PixelStore
Componentes pensados para trabajar y crear.
El contenido HTML no cambia: CSS modifica tipografía, color y ritmo de lectura.
Regla
Un selector más el bloque de declaraciones que se le aplican. Una hoja de estilos es una lista de reglas.
Los comentarios se escriben solo de una forma. // no funciona, aunque el editor a veces lo coloree como si lo hiciera:
/* Sistema tipográfico base */
body {
font-family: system-ui, sans-serif;
}
Los selectores, en tres familias
Un selector responde a «¿a qué te refieres?», y hay tres maneras de responder.
Por lo que el elemento es. p, a, h1. Afecta a todos los del sitio: útil para las bases, peligroso para algo específico.
Por el papel que le das. Una clase, que se repite en tantos elementos como quieras y describe una función:
<article class="card producto destacado">
.destacado { font-weight: 700; }
Es el selector que más vas a usar. El id también funciona, pero es único en la página y pesa demasiado en los conflictos. Regla práctica: los id son para enlazar y para los label; las clases son para dar estilo.
Por lo que el documento ya declara. Su posición, su estado o sus atributos:
nav a { } /* cualquier enlace dentro de nav */
input:required { } /* el campo es obligatorio */
li:first-child { } /* es el primer hijo de su padre */
a[href^="http"]{ } /* enlaces externos */
Pseudo-clase
Un selector que depende del estado o de la posición del elemento, no de su marcado. Se escribe con dos puntos y no existe en el HTML: la calcula el navegador.
Aquí se comprueba el efecto de lo que hiciste en la UD1: si escribiste type="email" en lugar de type="text", ahora tienes un selector. El HTML bien marcado te devuelve selectores, y esa es la razón de que inventar una clase para algo que el documento ya dice sea duplicar la información en dos sitios.
La palabra «cascading» no es decorativa
CSS significa Cascading Style Sheets. Hojas de estilo en cascada. Esa palabra describe el mecanismo central del lenguaje: varias reglas pueden querer cambiar la misma propiedad del mismo elemento, y hace falta un criterio para decidir.
p { color: blue; }
.destacado { color: red; }
<p class="destacado">Hola</p>
Se ve rojo. La pregunta relevante es por qué.
- Importancia · una declaración con
!importantgana a una normal - Especificidad · gana el selector más específico
- Orden · a igual especificidad, gana la última escrita
Especificidad
Una medida de cuán concreto es un selector. Funciona como un orden de prioridad que basta con conocer, sin necesidad de calcularlo manualmente.
| De menos a más específico | Ejemplo |
|---|---|
| Elemento y pseudo-elemento | p, a |
| Clase, atributo y pseudo-clase | .destacado, [type="email"], :hover |
id |
#productos |
Una regla práctica evita la aritmética: una clase gana a cualquier cantidad de elementos, y un id gana a cualquier cantidad de clases. Por eso #productos p gana a body main section article p, aunque el segundo parezca más trabajado. De ahí sale el consejo anterior: si das estilo con id, cualquier ajuste posterior con clases no podrá corregirlo.
Cuando hay empate de especificidad decide el orden, y gana la última escrita:
.boton { background: blue; }
.boton { background: green; }
Gana el verde. Por eso el orden de tu hoja importa, y por eso conviene escribir de lo general a lo particular.
Herencia
Algunas propiedades pasan de un elemento a sus descendientes, de modo que basta declararlas una vez en body:
| Se heredan | No se heredan |
|---|---|
color, font-family, font-size, line-height, text-align |
margin, padding, border, background, width, display |
La lógica es razonable: lo que se hereda tiene que ver con el texto, y lo que no, con la caja. Que un padding se heredara sería un desastre.
!important y cómo se lee un conflicto
color: red !important;
Existe, gana casi siempre, y no es el botón de arreglar CSS.
Por qué evitarlo
Un !important no resuelve el conflicto: lo esconde. La regla que perdía sigue ahí, y el problema real —que tu selector no era el adecuado, o que el orden estaba mal— sigue sin diagnosticarse.
Además escala. Cuando dentro de un mes necesites sobrescribir esa propiedad, la única forma será otro !important más específico. Ese es el punto en el que una hoja de estilos deja de poder mantenerse.
Si te encuentras escribiéndolo, la pregunta correcta no es «¿cómo hago que esto gane?» sino «¿qué está ganando ahora y por qué?».
Esa pregunta se responde en DevTools. Selecciona un elemento y ve a la pestaña Styles: verás las reglas que le afectan ordenadas de la que gana a la que pierde, con las declaraciones derrotadas tachadas y, a la derecha, el archivo y la línea donde se escribió cada una. La pestaña Computed da el valor final de cada propiedad, ya resuelto el conflicto.
Se trabaja
150 minutos · práctica sobre tu propio proyecto
Los dos primeros pasos ponen en marcha la hoja y eligen selectores; los cuatro últimos entran en los conflictos, que es donde se pierde el tiempo cuando no se sabe diagnosticar.
Paso 1 · Tu primer estilo · 25 min
Sobre tu proyecto de la UD1:
- Crea la carpeta
css/y dentrostyles.css. - Enlázalo en las cuatro páginas.
- Cambia la tipografía general del sitio desde
body. - Da un color distinto a los encabezados.
- Cambia el aspecto de los enlaces.
- Comprueba que el estilo se aplica en las cuatro.
Si una página no cambia, no escribas más CSS
Es el error que más tiempo consume la primera semana, y la reacción instintiva es escribir más reglas por si acaso. No sirve de nada: si la hoja no carga, ninguna regla va a funcionar.
Comprueba en este orden: ¿la ruta del link es correcta desde esa página?, ¿el archivo se llama exactamente así, con sus mayúsculas?, ¿lo has guardado? Y la comprobación definitiva: abre DevTools, pestaña Network, recarga, y busca styles.css. Si aparece en rojo con un 404, ya sabes que el problema es la ruta y no el CSS.
Antes de continuar: las cuatro páginas cargan la hoja, comprobado en Network y no por su apariencia, y el HTML no se ha tocado salvo para añadir el link.
Paso 2 · El selector correcto · 35 min
Para cada requisito, escribe el selector que le corresponde. No vale cualquiera que funcione: vale el que expresa lo que pide el enunciado.
2.1 · Ejemplo resuelto
Requisito: los enlaces del pie no deben subrayarse, pero los del contenido sí.
- ¿Qué me piden seleccionar?
- Enlaces, pero solo los de una zona concreta del documento.
- ¿Cómo está marcada esa zona?
- En la UD1 el pie es un
footer. Ya tengo por dónde acotar. - ¿Descendiente o hijo directo?
- Descendiente: los enlaces pueden estar dentro de párrafos o de listas, no necesariamente colgando del
footer. - Selector
footer a { text-decoration: none; }
No ha hecho falta inventar ninguna clase. Si el HTML ya distingue esa zona, el selector sale solo.
2.2 · Ahora tú
- Todos los enlaces de la navegación principal deben cambiar de aspecto.
- El primer producto del catálogo debe destacarse.
- Los campos obligatorios del formulario deben distinguirse.
- Los enlaces externos deben poder marcarse de forma distinta a los internos.
- Solo los párrafos que están dentro de una ficha de producto, no todos los del sitio.
Consultar · las familias de selectores al completo
Por elemento. Afecta a todos los del sitio.
p { line-height: 1.6; }
Por clase. Una clase puede repetirse en muchos elementos, y un elemento puede tener varias.
.destacado { font-weight: 700; }
Por id. Funciona, pero es único y pesa demasiado en los conflictos.
#productos { padding-block: 3rem; }
Descendiente y directo.
nav a { /* cualquier enlace dentro de nav, a la profundidad que sea */
text-decoration: none;
}
nav > ul { /* solo las listas que son hijas directas de nav */
display: flex;
}
Por atributo.
input[type="email"] {
border-color: #999;
}
a[href^="http"] { /* enlaces cuyo href empieza por http: los externos */
...
}
Pseudo-clases. Seleccionan por estado o por posición.
a:hover { } /* el cursor está encima */
a:focus-visible{ } /* tiene el foco de teclado */
li:first-child { } /* es el primer hijo de su padre */
li:last-child { } /* es el último */
input:required { } /* el campo es obligatorio */
input:invalid { } /* su valor no cumple la validación */
Agrupar. La coma es «o».
h1, h2, h3 {
line-height: 1.15;
}
Un fallo típico es olvidarla: h1 h2 significa «un h2 dentro de un h1», que casi nunca existe, y entonces la regla no hace nada.
Estoy atascado · ¿clase o selector estructural?
Pregúntate si la condición ya está escrita en el HTML. Si es «los obligatorios», el HTML ya lo dice con required: usa :required. Si es «el primero», el HTML ya lo dice por su posición: usa :first-child. Si es «los de oferta», eso no está en ninguna parte del marcado y sí necesita una clase.
Inventar una clase para algo que el documento ya declara es duplicar la información en dos sitios, y tarde o temprano dejan de coincidir.
Ver soluciones
1 · nav a, o si tienes varias navegaciones, acota por su etiqueta: nav[aria-label="Navegación principal"] a.
2 · .catalogo article:first-child, con la clase que uses para el contenedor.
3 · input:required, que además cubre los campos que añadas después sin tocar el CSS.
4 · a[href^="http"], porque los internos de tu proyecto son rutas relativas y no empiezan por http.
5 · article p, o mejor .producto p si el catálogo comparte marcado con otras zonas.
Paso 3 · ¿Quién está ganando? · 35 min
Este HTML y este CSS conviven:
<main id="contenido">
<section class="bloque">
<p class="aviso destacado">Envío gratuito a partir de 50 €.</p>
</section>
</main>
p { color: #333; }
.aviso { color: green; }
.destacado { color: orange; }
#contenido p { color: navy; }
section .aviso { color: purple; }
main section p.aviso { color: teal; }
3.1 · Ejemplo resuelto
- ¿Cuántos
idhay en juego? - Solo uno:
#contenido p. Como elidgana a cualquier cantidad de clases, ese es el candidato inmediato. - ¿Le puede ganar alguna otra?
- No.
main section p.avisotiene una clase y tres elementos, y sigue por debajo de unid. - ¿Importa el orden?
- Aquí no, porque no hay empate en especificidad. El orden solo decide entre iguales.
- Resultado
navy. Al eliminar la regla delid, prevaleceríamain section p.aviso, que esteal.
3.2 · Ahora tú
- Comprueba en el navegador que el color es el que dice el razonamiento.
- Borra la regla del
idy predice el nuevo color antes de recargar. Después comprueba. - Ahora consigue que el párrafo se vea naranja sin usar
!importanty sin tocar el HTML. Hay más de una solución válida: explica la que elijas. - Abre DevTools y localiza cuántas declaraciones de
coloraparecen tachadas.
Estoy atascado · ¿cómo gano sin !important?
Tienes tres caminos legítimos, y conviene que sepas cuál es cuál:
- Subir la especificidad del selector que quieres que gane, hasta pasar al que gana ahora.
- Bajar la del que gana, que casi siempre es lo correcto: quitar el
iddel selector y usar una clase. - Mover la regla más abajo en el archivo, si hay empate de especificidad.
El segundo es el que deja la hoja mejor que antes. Los otros dos la dejan igual de enredada, solo que a tu favor.
Paso 4 · La regla que no hace nada · 15 min
.card .titulo {
color: crimson;
}
<article class="card">
<h3 class="titulo">Portátil Nova 14</h3>
</article>
El título no se ve rojo, y DevTools no muestra la regla ni siquiera tachada. ¿Qué está pasando?
Ver respuesta
Que no aparezca ni tachada es la pista entera. Una regla tachada es una regla que sí seleccionó el elemento y perdió el conflicto. Si no aparece en absoluto, es que no ha seleccionado nada.
Las causas posibles son de fontanería, no de cascada: la hoja no se está cargando, hay una errata en el nombre de la clase, falta el punto y coma o la llave de la regla anterior —lo que invalida esta—, o el elemento no está donde crees.
La lección es el método: tachado significa problema de cascada; ausente significa problema de selector o de sintaxis. Son dos diagnósticos distintos y se buscan en sitios distintos.
Paso 5 · Cinco selectores reales en tu sitio · 25 min
Lleva al proyecto lo del paso 2. Escribe cinco reglas que usen, cada una, una familia distinta de selector, y anota en un comentario por qué ese y no otro:
- Una que acote por una zona semántica de la UD1 (
nav,main,footer…). - Una que use una clase que describa un papel, no una apariencia.
- Una que se apoye en un atributo que ya está en tu HTML.
- Una que use una pseudo-clase de estado o de posición.
- Una que agrupe varios selectores con la coma.
Si alguna te obliga a añadir una clase al HTML, pregúntate antes si el documento ya lo decía de otra forma. Si te obliga a inventar un id, es que no era el camino.
Paso 6 · Auditoría de tu propia hoja · 15 min
Recorre styles.css de arriba abajo y responde:
| Comprobación | Cuántos | Qué haces |
|---|---|---|
!important en la hoja |
||
Selectores que empiezan por # |
||
| Reglas que no seleccionan nada (comprobado en DevTools) | ||
| Clases cuyo nombre describe la apariencia y no el papel |
Corrige los cuatro grupos. Los nombres del tipo .azul o .texto-grande se renombran por lo que significan: el día que el azul pase a verde, la clase .azul miente.
Ampliación si has completado el trabajo
Primero termina y comprueba los seis pasos. Los dos retos trabajan con hojas que no has escrito tú, que es como llegan los proyectos reales.
Reto 1 · La hoja heredada
Recibes esta hoja de un proyecto anterior. Funciona, y es un desastre.
#main .content p.text { color: #444 !important; }
#main .content p { color: #888; }
.text { color: #222; }
p { color: #000; }
#nav ul li a { text-decoration: none !important; }
#nav ul li a:hover { text-decoration: underline; }
.boton-azul { background: #1a5fb4; color: white; }
.boton-azul-grande { background: #1a5fb4; color: white; padding: 1rem 2rem; }
#formulario input { border: 1px solid #ccc !important; }
Reescríbela entera con una condición: ningún !important y ningún id como selector de estilo, manteniendo exactamente el mismo resultado visual.
- Antes de tocar nada, escribe qué color acaba teniendo un
<p class="text">dentro de#main .content, y por qué. Compruébalo después. - El
!importantde la navegación tiene un efecto que quizá no era el buscado: averigua qué le ocurre al subrayado del:hovery explícalo. - Las dos clases de botón repiten dos declaraciones. Resuélvelo sin duplicar, y di qué has hecho con el nombre de las clases.
- Anota cuántas líneas tiene tu versión frente a la original.
Reto 2 · Seis conflictos, predichos antes de mirar
Para cada pareja, predice por escrito qué regla gana y por qué, antes de probar nada. Después móntalo y comprueba.
| # | Regla A | Regla B | Gana | Motivo |
|---|---|---|---|---|
| 1 | .card p |
article p |
||
| 2 | p.aviso |
.aviso |
||
| 3 | #main p |
.a .b .c .d p |
||
| 4 | a:hover |
nav a |
||
| 5 | ul li escrito arriba |
ul li escrito abajo |
||
| 6 | p { color: red !important } |
#main p { color: blue } |
La fila 4 no se decide igual que las demás: piénsala dos veces antes de escribir el motivo.
!important ni id, y las seis predicciones escritas antes de comprobarlas.Cierre
5 minutos · comprobación y recuerdo
Lista de verificación de la sesión
- Existe
css/styles.cssy está enlazado en las cuatro páginas. - Sabes nombrar las tres partes de una regla y comprobar en Network si la hoja se ha cargado.
- Sabes ordenar elemento, clase e
idpor especificidad. - Distingues una propiedad que se hereda de una que no.
- Sabes leer en Styles qué regla gana y cuáles están tachadas.
- No hay ningún
!importantni ningúnidde estilo en tu hoja.
Antes de cerrar · 3 minutos, sin mirar
- ¿Por qué usamos una hoja externa y no un atributo
style? - Nombra las tres partes de una regla CSS.
- ¿Qué diferencia hay entre
nav aynav > a? - ¿Qué gana: tres clases o un
id? - ¿Cuándo decide el orden en que están escritas las reglas?
- En DevTools, ¿qué significa que una declaración aparezca tachada, y qué que no aparezca?
Ver respuestas
1 · Una definición sirve para todas las páginas, el navegador la cachea, y el estilo queda separado del contenido.
2 · Selector, propiedad y valor. La propiedad con su valor forman una declaración.
3 · El primero selecciona cualquier enlace dentro del nav, a la profundidad que sea; el segundo, solo los que cuelgan directamente de él.
4 · El id. Gana a cualquier cantidad de clases.
5 · Solo cuando dos reglas tienen la misma especificidad; entonces se aplica la última escrita.
6 · Tachada quiere decir que seleccionó el elemento pero perdió el conflicto: es un problema de cascada. Que no aparezca quiere decir que no seleccionó nada: es un problema de selector, de sintaxis o de carga.
Microprueba semanal 1 · 5–10 minutos
Individual, sin IA y sin apuntes.
- Escribe un selector de clase, uno descendiente y uno por atributo.
- Ordena por especificidad:
p,.aviso py#principal p. - Una regla aparece tachada en DevTools: explica qué significa y qué revisarías.