Saltar a contenido

CSS: la presentación visual

Una página construida solo con HTML funciona, pero se ve como un documento de texto plano: títulos en negrilla, párrafos apilados, enlaces azules subrayados. Toda la información está ahí, y aun así resulta difícil de leer.

CSS (Cascading Style Sheets) es el lenguaje que resuelve eso. Define el estilo visual de la página: colores, espacios, tamaños, posiciones, fuentes y la disposición de los elementos en pantalla.

Su aporte va más allá de lo estético. CSS permite separar el contenido de la presentación: el HTML dice qué hay, el CSS dice cómo se ve. Gracias a esa separación, cambiar la apariencia de un sitio completo puede requerir tocar un solo archivo, sin modificar una línea de contenido. Es la misma idea que veremos formalizada más adelante en el patrón MVC.

Documentación de referencia

CSS tiene cientos de propiedades y ninguna persona las memoriza todas. La referencia recomendada para consultarlas es w3schools.com/cssref.


Sintaxis de una regla CSS

Toda hoja de estilos se compone de reglas, y toda regla tiene la misma estructura:

Anatomía de una regla CSS: selector, propiedad, valor y declaración

Sus partes son:

  • Regla — el bloque completo.
  • Selectora qué elementos se aplica el estilo (en el ejemplo, h1).
  • Declaración — cada instrucción de estilo dentro de las llaves, terminada en punto y coma.
  • Propiedadqué característica se modifica (color).
  • Valorqué valor recibe esa característica (blue).
h1 {
  color: blue;
}

Se lee de forma casi literal: "a todos los h1 del documento, ponles el color de texto azul". Una regla puede contener tantas declaraciones como haga falta:

h1 {
  color: blue;
  font-size: 32px;
  text-align: center;
  margin-bottom: 16px;
}

¿Dónde se escribe el CSS?

Hay tres formas de aplicar estilos, y no son equivalentes:

Forma Cómo se escribe Cuándo usarla
Archivo externo <link href="estilos.css"> en el <head> La forma correcta. Un solo archivo estiliza todo el sitio y el navegador puede guardarlo en caché.
Interno Bloque <style> dentro del <head> Solo para pruebas rápidas o páginas de un único archivo.
En línea Atributo style="..." en la etiqueta Evitar. Mezcla presentación con contenido y es casi imposible de mantener.
<head>
  <link rel="stylesheet" href="estilos.css">
</head>

El DOM: sobre qué actúan los selectores

Antes de escribir selectores hay que entender sobre qué operan. Cuando el navegador recibe el HTML no lo trata como texto: lo convierte en una estructura de datos llamada DOM (Document Object Model).

HTML y CSS se combinan en el DOM, que el navegador dibuja en pantalla

El DOM es la estructura de datos que guarda los contenidos del documento a desplegar, combinando contenido (del HTML) y presentación (del CSS). Es análogo a un árbol de sintaxis abstracta en un lenguaje de programación: así como un compilador convierte el código fuente en un árbol antes de procesarlo, el navegador convierte el HTML en un árbol antes de dibujarlo.

Ese árbol tiene la misma jerarquía que las etiquetas anidadas del documento:

html
├── head
│   ├── title
│   └── link
└── body
    ├── header
    │   └── h1
    ├── main
    │   ├── section
    │   │   ├── h2
    │   │   └── p
    │   └── article
    └── footer

Comprender esto es clave por dos razones. La primera es que un selector CSS es una consulta sobre ese árbol: cuando escribimos main p, estamos preguntando "¿qué nodos p cuelgan de un nodo main?". La segunda es que, más adelante, JavaScript modificará ese mismo árbol para cambiar la página en tiempo real. HTML, CSS y JS no son tres mundos separados: los tres convergen en el DOM.


Selectores

Un selector identifica uno o varios elementos del DOM para aplicarles estilo. Es la parte de CSS que más conviene dominar, porque de ella depende que los estilos lleguen exactamente a donde deben.

Selector de tipo

Selecciona todos los elementos de una etiqueta determinada: h1, span, body, p.

p {
  color: blue;
}

Afecta a todos los párrafos del documento, sin excepción. Es útil para definir la base tipográfica del sitio, pero demasiado amplio para casos concretos.

Selector de clase

Dentro de las etiquetas HTML existe un atributo class, un texto que define las clases que tiene ese elemento del DOM. Cada clase no debe tener espacios, y un mismo elemento puede declarar varias clases separadas por espacios.

<p class="destacado">Este párrafo va resaltado.</p>
<p class="destacado grande">Este además es grande.</p>
<p>Este no recibe ningún estilo especial.</p>
.destacado {
  background-color: #fff3cd;
}

.grande {
  font-size: 20px;
}

La clase se escribe en CSS precedida de un punto. Es el selector más usado en la práctica, porque permite reutilizar un mismo estilo en cualquier elemento y combinar varios estilos sobre uno solo.

Selector por identificador

El atributo id también vive dentro de las etiquetas, pero con una restricción importante: debe ser único en todo el documento. Los estilos definidos para un id se aplican solo al elemento que lo lleva.

<div id="menu-principal">...</div>
#menu-principal {
  background-color: gray;
}

El identificador se escribe precedido de almohadilla.

¿Clase o identificador?

Clase para estilos que se repiten —botones, tarjetas, alertas—, que es la mayoría de los casos. Identificador para elementos únicos de la página y, sobre todo, para que JavaScript los localice o para enlazar a una sección con #.

Como regla práctica: si dudas, usa clase. Un estilo que hoy parece único casi siempre termina repitiéndose.

Selectores de atributo

Permiten seleccionar los elementos del DOM según alguno de sus atributos, ya sea por su presencia o por su valor. Son especialmente útiles en formularios, enlaces y componentes dinámicos.

Selector Selecciona los elementos…
[attr] que tienen el atributo attr, sin importar su valor.
[attr=val] cuyo atributo attr vale exactamente val.
[attr~=val] cuyo atributo attr contiene la palabra val dentro de una lista separada por espacios.
[attr|=val] cuyo atributo attr vale val o empieza por val seguido de un guion (útil para idiomas: es, es-CO).
[attr^=val] cuyo atributo attr empieza por el texto val.
[attr$=val] cuyo atributo attr termina en el texto val.
[attr*=val] cuyo atributo attr contiene el texto val en cualquier posición.
/* Todos los campos deshabilitados */
[disabled] {
  opacity: 0.5;
}

/* Solo los campos de texto */
input[type="text"] {
  border: 1px solid black;
}

/* Enlaces a archivos PDF */
a[href$=".pdf"] {
  font-weight: bold;
}

/* Enlaces externos */
a[href^="http"] {
  color: darkgreen;
}

No confundir ^, $ y |

Son los tres que más se prestan a error: ^= empieza por, $= termina en, *= contiene en cualquier lugar. El |= es un caso especial pensado para valores con guion, como los códigos de idioma.

Pseudoclases

Las pseudoclases se utilizan para describir una característica que el elemento está cumpliendo en un momento dado: que el mouse esté encima, que sea la página actual, que un campo esté enfocado. Se escriben con dos puntos.

a:hover {
  color: red;
}

input:focus {
  border-color: blue;
}

li:first-child {
  font-weight: bold;
}

tr:nth-child(even) {
  background-color: #f5f5f5;
}

Lo interesante de las pseudoclases es que permiten reaccionar a estados sin escribir una línea de JavaScript. El listado completo está en w3schools.com/css/css_pseudo_classes.asp.

Pseudoelementos

Se escriben con dos veces dos puntos y seleccionan una parte de un elemento, o generan contenido que no existe en el HTML:

p::first-letter {
  font-size: 2em;
}

.obligatorio::after {
  content: " *";
  color: red;
}

Combinadores

Los combinadores se utilizan cuando necesitamos unir varios selectores para expresar una relación entre elementos dentro del árbol del DOM.

Combinador Sintaxis Selecciona… Ejemplo
Concatenación (sin espacio) AB los elementos que cumplen ambos selectores a la vez. p#pipol1, div.clase1
Descendiente (espacio) A B los elementos B que están dentro de A, a cualquier nivel de profundidad. p .clase1
Hijo directo A > B los elementos B que son hijos directos de A. p > b
Hermano adyacente A + B el elemento B que aparece inmediatamente después de A, con el mismo padre. h1 + p
Hermanos generales A ~ B todos los elementos B que son hermanos de A y aparecen después. h2 ~ p

La diferencia entre concatenación y descendiente es la que más confusión genera, y es solo un espacio:

/* Concatenación: un <p> que ADEMÁS tiene la clase destacado */
p.destacado { color: blue; }

/* Descendiente: cualquier elemento con clase destacado DENTRO de un <p> */
p .destacado { color: blue; }

Ejemplos de cada combinador:

/* Concatenación */
div.clase1 {
  color: blue;
}

/* Descendiente */
div p {
  color: blue;
}

/* Hijo directo */
ul > li {
  list-style: none;
}

/* Hermano adyacente */
h1 + p {
  margin-top: 0;
}

/* Hermanos generales */
h2 ~ p {
  color: gray;
}

/* Selector múltiple: el mismo estilo para varios selectores */
h1, h2, h3 {
  font-family: Arial;
}

/* Universal: todos los elementos del documento */
* {
  margin: 0;
}

La cascada: por qué se llama Cascading

El nombre del lenguaje no es decorativo. Cuando varias reglas afectan al mismo elemento y se contradicen, el navegador necesita un criterio para decidir cuál gana. Ese criterio es la cascada, y se resuelve en dos niveles:

  1. Especificidad. Gana el selector más específico. En orden creciente: selector universal * → selector de tipo p → selector de clase .destacado → selector de id #menu → estilos en línea style="...".
  2. Orden de aparición. A igual especificidad, gana la última regla escrita.
p            { color: black; }   /* especificidad baja  */
.destacado   { color: blue;  }   /* gana sobre la anterior */
#unico       { color: red;   }   /* gana sobre todas */

Sobre !important

Existe la posibilidad de forzar una regla añadiendo !important, y salta por encima de toda la cascada. Es tentador cuando un estilo "no aplica", pero casi siempre indica que el problema real es un selector mal diseñado. Usarlo convierte la hoja de estilos en una escalada de excepciones difícil de mantener.


Propiedades más utilizadas

Propiedad Descripción Valores comunes
color Color del texto. red, blue, #333, rgb(0,0,0)
background-color Color de fondo del elemento. white, #f5f5f5, transparent
font-size Tamaño del texto. 12px, 16px, 1em, 1rem, %
font-family Tipografía del texto. Arial, Verdana, sans-serif
font-weight Grosor del texto. normal, bold, 100–900
text-align Alineación horizontal del texto. left, center, right, justify
margin Espacio externo alrededor del elemento. 10px, 0 auto, 5px 10px
padding Espacio interno entre el contenido y el borde. 10px, 5px 15px
border Borde del elemento. 1px solid black, none
width Ancho del elemento. 100px, 50%, auto
height Altura del elemento. 200px, auto, 100%
display Cómo se muestra el elemento. block, inline, inline-block, none, flex, grid
position Método de posicionamiento. static, relative, absolute, fixed, sticky
top, right, bottom, left Ajustan la posición del elemento. 0, 10px, %
overflow Comportamiento del contenido que desborda. visible, hidden, scroll, auto
cursor Cursor del mouse sobre el elemento. pointer, default, text
opacity Transparencia del elemento. 0 a 1
box-shadow Sombra del elemento. 2px 2px 5px gray
border-radius Redondeo de las esquinas. 5px, 50%
z-index Orden de superposición entre elementos. 1, 10, 100

Contenedores: el modelo de caja

En CSS todos los elementos HTML se representan como una caja. Este concepto, conocido como modelo de caja (Box Model), define cómo se distribuyen el contenido y los espacios de un elemento dentro de la página. Es, probablemente, el concepto que más problemas resuelve una vez se entiende bien.

Modelo de caja: contenido, padding, borde y margen

La caja se compone, de adentro hacia afuera, de cuatro zonas:

  1. Contenido (content). El texto, la imagen o los elementos visibles. Sus dimensiones se controlan con width y height.
  2. Relleno (padding). El espacio interno entre el contenido y el borde. Evita que el contenido quede pegado al límite de la caja.
  3. Borde (border). La línea visible que delimita el elemento.
  4. Margen (margin). El espacio externo que separa este elemento de los demás.

El orden es siempre: contenido → padding → border → margin.

La confusión más común es entre padding y margin. La forma corta de recordarlo: el padding empuja el contenido hacia adentro; el margin empuja los elementos vecinos hacia afuera. Si el fondo de un elemento es de color, el padding se pinta de ese color y el margin no.

El truco de box-sizing

Por defecto, width define solo el ancho del contenido: el padding y el borde se suman por fuera, de modo que un elemento con width: 200px y padding: 20px ocupa realmente 240px. Añadir esta regla al inicio de la hoja de estilos hace que width incluya padding y borde, que es como casi todo el mundo espera que funcione:

* {
  box-sizing: border-box;
}

Despliegue y posicionamiento de los contenedores

La propiedad position determina cómo se ubica un contenedor respecto al resto de la página:

Valor Comportamiento
static Valor por defecto. Los elementos se ponen uno después del otro, siguiendo el flujo natural del documento.
relative La posición se modifica a partir de la posición por defecto que debería tener el elemento. El espacio que ocupaba se conserva.
absolute La posición se modifica relativa al padre más cercano que no tenga posición static. El elemento sale del flujo normal.
fixed La posición se modifica con respecto a la ventana. El elemento permanece fijo aunque se haga scroll.
float Pone los elementos uno al lado del otro, y cuando se acaba el espacio continúa en la parte inferior.

float es una propiedad aparte

A diferencia de los otros cuatro, float no es un valor de position sino una propiedad independiente (float: left). Fue durante años la herramienta principal para construir layouts de columnas, y por eso aparece en muchísimo código existente. Hoy, para organizar la página, la recomendación es usar Flexbox o Grid, que están diseñados específicamente para eso y evitan los problemas clásicos de los flotantes.

Las cuatro propiedades top, right, bottom y left son las que efectivamente desplazan el elemento, y solo tienen efecto si position es distinto de static.


Diseño responsivo

Una misma página debe verse bien en un monitor de escritorio y en la pantalla de un teléfono. Dos herramientas hacen posible esa adaptación.

Flexbox y Grid

Ambas organizan el contenido en el espacio disponible sin recurrir a posiciones absolutas:

/* Flexbox: distribución en una dirección (fila o columna) */
.contenedor {
  display: flex;
  gap: 16px;
  justify-content: space-between;
}

/* Grid: distribución en dos dimensiones (filas y columnas) */
.galeria {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

Media queries

Una media query aplica un bloque de estilos solo cuando se cumple una condición sobre el dispositivo, típicamente el ancho de la pantalla:

/* Estilos base: escritorio */
.contenedor {
  display: flex;
  flex-direction: row;
}

/* En pantallas de 768px o menos, apilar en columna */
@media (max-width: 768px) {
  .contenedor {
    flex-direction: column;
  }
}

Nunca debe haber desplazamiento horizontal

El síntoma más claro de una página mal adaptada es que en el teléfono se pueda desplazar hacia los lados. Suele deberse a un ancho fijo en píxeles, a una imagen sin max-width: 100% o a una tabla demasiado ancha. Es uno de los criterios de verificación de la actividad.


Actividad 2 · CSS responsivo

Dale estilo a la página creada en la actividad anterior.

Objetivo

Mejorar la presentación visual y adaptar la página a pantallas de escritorio y móvil.

Pasos

  1. Crea estilos.css y enlázalo desde index.html.
  2. Define colores, tipografía, espaciado y modelo de caja.
  3. Organiza el contenido con Flexbox o Grid.
  4. Agrega una media query para reorganizar la página en móvil.

Entregable

index.html + estilos.css + capturas en escritorio y móvil.

Verificación

✓ Selectores claros y estilos reutilizables. ✓ Jerarquía visual, contraste y espaciado consistentes. ✓ Sin desplazamiento horizontal en móvil. ✓ Contenido legible y bien organizado en ambos tamaños.


Lo que sigue

La página ya tiene contenido y presentación. Falta la tercera capa: hacer que responda a lo que el usuario hace. Continúa en JavaScript.