01 · Introducción a la programación y al entorno

Ponemos a punto la web de 1.º y el editor, y aprendemos a pensar como un programador: qué es programar, qué es un algoritmo y cómo se escribe en pseudocódigo.

Antes de empezar

Todo lo que haremos este curso se construye sobre lo que aprendiste en Programación I: las imágenes interactivas usan position, el responsive parte de las media queries y JavaScript cambia el HTML y el CSS que ya sabes escribir. Después del verano es normal haber olvidado cosas, así que empezamos poniéndonos al día.

No vamos a repetir el curso pasado. Vamos a revisar la web que hiciste en 1.º con una lista guiada: cada punto te dice qué comprobar y te lleva al sitio donde está explicado, para que repases sólo lo que necesites.

Tu herramienta para este curso: el esquema de HTML y CSS de Recursos reúne lo imprescindible de 1.º en una sola página, con enlaces a cada apartado de los apuntes. Tenlo a mano durante todo el curso: puedes abrirlo en otra pestaña o imprimirlo.

Recupera tu web de 1.º

Este curso vas a seguir trabajando sobre tu web de apuntes: la que explica lo que aprendes en esta asignatura. En cada tema le añadirás algo nuevo y, al final, será tu proyecto final.

  1. Busca la carpeta de la web que hiciste en 1.º. Si sólo la tienes publicada, descárgala desde GitHub o Netlify.
  2. Ábrela en Visual Studio Code (Archivo → Abrir carpeta) y comprueba que la estructura está ordenada: index.html en la raíz y carpetas css e img.
  3. Abre index.html en el navegador y recorre todas las páginas. Apunta lo que no funcione o no te guste.
  4. Haz una copia de seguridad de la carpeta tal y como está ahora, con la fecha en el nombre (web-apuntes-septiembre). Al final del curso podrás comparar.

Ojo: si no tienes la web de 1.º o no la encuentras, no pasa nada: pide en clase la web de apuntes base y cambia los textos por los tuyos. Tiene lo que se hace en 1.º, así que puedes empezar el curso desde ahí.

Calentamiento

Antes de revisar, un ejercicio para desentumecer los dedos. Construye desde cero, en un archivo nuevo, una tarjeta de proyecto como las de tu galería. Intenta hacerlo primero sin mirar nada, y sólo después consulta el esquema para lo que no recuerdes.

<article class="tarjeta">
  <img src="img/proyecto.jpg" alt="…" width="800" height="600">
  <div class="tarjeta-texto">
    <h3>Nombre del proyecto</h3>
    <p>Una línea que lo describa.</p>
    <a href="proyecto.html">Ver proyecto</a>
  </div>
</article>
  1. Escribe el HTML.
  2. Dale estilo: fondo blanco, esquinas redondeadas, una sombra suave y relleno en el texto.
  3. Haz que la imagen ocupe todo el ancho de la tarjeta sin deformarse.
  4. Coloca tres tarjetas en una retícula que se adapte sola al ancho de la pantalla, con Grid.
  5. Haz que el enlace cambie de color con una transición al pasar el ratón.

Fíjate: apunta qué has tenido que buscar en el esquema. Esos son los puntos que más te conviene repasar en los apuntes de 1.º.

El entorno de trabajo

En 1.º empezaste a usar Visual Studio Code para escribir HTML y CSS. Este curso también escribirás JavaScript, así que merece la pena dejarlo bien configurado: un buen entorno te avisa de los errores, ordena el código por ti y te ahorra mucho tiempo.

A un editor como VS Code, con todo lo necesario para programar (resaltado de código, autocompletado, terminal, extensiones), se le llama IDE (Integrated Development Environment, entorno de desarrollo integrado).

Ajustes recomendados

Abre los ajustes con Ctrl + , (en Mac, Cmd + ,), busca cada uno por su nombre y actívalo:

Extensiones

Las extensiones añaden funciones al editor. Se instalan desde el icono de los cuatro cuadrados de la barra lateral. Con éstas tienes de sobra:

ExtensiónPara qué
Spanish Language PackPone los menús de VS Code en español.
Live ServerAbre tu web en el navegador y la recarga sola cada vez que guardas.
PrettierOrdena el código siempre igual (sangrías, comillas, espacios). Se combina con Format On Save.
Auto Rename TagAl cambiar una etiqueta de apertura, cambia también la de cierre.
Error LensMuestra los errores escritos en la misma línea donde están, en lugar de esconderlos en un panel.

Ojo: no instales extensiones a lo loco. Cada una consume memoria y algunas chocan entre sí. Si el editor empieza a ir lento o a hacer cosas raras, revisa cuáles tienes y desactiva las que no uses.

Escribir más rápido: Emmet

VS Code trae Emmet, un sistema de abreviaturas que se convierten en código al pulsar Tab:

EscribesObtienes
!La estructura básica completa de un documento HTML.
ul>li*3Una lista con tres elementos.
.tarjeta<div class="tarjeta"></div>
nav>a*4Un nav con cuatro enlaces.
img<img src="" alt="">

Todos los símbolos (>, +, *, {}, []…) los tienes explicados en «Introducción a HTML», de Programación I.

Atajos imprescindibles

AcciónWindowsMac
Comentar o descomentar la líneaCtrl + /Cmd + /
Mover la línea arriba o abajoAlt + ↑ / ↓Opción + ↑ / ↓
Duplicar la líneaMayús + Alt + ↓Mayús + Opción + ↓
Seleccionar la siguiente palabra igualCtrl + DCmd + D
Buscar un archivo del proyectoCtrl + PCmd + P

Qué es programar

Programar es escribir instrucciones para que un ordenador haga algo. Un programa es esa lista de instrucciones, escrita en un lenguaje que el ordenador entiende.

El ordenador tiene dos cualidades y un gran defecto:

  • Es rapidísimo: hace millones de operaciones por segundo.
  • Es totalmente obediente: hace exactamente lo que le dices, sin cansarse ni equivocarse.
  • Pero no entiende nada: no interpreta, no supone y no tiene sentido común. Si le das una instrucción ambigua o en el orden equivocado, hará algo absurdo sin pestañear.

Por eso, la parte difícil de programar no es aprender un lenguaje, sino aprender a pensar los pasos con precisión. Eso es lo que trabajamos en este tema, antes de escribir código.

¿HTML y CSS son programación?

No exactamente. HTML y CSS son lenguajes descriptivos: describen qué hay en la página y cómo se ve, pero no deciden nada ni hacen nada por sí solos. Un lenguaje de programación como JavaScript puede:

  • tomar decisiones: «si el usuario ha escrito su correo, envía el formulario; si no, muestra un aviso»;
  • repetir tareas: «crea una tarjeta por cada proyecto de la lista»;
  • reaccionar a lo que pasa: «cuando se pulse este botón, abre el menú».

El pensamiento computacional

Se llama así a la forma de abordar problemas que usan los programadores. Tiene cuatro ideas, y verás que como diseñador ya las usas sin saberlo:

IdeaQué esEn diseño
DescomposiciónDividir un problema grande en partes pequeñas.Diseñar una identidad: logotipo, paleta, tipografías, aplicaciones…
PatronesDetectar lo que se repite.Todas las tarjetas del portfolio tienen la misma estructura.
AbstracciónQuedarse con lo esencial e ignorar los detalles que no importan.Un pictograma: un hombre con muletas no tiene cara ni ropa, pero se entiende.
AlgoritmoEscribir los pasos ordenados para resolverlo.Las instrucciones de un manual de marca para aplicar el logotipo.

Idea clave: programar no es cosa de matemáticos. Es sobre todo ordenar ideas, ser preciso y tener paciencia para buscar errores. Son las mismas habilidades que usas al resolver un encargo de diseño.

Algoritmos y pseudocódigo

Un algoritmo es una serie de pasos ordenados y precisos para resolver un problema. Una receta de cocina, las instrucciones de montaje de un mueble o las indicaciones para llegar a un sitio son algoritmos.

Para que un ordenador pueda seguirlo, un algoritmo tiene que ser:

  • Preciso: cada paso dice exactamente qué hacer, sin ambigüedades.
  • Ordenado: los pasos van en un orden concreto, y cambiarlo cambia el resultado.
  • Finito: termina en algún momento.
  • Con una entrada (los datos de partida) y una salida (el resultado).

El problema de ser preciso

Imagina que le das estas instrucciones a un robot para dibujar una casa:

1. Coge un lápiz.
2. Dibuja un cuadrado.
3. Dibuja un triángulo encima.

Una persona lo entendería. Un robot, no: ¿de qué tamaño es el cuadrado? ¿Dónde lo dibujo? ¿«Encima» significa apoyado en el cuadrado o flotando? ¿De qué tamaño es el triángulo? Para un robot habría que escribir algo así:

1. Coge un lápiz con la mano derecha.
2. Pon la punta en el centro de la hoja.
3. Traza una línea recta de 5 cm hacia la derecha.
4. Gira 90° hacia arriba y traza otra línea de 5 cm.
5. Repite el paso 4 dos veces más: ya tienes un cuadrado.
6. …

Fíjate en el paso 5: en lugar de escribir tres veces lo mismo, decimos «repite». Es la primera señal de que, al programar, buscamos patrones.

Las tres piezas de cualquier algoritmo

Por complejo que sea, cualquier programa se construye combinando sólo tres estructuras:

EstructuraQué haceEjemplo cotidiano
SecuenciaPasos uno detrás de otro, en orden.Encender el ordenador, abrir el navegador, escribir la dirección.
DecisiónHacer una cosa u otra según una condición.Si llueve, coge el paraguas; si no, las gafas de sol.
RepeticiónRepetir pasos mientras se cumpla algo o un número de veces.Mientras queden platos sucios, friega uno.

Más adelante, en este mismo tema, veremos cómo se escribe cada una en JavaScript: las decisiones son los condicionales y las repeticiones, los bucles.

Pseudocódigo

Es escribir el algoritmo en lenguaje normal, pero con la estructura de un programa: una instrucción por línea, con palabras clave en mayúsculas para las decisiones y repeticiones, y con sangría para ver qué va dentro de qué. No es un lenguaje real: no hay reglas fijas, el objetivo es que se entienda.

Una decisión: elegir el color del texto según el fondo.

INICIO
  Pedir el color de fondo
  SI el fondo es oscuro ENTONCES
    Usar texto claro
  SI NO
    Usar texto oscuro
  FIN SI
  Mostrar el texto
FIN

Una repetición: colocar las fotos de una galería.

INICIO
  Número de foto = 1
  MIENTRAS queden fotos por colocar
    Colocar la foto en la galería
    Número de foto = número de foto + 1
  FIN MIENTRAS
FIN

Fíjate: Número de foto = número de foto + 1 no es una ecuación de matemáticas (sería imposible). En programación significa «coge el valor que tiene, súmale uno y guárdalo de nuevo». Es una de las ideas que más extrañan al empezar.

Para saber más (opcional)

Contenidos para ir más allá, si te sobra tiempo o te interesa el tema.

Diagramas de flujo

Un diagrama de flujo dibuja el algoritmo con formas unidas por flechas. Es muy visual y deja ver de un vistazo los caminos posibles. Cada forma tiene un significado:

FormaSignificado
ÓvaloInicio o fin.
RectánguloUna acción o proceso.
RomboUna decisión: una pregunta de sí o no, con dos salidas.
ParalelogramoEntrada o salida de datos (recibir o mostrar algo).
FlechaEl orden: hacia dónde sigue el algoritmo.

Este diagrama decide qué texto alternativo poner a una imagen, como vimos en Programación I:

Diagrama de flujo: decidir el texto alternativo de una imagen Inicio Recibir una imagen ¿Aportainformación? Sí No Describirlaen el alt alt="" Fin

Truco: para dibujar diagramas puedes usar papel y lápiz (lo más rápido para pensar), draw.io (gratuito, en el navegador) o FigJam si ya trabajas con Figma.

Repasa la unidad

En PDF

Ponlo en práctica: revisa tu web de 1.º

Revisa tu web punto por punto. Marca cada casilla cuando lo hayas comprobado o corregido; los enlaces te llevan al esquema o al apartado de los apuntes de 1.º donde se explica. Las casillas se borran al recargar la página.

HTML

CSS

Comprobación final

Entrega: tu web corregida y publicada de nuevo, con una lista breve de los cambios que has hecho. Será el punto de partida de todas las prácticas del curso.

Ponlo en práctica: algoritmos y entorno

Empieza sin ordenador y termina con el editor listo para todo el curso.

  1. El robot humano. Por parejas: cada uno dibuja en secreto una figura sencilla con formas geométricas y escribe las instrucciones para dibujarla. El compañero las sigue al pie de la letra, sin preguntar. ¿Dónde estaban las ambigüedades?
  2. Escribe en pseudocódigo un algoritmo para decidir si una imagen está lista para publicarse en tu web (¿pesa menos de 300 KB? ¿tiene alt?).
  3. Configura VS Code con los ajustes y las extensiones de este tema, y abre tu web de apuntes con Live Server.

Retos opcionales

  • Dibuja el diagrama de flujo de tu algoritmo de las imágenes.
  • Rehaz con Emmet la estructura de una página de tu web de apuntes: ¿cuánto tardas?

Comprueba: ¿tu pseudocódigo lo podría seguir alguien que no sabe nada del tema? Al guardar un archivo, ¿se ordena solo y se recarga el navegador?

02 · HTML5 y CSS3 avanzado

Damos un paso más sobre lo que viste en 1.º: semántica, selectores avanzados, formularios de interfaz, estructuras complejas como las imágenes interactivas, Flexbox y Grid a fondo, y buenas prácticas.

Semántica web

En 1.º viste las grandes zonas de una página: <header>, <nav>, <main>, <footer>… HTML tiene además muchos elementos pequeños que dicen qué es cada trozo de contenido. Usarlos bien hace la web más accesible, la posiciona mejor en los buscadores y, a menudo, te ahorra trabajo.

ElementoPara qué
<figure> y <figcaption>Una imagen, un gráfico o un fragmento de código con su pie.
<time datetime="2026-11-14">Una fecha u hora. El atributo la escribe en un formato que entienden las máquinas.
<blockquote> y <cite>Una cita larga y el título de la obra citada.
<address>Los datos de contacto de la persona o empresa responsable.
<mark>Texto resaltado, como con un rotulador fosforito.
<abbr title="…">Una abreviatura o sigla, con su significado.
<details> y <summary>Un bloque desplegable, sin JavaScript.
<dialog>Una ventana emergente. La usaremos en «Interactividad aplicada al diseño».

Un desplegable sin JavaScript

Las preguntas frecuentes de una web son el ejemplo perfecto de <details>: el navegador se encarga de abrir y cerrar, y funciona con el teclado.

<details>
  <summary>¿Hacéis encargos de ilustración?</summary>
  <p>Sí, escríbenos con la idea y las fechas, y te enviamos presupuesto.</p>
</details>
¿Hacéis encargos de ilustración?

Sí, escríbenos con la idea y las fechas, y te enviamos presupuesto.

Las regiones de la página

Los lectores de pantalla usan <header>, <nav>, <main>, <aside> y <footer> como puntos de referencia para saltar directamente de una zona a otra, igual que tú echas un vistazo a una página antes de leerla. Si hay más de un <nav>, ponles nombre para distinguirlos:

<nav aria-label="Principal">…</nav>
<nav aria-label="Redes sociales">…</nav>

Idea clave: antes de poner un <div>, pregúntate si existe una etiqueta que diga lo que es. Un <div> con aspecto de botón no es un botón: no se puede usar con el teclado ni lo anuncia un lector de pantalla. Un <button>, sí. Lo veremos a fondo en «Accesibilidad y proyecto final».

Selectores avanzados

En 1.º viste los selectores de elemento, clase, id y descendiente, y algunas pseudoclases como :hover. Con ellos se puede hacer casi todo, pero CSS tiene muchos más, y algunos te ahorran poner clases a cada elemento. Además, son los mismos que usarás en «JavaScript para interfaces» para encontrar elementos con JavaScript. Antes de verlos uno a uno, pruébalos: escribe un selector o elige un ejemplo, y verás qué elementos selecciona.

  • li 1
  • li 2
  • li 3 .destacado
  • li 4
  • li 5
  • li 6

p con un a dentro

Combinadores: según dónde está el elemento

Ya conoces el selector descendiente (un espacio). Hay tres combinadores más, que tienen en cuenta la posición exacta de un elemento respecto a otro:

CombinadorEjemploSelecciona
Descendiente (espacio)nav aLos a que estén dentro de un nav, a cualquier profundidad.
Hijo directo >nav > aSólo los a que estén justo en el primer nivel dentro del nav, no más adentro.
Hermano siguiente +h2 + pEl párrafo que va justo después de un h2. Muy útil para dar estilo a la entradilla de un artículo.
Hermanos siguientes ~h2 ~ pTodos los párrafos que van después de un h2, al mismo nivel.

Un uso clásico de +: separar los elementos de una lista sin dejar un hueco antes del primero.

li + li {
  margin-top: 12px; /* todos los li menos el primero */
}

Selectores de atributo

Los selectores de atributo eligen elementos según sus atributos HTML, sin tener que añadirles una clase. Se escriben entre corchetes:

a[target="_blank"]   { … }   /* enlaces que se abren en pestaña nueva */
a[href^="https"]     { … }   /* href que EMPIEZA por https */
a[href$=".pdf"]      { … }   /* href que TERMINA en .pdf */
a[href*="youtube"]   { … }   /* href que CONTIENE youtube */
img[alt=""]          { … }   /* imágenes decorativas */

Los símbolos funcionan como en un buscador: ^= «empieza por», $= «termina en» y *= «contiene». Por ejemplo, para avisar de qué enlaces descargan un PDF:

a[href$=".pdf"]::after {
  content: " (PDF)";
  font-size: 0.8em;
}

Idea clave: los selectores de atributo te permiten dar estilo según lo que el elemento es o hace (un enlace externo, una descarga), y así no tienes que acordarte de poner una clase cada vez que añades uno nuevo.

:nth-child() con fórmulas

En 1.º usamos :nth-child(2) para elegir el segundo elemento. Además de un número, acepta palabras y fórmulas, donde n va tomando los valores 0, 1, 2, 3…

li:nth-child(2)      { … }   /* el segundo */
li:nth-child(odd)    { … }   /* impares: 1, 3, 5… */
li:nth-child(even)   { … }   /* pares: 2, 4, 6… */
li:nth-child(3n)     { … }   /* cada tres: 3, 6, 9… */
li:nth-child(-n + 3) { … }   /* los tres primeros */

El uso más típico son las tablas cebra, con filas alternas de color para seguir mejor cada línea:

tr:nth-child(even) {
  background: #F2F1EC;
}
ProyectoAño
Identidad cafetería2025
Cartel festival2025
Revista nº 32026
Web del estudio2026

:not(): todos menos…

Selecciona los elementos que no cumplen una condición. Ahorra mucho código:

.menu a:not(.activo) {
  opacity: 0.6;
}

li:not(:last-child) {
  border-bottom: 1px solid #DEDBD2;   /* línea entre elementos, salvo tras el último */
}

:is(): agrupar

Una forma corta de agrupar selectores que comparten una parte. Las dos reglas siguientes son iguales:

header a, footer a { … }
:is(header, footer) a { … }

:has(): según lo que contiene

Es la pseudoclase más reciente y una de las más potentes: selecciona un elemento según lo que tiene dentro. Durante años fue imposible en CSS (se le llamaba «el selector padre») y había que recurrir a JavaScript.

/* Tarjetas que contienen una imagen */
.tarjeta:has(img) {
  padding: 0;
}

/* Formulario con algún campo no válido */
form:has(input:invalid) button {
  opacity: 0.5;
}

Truco: para entender qué selecciona un selector complicado, pégalo en el buscador del inspector (Ctrl + F dentro de la pestaña Elementos): te marca uno a uno los elementos que coinciden.

Pseudoclases de formularios

Con ellas se da estilo a los campos del «Formularios», de 1.º según su estado:

PseudoclaseCuándo se aplica
:focusCuando el campo está activo, escribiendo en él.
:checkedUna casilla o un botón de opción marcados.
:disabledUn campo desactivado.
:requiredUn campo obligatorio.
:invalid / :validUn campo cuyo contenido no cumple / sí cumple lo que se pide (por ejemplo, un correo sin @).
:user-invalidComo :invalid, pero sólo después de que la persona haya tocado el campo. Mejor para avisar de errores: no aparecen en rojo antes de empezar a escribir.
input:user-invalid {
  border-color: #B3261E;
}

Pseudoelementos

Las pseudoclases seleccionan elementos en un estado; los pseudoelementos seleccionan una parte de un elemento, o crean una caja nueva. Se escriben con dos pares de dos puntos:

PseudoelementoSelecciona
::before / ::afterUna caja nueva al principio / al final del contenido. Necesitan la propiedad content. Los tienes explicados en el «Para saber más» de esta unidad.
::first-letterLa primera letra, para hacer una capitular.
::first-lineLa primera línea del párrafo, sea cual sea el ancho de la pantalla.
::placeholderEl texto de ejemplo de un campo de formulario.
::markerLas viñetas o números de una lista.
::selectionEl texto que se selecciona con el ratón.
article p:first-of-type::first-letter {
  float: left;
  font-size: 3.2em;
  line-height: 1;
  margin-right: 6px;
  color: #546D78;
}

li::marker {
  color: #DA8A2F;
}

Idea clave: no hace falta memorizarlos todos. Quédate con la idea de que casi cualquier cosa se puede seleccionar sin añadir clases al HTML, y cuando lo necesites, vuelve a esta página o búscalo en MDN.

Pruébalo en tu web de apuntes: busca en tu hoja de estilos dos sitios donde un selector avanzado te ahorre una clase. Por ejemplo, li:not(:last-child) para separar los elementos del menú, o a[target="_blank"] para marcar los enlaces externos.

Formularios de interfaz

En 1.º aprendiste el HTML de los formularios («Formularios», de Programación I). Ahora toca diseñarlos: los campos que trae el navegador por defecto son poco atractivos y cambian de uno a otro. Un formulario bien diseñado es claro, cómodo en el móvil y avisa bien de los errores.

Pruébalo: escribe un correo sin @ y sal del campo. Estrecha la ventana: los campos se colocan en una columna solos.

Diseña todos los estados

Un campo de formulario no tiene un único aspecto, sino varios, y hay que diseñarlos todos (como en los estados de los componentes de Recursos):

EstadoSelectorQué debe comunicar
NormalinputQue es un campo donde se puede escribir: un borde visible, no sólo una línea gris muy clara.
Foco:focus-visibleDónde estás escribiendo. Imprescindible para quien usa el teclado.
Error:user-invalidQue algo está mal, y qué. El color solo no basta: acompáñalo de un texto.
Desactivado:disabledQue ahora no se puede usar.

Pautas para formularios cómodos

Texto sobre imagen

Uno de los recursos más usados en diseño web es escribir texto sobre una foto: portadas, tarjetas de proyectos, banners. Para que el texto se lea sea cual sea la imagen, se pone entre los dos una capa oscura o un degradado. Juntando lo que vimos en 1.º (position y z-index) con ::after, se hace sin añadir HTML:

::after es un pseudoelemento: una caja extra que CSS crea dentro de otro elemento, sin tocar el HTML. Necesita siempre la propiedad content, aunque sea vacía (content: ""). Si te interesa, en «Para saber más» lo tienes explicado a fondo, con más usos.

<article class="tarjeta">
  <img src="img/cartel.jpg" alt="Cartel del festival">
  <h3>Cartel para un festival</h3>
</article>
.tarjeta {
  position: relative;
}

.tarjeta::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(transparent 40%, rgba(0, 0, 0, 0.75));
}

.tarjeta h3 {
  position: absolute;
  left: 16px;
  bottom: 12px;
  z-index: 1;
  color: white;
}

Cartel para un festival

  1. La tarjeta lleva relative para ser la referencia.
  2. ::after crea una capa con inset: 0 que cubre toda la tarjeta, con un degradado de transparente a negro.
  3. El título se coloca con absolute abajo a la izquierda, y con z-index por encima de la capa.

Imágenes interactivas

En gráfica interactiva es muy habitual una imagen con zonas que se pueden pulsar: una infografía que explica cada parte, un plano con fichas de cada sala, una ilustración con detalles ocultos, el análisis de un cartel… Se hacen colocando puntos interactivos sobre la imagen con lo que ya sabes de position.

Hotspots con CSS

Esta técnica junta lo que has visto en este tema: la imagen va en un contenedor con relative, y cada punto interactivo es un elemento con absolute colocado con porcentajes. Como los porcentajes son relativos al tamaño de la imagen, los puntos se quedan en su sitio a cualquier tamaño de pantalla.

Esquema de un cartel con título, imagen, texto y logotipo

Pasa el ratón por los puntos, o recórrelos con la tecla Tab. Después, estrecha la ventana: los puntos siguen en su sitio.

<figure class="mapa">
  <img src="img/cartel.jpg" alt="Cartel de un festival de jazz" width="600" height="400">

  <button class="punto" style="--x: 25%; --y: 20%">
    1
    <span class="ficha">Título: tipografía de palo seco en negrita y gran tamaño.</span>
  </button>

  <button class="punto" style="--x: 72%; --y: 45%">
    2
    <span class="ficha">Imagen: formas geométricas en los colores de la marca.</span>
  </button>
</figure>
.mapa {
  position: relative;
  margin: 0;
}

.mapa img {
  display: block;
  width: 100%;
  height: auto;
}

.punto {
  position: absolute;
  left: var(--x);
  top: var(--y);
  transform: translate(-50%, -50%);   /* el centro del punto, justo en la coordenada */
  width: 28px;
  height: 28px;
  border-radius: 50%;
}

.ficha {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
  width: 200px;
  opacity: 0;                  /* oculta por defecto */
  visibility: hidden;
  transition: opacity 0.2s ease;
}

.punto:hover .ficha,
.punto:focus-visible .ficha {
  opacity: 1;
  visibility: visible;
}
  1. La <figure> lleva relative: es la referencia de los puntos.
  2. Cada punto se coloca con left y top en porcentaje. Las coordenadas se pasan como variables en el atributo style (--x, --y), así el CSS es el mismo para todos los puntos y sólo cambian los números. translate(-50%, -50%) centra el círculo justo sobre la coordenada, en lugar de colocar ahí su esquina.
  3. La ficha va dentro del punto, colocada encima con absolute, y empieza oculta.
  4. Con :hover y :focus-visible se muestra.

Cómo sacar las coordenadas

Para saber el porcentaje de un punto, abre la imagen en Photoshop, Illustrator o Figma, mira la posición del punto en píxeles y divídela entre el tamaño total: un punto a 180px de la izquierda en una imagen de 600px de ancho está en 180 / 600 = 0,3, es decir, en el 30%.

Ojo: los puntos son <button>, no <div>, para que se puedan alcanzar con el teclado y los lectores de pantalla sepan que se pueden pulsar. En el móvil no existe el :hover, y el comportamiento al tocar un botón varía según el navegador. Para que funcione igual en todas partes, con un toque para abrir y otro para cerrar, hará falta JavaScript; lo completaremos en «JavaScript para interfaces».

Flexbox y Grid a fondo

En 1.º aprendiste las bases de Flexbox y Grid. Ahora vamos con los patrones que más se repiten en las webs reales y con las propiedades que te permiten maquetar diseños más complejos.

Patrones con Flexbox

/* Logo a un lado, menú al otro */
.cabecera {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Empujar un elemento al final */
.menu .boton-contacto {
  margin-left: auto;
}

/* El botón, siempre abajo */
.tarjeta {
  display: flex;
  flex-direction: column;
}
.tarjeta .boton {
  margin-top: auto;
}

/* Etiquetas que saltan de línea */
.etiquetas {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

Grid con áreas: repaso

En 1.º viste grid-template-areas, que permite «dibujar» la maqueta con palabras. Recuerda su gran ventaja en responsive: para cambiar la distribución en otra pantalla, basta con redibujar las áreas dentro de una media query, sin tocar el HTML.

.pagina {
  display: grid;
  grid-template-areas: "cabecera" "principal" "lateral" "pie";
}

@media (min-width: 900px) {
  .pagina {
    grid-template-columns: 3fr 1fr;
    grid-template-areas:
      "cabecera  cabecera"
      "principal lateral"
      "pie       pie";
  }
}

auto-fill o auto-fit

En 1.º usamos repeat(auto-fit, minmax(…)) para la galería que se adapta sola. Existe una variante, auto-fill, y la diferencia sólo se nota cuando hay pocos elementos:

/* Con pocos elementos, auto-fill deja huecos vacíos al final... */
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));

/* ...y auto-fit estira los elementos para ocupar todo el ancho */
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));

auto-fill: los elementos mantienen su tamaño y quedan columnas vacías

1
2

auto-fit: las columnas vacías desaparecen y los elementos se estiran

1
2

Que nada se salga en pantallas muy estrechas

Con minmax(250px, 1fr), cada columna mide al menos 250px. Pero si la pantalla mide menos que eso, la columna se sale y aparece scroll horizontal. La solución es pedir «250px, o el 100 % si no caben»:

.galeria {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
  gap: 1rem;
}

Galerías con piezas de distintos tamaños

Si algunas piezas ocupan dos columnas o dos filas, quedan huecos. grid-auto-flow: dense hace que Grid rellene esos huecos con las piezas que vienen después, aunque altere un poco el orden:

.galeria {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  grid-auto-flow: dense;   /* rellena los huecos */
}

.galeria .ancha { grid-column: span 2; }
.galeria .alta  { grid-row: span 2; }
1 · ancha
2 · alta
3
4 · ancha
5
6
7
8

Ojo: dense cambia el orden visual, pero no el del HTML. Quien navega con el teclado o con lector de pantalla recorrerá las piezas en el orden original. Úsalo en galerías, donde el orden no importa, y no en contenidos que se leen en secuencia.

Buenas prácticas de maquetación

Una hoja de estilos crece muy deprisa. Si no se ordena desde el principio, a las pocas semanas nadie (ni siquiera tú) sabe dónde está cada cosa ni por qué un cambio rompe otra parte de la web. Estas costumbres son las que se piden en cualquier estudio.

Ordena la hoja de estilos por bloques

/* ===== 1. Variables ===== */
:root { … }

/* ===== 2. Base: estilos generales ===== */
*, *::before, *::after { box-sizing: border-box; }
body { … }
img { max-width: 100%; height: auto; display: block; }

/* ===== 3. Maquetación: las grandes zonas ===== */
.cabecera { … }
.pie { … }

/* ===== 4. Componentes: piezas que se repiten ===== */
.boton { … }
.tarjeta { … }

/* ===== 5. Páginas concretas ===== */
.portada-hero { … }

Las media queries de cada componente van justo debajo de él: así, todo lo que afecta a la tarjeta está junto.

Nombres de clases que se entienden

  • Por su función, no por su aspecto: .aviso mejor que .texto-rojo.
  • En minúsculas y con guiones: .tarjeta-proyecto.
  • Las partes de un componente llevan su nombre delante: .tarjeta, .tarjeta-imagen, .tarjeta-titulo. Y las variantes, con dos guiones: .boton--secundario. Esta forma de nombrar, muy extendida, se basa en una metodología llamada BEM.

Selectores sencillos

  • Da estilo con clases, no con id: un id pesa tanto en la especificidad que luego cuesta sobrescribirlo.
  • Evita anidar demasiado: .menu a es mejor que header nav ul li a, que se rompe en cuanto cambias el HTML.
  • No uses !important para arreglar un conflicto: busca por qué otra regla gana (con el inspector) y corrígelo ahí.

Variables como sistema de diseño

En 1.º usamos las variables para no repetir colores. En 2.º las convertimos en un sistema de diseño: un conjunto pequeño de decisiones (colores, espacios, radios) del que sale todo lo demás. Es lo que en un manual de identidad corporativa son la paleta y la retícula.

:root {
  --color-fondo: #F7F6F2;
  --color-texto: #21231F;
  --color-suave: #5B5D57;
  --color-acento: #546D78;

  --espacio: 1rem;
  --espacio-s: calc(var(--espacio) / 2);    /* 0.5rem */
  --espacio-l: calc(var(--espacio) * 2);    /* 2rem */
  --espacio-xl: calc(var(--espacio) * 4);   /* 4rem */

  --radio: 8px;
}

Idea clave: nombra los colores por su función (--color-fondo, --color-acento), no por su aspecto (--verde, --blanco). Si mañana el acento pasa a ser azul, --verde dejaría de tener sentido; y en el modo oscuro, el «fondo» ya no será blanco.

De Figma al código: un sistema de diseño completo también incluye los componentes y sus variantes. Cómo se construye en Figma y cómo se traduce a CSS, en Recursos › Componentes y sistemas de diseño.

calc(): operaciones con medidas

calc() hace sumas, restas, multiplicaciones y divisiones con medidas, incluso mezclando unidades distintas, algo imposible de calcular a mano porque depende de la pantalla:

.contenido {
  width: calc(100% - 2rem);
  max-width: calc(65ch + var(--espacio-l));
}

.cabecera-fija + main {
  padding-top: calc(var(--alto-cabecera) + var(--espacio));
}

Los signos + y - necesitan espacios a los lados: calc(100% - 2rem) funciona, calc(100%-2rem) no.

Valor de respaldo

.tarjeta {
  border-radius: var(--radio, 4px);   /* si --radio no existe, usa 4px */
}

Variables locales

Una variable no tiene por qué estar en :root. Si la defines en un elemento, sólo vale para él y sus hijos. Esto permite crear variantes de un componente cambiando sólo un valor:

.boton {
  --color-boton: var(--color-acento);
  background: var(--color-boton);
  border: 2px solid var(--color-boton);
  color: white;
}

.boton--secundario {
  --color-boton: #DA8A2F;
}

Es la misma técnica que usamos en los hotspots de las imágenes interactivas, donde cada punto recibía sus coordenadas con --x y --y.

Para saber más (opcional)

Contenidos para ir más allá, si te sobra tiempo o te interesa el tema.

Pseudoelementos: ::before y ::after

Los pseudoelementos permiten añadir contenido desde CSS, sin escribirlo en el HTML. ::before crea un elemento al principio del contenido de otro, y ::after, al final. Se usan para detalles decorativos que no aportan información.

<a class="externo" href="https://www.w3.org/">W3C</a>
.externo::after {
  content: " ↗";
}

La propiedad content es obligatoria: sin ella, el pseudoelemento no existe. Puede llevar texto, un símbolo o quedarse vacía (content: "") cuando sólo quieres una forma.

Formas decorativas

Con content: "" y display: block, el pseudoelemento se convierte en una caja a la que puedes dar tamaño y color. Por ejemplo, una línea corta sobre cada título:

h2::before {
  content: "";          /* vacío, pero obligatorio */
  display: block;
  width: 40px;
  height: 4px;
  background: #546D78;
  margin-bottom: 12px;
}

Proyectos recientes

Fíjate: en esta web hay pseudoelementos por todas partes: las comillas grandes de la cita de Epicteto, el símbolo ./ delante de cada enlace del terminal de la portada o la palabra «Resultado» de estas cajas de ejemplo. Abre el inspector y búscalos: aparecen como ::before y ::after dentro de cada elemento.

Ojo: el contenido de ::before y ::after no se puede seleccionar ni copiar, y algunos lectores de pantalla no lo leen. Úsalos sólo para decoración, nunca para información importante.

Cuando z-index no funciona

A veces pones z-index: 9999 y el elemento sigue quedando debajo. Casi siempre es porque está dentro de otro elemento que tiene su propio z-index (o una transparencia, un transform…). Ese padre crea un contexto de apilamiento: un grupo cerrado de capas.

Es como un grupo de capas en Photoshop: puedes ordenar como quieras las capas dentro del grupo, pero ninguna puede salir de él. Si el grupo entero está por debajo de otra capa, todo su contenido también lo estará, por alto que sea su número.

Truco: si un z-index no hace caso, sube por sus antepasados en el inspector buscando cuál tiene z-index, opacity menor que 1 o transform. El número hay que subirlo en ese elemento, no en el hijo.

El mapa de imagen clásico: <map> y <area>

Antes de los hotspots con CSS, la forma de hacer zonas clicables en una imagen era el mapa de imagen de HTML. Conviene conocerlo porque aparece en webs antiguas.

HTML tiene desde sus inicios una forma de definir zonas enlazables sobre una imagen. Se describen con coordenadas en píxeles: rectángulos (rect: esquina superior izquierda e inferior derecha), círculos (circle: centro y radio) o polígonos (poly: la lista de vértices).

<img src="img/plano.jpg" alt="Plano de la escuela" usemap="#plano" width="800" height="500">

<map name="plano">
  <area shape="rect"   coords="40,30,260,180"  href="aulas.html"     alt="Aulas">
  <area shape="circle" coords="520,240,70"     href="biblioteca.html" alt="Biblioteca">
  <area shape="poly"   coords="600,350,780,350,780,480,650,480" href="taller.html" alt="Taller">
</map>

El atributo usemap de la imagen enlaza con el name del mapa (con # delante), y cada <area> lleva su enlace y su alt.

Ojo: el mapa clásico no es responsive. Las coordenadas están en píxeles de la imagen original: si la imagen se ve más pequeña en el móvil, las zonas no se encogen con ella y quedan descolocadas. Además, no se les puede dar estilo (no se ven, ni se puede resaltar la zona). Hoy se usa la técnica anterior.

Repasa la unidad

En PDF

Ponlo en práctica

Partimos de la web de apuntes que pusiste a punto en «Introducción a la programación y al entorno».

  1. Revisa la semántica: cambia por la etiqueta adecuada los <div> que lo merezcan (<figure>, <time>, <address>…) y añade una sección de preguntas frecuentes con <details>.
  2. Diseña el formulario de dudas con todos sus estados: normal, foco, error y desactivado.
  3. Cambia la caja de color de las tarjetas de tu índice de temas por una imagen, y pon el título sobre ella: capa con degradado y título encima.
  4. Haz una captura de una web que te guste y crea con ella una imagen interactiva con al menos cuatro hotspots que expliquen sus partes: cabecera, menú, contenido principal, pie…
  5. Ordena tu hoja de estilos por bloques y pasa los colores, espacios y radios a un sistema de variables.

Retos opcionales

  • Usa al menos dos selectores avanzados que te ahorren clases: por ejemplo, li:not(:last-child) o a[target="_blank"].
  • Pon una línea decorativa corta encima de cada <h2> con ::before.

Comprueba: ¿se lee el título de la tarjeta sobre una imagen muy clara? ¿Los hotspots siguen en su sitio al estrechar la ventana? ¿Puedes recorrer los hotspots y el formulario con la tecla Tab, y se ve siempre dónde está el foco?

03 · Responsive Web Design

La web, en cualquier pantalla: mobile first como método de trabajo, media queries más allá del ancho, tipografía fluida e imágenes que se adaptan.

Qué es una media query

Una media query es una pregunta que el CSS le hace a la pantalla: «¿mides al menos 700px de ancho?». Si la respuesta es sí, se aplican las reglas que van dentro; si no, se ignoran. Así, con un mismo HTML, la página cambia de distribución según el espacio que tiene.

.tarjetas {
  display: grid;
  gap: 16px;
}

@media (min-width: 700px) {
  .tarjetas {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

Fuera de la media query van los estilos para el móvil: una sola columna. Dentro, sólo lo que cambia cuando hay más espacio: tres columnas. Ese ancho en el que cambia el diseño se llama punto de ruptura (breakpoint).

Para que funcione en el móvil, la página tiene que llevar en el <head> la etiqueta <meta name="viewport" content="width=device-width, initial-scale=1">. Sin ella, el móvil muestra la web como si fuera una pantalla de ordenador, en miniatura.

En este ejemplo, la caja de resultado mide más de 500px en el ordenador y menos en el móvil. Cambia 500px por 2000px y mira qué pasa.

Pruébalo: abre cualquier web en el inspector con el modo de dispositivo (Ctrl + Mayús + M) y cambia el ancho poco a poco. Los saltos que ves en el diseño son sus media queries.

Mobile first y media queries

Trabajar mobile first es escribir primero los estilos del móvil y después, con min-width, los cambios para pantallas más grandes. Si lo viste en 1.º, esto será un repaso; aquí lo convertimos en un método de trabajo.

Diseñar desde el móvil

Mobile first no es sólo un orden en el CSS: es una forma de pensar el diseño. En una pantalla pequeña no cabe todo, así que obliga a decidir qué es lo importante. Por eso conviene bocetar primero la versión de móvil en Figma y después ampliarla, y no al revés.

Desktop first (max-width)Mobile first (min-width)
Se empieza porEl diseño de ordenador, y se va quitandoEl diseño de móvil, y se va añadiendo
El móvil cargaTodos los estilos de ordenador, más los que los deshacenSólo los estilos que necesita
Resultado habitualMuchas reglas para «arreglar» el móvilUn CSS más corto y fácil de mantener

Dónde poner los puntos de ruptura

Un error frecuente es poner los puntos de ruptura en los anchos de dispositivos concretos («el del iPhone», «el del iPad»). Hay cientos de pantallas distintas, y cada año salen nuevas. La regla es otra: el punto de ruptura lo decide el contenido.

  1. Abre tu web en el inspector con el modo de dispositivo (Ctrl + Mayús + M).
  2. Ve ensanchando la ventana poco a poco desde el ancho del móvil.
  3. En cuanto algo se vea mal (líneas de texto demasiado largas, tarjetas enormes, mucho espacio vacío), ahí va un punto de ruptura.

Con dos o tres puntos de ruptura suele bastar. Muchos equipos los escriben en em (48em son 768px con la letra por defecto), porque así respetan el tamaño de letra que haya elegido cada persona en su navegador.

Media queries más allá del ancho

Las media queries no sólo preguntan por el ancho. También pueden preguntar cómo se usa el dispositivo:

Media querySe cumple cuando…Para qué
(hover: hover)El dispositivo tiene un ratón que puede pasar por encima.Poner efectos de :hover sólo donde existen. En el móvil, un :hover puede quedarse «enganchado» tras tocar.
(pointer: coarse)Se maneja con el dedo, que es poco preciso.Hacer más grandes los botones y los enlaces.
(orientation: landscape)La pantalla está en horizontal.Ajustar galerías o vídeos al girar el móvil.
(prefers-color-scheme: dark)La persona tiene activado el modo oscuro.El modo oscuro (en «Para saber más»).
(prefers-reduced-motion: reduce)Prefiere menos movimiento.Quitar o suavizar animaciones («Animación con CSS»).
/* Sólo con ratón */
@media (hover: hover) {
  .tarjeta:hover {
    transform: translateY(-6px);
  }
}

Lista de comprobación responsive

Fíjate: en Recursos tienes un ejemplo completo de una web diseñada en Figma y maquetada con una retícula de 12 columnas que pasa a 4 en el móvil.

Tipografía fluida con clamp()

Con las media queries, los tamaños cambian a saltos: 2rem en el móvil y, a partir de 900px, 3rem. Con clamp() cambian de forma continua, creciendo poco a poco con la pantalla, pero sin pasarse de unos límites.

h1 {
  font-size: clamp(2rem, 1rem + 4vw, 4rem);
  /*              mínimo  ideal       máximo */
}

clamp() recibe tres valores:

  1. El mínimo: nunca será más pequeño (en el móvil).
  2. El valor ideal, que depende del ancho de la pantalla (lleva vw).
  3. El máximo: nunca será más grande (en un monitor enorme).

Título fluido

Estrecha y ensancha la ventana: el título crece y decrece sin saltos.

Ojo: ¿por qué 1rem + 4vw y no sólo 5vw? Porque un tamaño hecho sólo con vw depende únicamente de la pantalla, e ignora el zoom del navegador: si alguien con baja visión amplía la página, el texto no crece. Sumar una parte en rem mantiene el zoom funcionando.

clamp() no es sólo para texto. Sirve para cualquier medida, como los espacios:

.seccion {
  padding: clamp(1.5rem, 5vw, 5rem);
}

Imágenes: aspect-ratio y object-fit

Proporción fija: aspect-ratio

Indica la proporción de una caja (ancho / alto). El navegador calcula el alto a partir del ancho, así que la caja mantiene su forma en cualquier pantalla.

.video,
.tarjeta img {
  aspect-ratio: 16 / 9;
}

.avatar {
  aspect-ratio: 1;   /* cuadrado */
}

Encajar la imagen: object-fit

Si una imagen tiene una proporción distinta de la caja que la contiene, por defecto se deforma para rellenarla. object-fit decide qué hacer en su lugar:

fill (por defecto): se deforma
contain: cabe entera, deja huecos
cover: rellena y recorta

La imagen original es horizontal; las cajas, cuadradas. Para galerías y tarjetas, casi siempre querrás cover:

.galeria img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;          /* recorta sin deformar */
  object-position: center;    /* qué parte se conserva al recortar */
}

Truco: con object-position eliges qué parte de la imagen se conserva al recortar: top para no cortar las cabezas en un retrato, left, 30% 20%… Es como mover la imagen dentro del marco en InDesign.

Para saber más (opcional)

Contenidos para ir más allá, si te sobra tiempo o te interesa el tema.

Modo oscuro paso a paso

Los sistemas operativos y los navegadores permiten elegir entre modo claro y oscuro, y CSS puede saber cuál ha elegido cada persona. Si tus colores están organizados en variables, crear el modo oscuro consiste en redefinir esas variables, sin tocar el resto del CSS.

Paso 1. Todos los colores en variables

Revisa tu hoja de estilos: no puede quedar ningún color escrito a mano fuera de :root. Cada color que uses (fondos, textos, bordes, sombras…) debe salir de una variable.

Y muy importante: nombra las variables por su función (--color-fondo, --color-texto, --color-acento), no por su aspecto (--blanco, --verde). En el modo oscuro el «fondo» ya no será blanco, y una variable llamada --blanco que vale negro sería un lío.

:root {
  --color-fondo: #F7F6F2;
  --color-superficie: #FFFFFF;
  --color-texto: #21231F;
  --color-suave: #5B5D57;
  --color-linea: #DEDBD2;
  --color-acento: #546D78;
}

body {
  background: var(--color-fondo);
  color: var(--color-texto);
}

.tarjeta {
  background: var(--color-superficie);
  border: 1px solid var(--color-linea);
}

Paso 2. Redefinir las variables en modo oscuro

La media query prefers-color-scheme: dark se cumple cuando el sistema de la persona está en modo oscuro. Dentro, se dan nuevos valores a las mismas variables:

@media (prefers-color-scheme: dark) {
  :root {
    --color-fondo: #171815;
    --color-superficie: #1E1F1B;
    --color-texto: #EDEBE4;
    --color-suave: #A3A69B;
    --color-linea: #33352E;
    --color-acento: #9FB9C4;   /* el verde, más claro para que contraste */
  }
}

Y ya está: como todo el CSS usa las variables, todo cambia a la vez.

Modo claro

Fondo claro, texto oscuro y el verde original.

Botón
Modo oscuro

Las mismas variables con otros valores.

Botón

Paso 3. Avisar al navegador

Los elementos que dibuja el propio navegador (campos de formulario, casillas, barras de scroll) no usan tus variables. Con esta línea, el navegador los adapta también al modo oscuro:

:root {
  color-scheme: light dark;
}

Paso 4. Revisar las imágenes

Un logotipo oscuro desaparece sobre un fondo oscuro. Con la etiqueta <picture>, que elige entre varias imágenes según una condición, puedes cambiar de archivo según el modo:

<picture>
  <source srcset="img/logo-claro.svg" media="(prefers-color-scheme: dark)">
  <img src="img/logo-oscuro.svg" alt="Estudio Ebro" width="160" height="40">
</picture>

Y las fotos muy luminosas pueden deslumbrar en modo oscuro. Se pueden atenuar un poco con un filtro (lo tienes en el bloque de filtros de este mismo apartado):

@media (prefers-color-scheme: dark) {
  img:not([src$=".svg"]) {
    filter: brightness(0.9);   /* fotos un poco menos brillantes */
  }
}

Paso 5. Probarlo

No hace falta cambiar el modo de tu ordenador cada vez. En Chrome, abre el inspector, pulsa Ctrl + Mayús + P (en Mac, Cmd + Mayús + P), escribe dark y elige Emulate CSS prefers-color-scheme: dark.

Ojo: un buen modo oscuro no es invertir los colores. Evita el negro puro (#000) de fondo y el blanco puro de texto: el contraste extremo cansa la vista. Usa grises muy oscuros y blancos rotos. Los colores de acento suelen necesitar una versión más clara y menos saturada. Y las sombras casi no se ven sobre fondo oscuro: para separar capas, funcionan mejor las superficies un poco más claras.

Fíjate: el modo oscuro de esta misma web está hecho exactamente así. Muchas webs añaden además un botón para cambiar de modo manualmente; eso necesita JavaScript, y lo tienes en «Para saber más» de «JavaScript para interfaces».

Altura de pantalla en el móvil: dvh

En 1.º vimos vw y vh. 100vh debería ser una pantalla de alto, pero en el móvil hay un problema: las barras del navegador (la de direcciones arriba, la de botones abajo) aparecen y desaparecen al hacer scroll, y 100vh se calcula como si no estuvieran. Resultado: una portada de 100vh queda un poco más alta que la pantalla y el botón de abajo queda escondido.

La solución es la unidad dvh (dynamic viewport height), que se ajusta en cada momento al espacio realmente visible:

.portada {
  min-height: 100vh;    /* por si el navegador no conoce dvh */
  min-height: 100dvh;   /* altura visible real, también en el móvil */
}

Escribir la propiedad dos veces es un truco habitual: si el navegador no entiende la segunda línea, la ignora y se queda con la primera.

Más unidades de pantalla: svh, lvh, vmin y vmax
UnidadAltura de referencia
svh (small)La pantalla con las barras del navegador visibles: el espacio más pequeño.
lvh (large)La pantalla con las barras escondidas: el espacio más grande.
dvh (dynamic)Se ajusta en cada momento al espacio realmente visible.

Otras dos unidades útiles: vmin (el 1 % del lado más corto de la pantalla) y vmax (el 1 % del lado más largo). Sirven para elementos que deben verse proporcionados tanto en vertical como en horizontal, como un logotipo grande en una portada.

Imágenes responsive: srcset y <picture>

Con max-width: 100% la imagen se ve más pequeña en el móvil, pero se descarga igual de grande. Un móvil con datos móviles no debería bajarse una foto de 2000px para mostrarla a 400px. HTML tiene dos herramientas para servir a cada pantalla la imagen adecuada.

Mismo encuadre, distintos tamaños: srcset

Exportas la misma imagen a varios anchos y se los ofreces todos al navegador, que elige el más adecuado según la pantalla y su densidad de píxeles:

<img
  src="img/portada-800.jpg"
  srcset="img/portada-400.jpg 400w,
          img/portada-800.jpg 800w,
          img/portada-1600.jpg 1600w"
  sizes="(min-width: 900px) 50vw, 100vw"
  alt="Portada del proyecto"
  width="1600" height="900">
  • srcset — la lista de archivos con su ancho real en píxeles (400w = 400px de ancho).
  • sizes — cuánto va a ocupar la imagen en pantalla: aquí, la mitad de la ventana (50vw) a partir de 900px, y todo el ancho (100vw) por debajo.
  • src — la imagen por defecto, por si el navegador no entiende lo anterior.

Distinto encuadre: <picture>

A veces no basta con cambiar el tamaño: en el móvil querrías un encuadre distinto (vertical, más cerrado). Es lo que se llama dirección de arte, y se hace con <picture>:

<picture>
  <source media="(min-width: 800px)" srcset="img/cartel-horizontal.jpg">
  <img src="img/cartel-vertical.jpg" alt="Cartel del festival" width="800" height="1200">
</picture>

El navegador recorre los <source> en orden y usa el primero cuya condición se cumpla. Si no se cumple ninguna, usa el <img> del final, que es obligatorio y lleva el alt.

<picture> también sirve para ofrecer formatos modernos y más ligeros, con uno clásico de respaldo:

<picture>
  <source type="image/avif" srcset="img/foto.avif">
  <source type="image/webp" srcset="img/foto.webp">
  <img src="img/foto.jpg" alt="…" width="1200" height="800">
</picture>

Idea clave: srcset cuando es la misma imagen a distintos tamaños (lo más habitual); <picture> cuando necesitas un encuadre o un formato distinto. Y en los dos casos, el alt, width y height van siempre en el <img>.

Container queries

Las media queries preguntan por el tamaño de la pantalla. Pero una misma tarjeta puede aparecer en una columna estrecha lateral y en una zona principal ancha, en la misma pantalla. Lo que le importa a la tarjeta no es la pantalla, sino el espacio que tiene ella.

Las container queries resuelven esto: un componente cambia según el tamaño de su contenedor. Es el gran avance del responsive de los últimos años.

<div class="zona-tarjeta">
  <article class="tarjeta">
    <img src="img/cartel.jpg" alt="…">
    <div>
      <h3>Cartel para un festival</h3>
      <p>Ilustración y tipografía.</p>
    </div>
  </article>
</div>
.zona-tarjeta {
  container-type: inline-size;
}

.tarjeta {
  display: grid;
  gap: 1rem;
}

@container (min-width: 400px) {
  .tarjeta {
    grid-template-columns: 150px 1fr;
  }
}

La misma tarjeta, en un contenedor estrecho…

Cartel para un festival

Ilustración y tipografía.

…y en uno ancho

Cartel para un festival

Ilustración y tipografía.

  1. Al contenedor se le da container-type: inline-size, que significa «se puede consultar mi ancho».
  2. Se escriben los estilos del componente para el caso pequeño.
  3. Con @container (min-width: …) se añaden los cambios para cuando el contenedor es grande. Se escribe igual que una media query.

Idea clave: usa media queries para la estructura general de la página (cuántas columnas tiene, si aparece el menú lateral) y container queries para los componentes que se reutilizan en sitios distintos (tarjetas, bloques de texto con imagen). Así cada componente funciona bien dondequiera que lo pongas.

Repasa la unidad

En PDF

Ponlo en práctica

Seguimos con tu web de apuntes.

  1. Revisa tu CSS: ¿es mobile first? Si usas max-width, pásalo a min-width, empezando por los estilos del móvil.
  2. Busca tus puntos de ruptura ensanchando la ventana poco a poco, como en este tema, y apunta en un comentario por qué está cada uno.
  3. Pon el tamaño de los títulos con clamp(), con una parte en rem. Comprueba que el texto sigue creciendo al hacer zoom.
  4. Iguala las imágenes de las tarjetas de temas con aspect-ratio y object-fit: cover.
  5. Mete los efectos de :hover dentro de @media (hover: hover).

Retos opcionales

  • Crea el modo oscuro de tu web siguiendo los cinco pasos de «Para saber más».
  • Usa <picture> para mostrar un encuadre distinto de la imagen de portada en el móvil.

Comprueba: pasa la lista de comprobación responsive de este tema, ancho a ancho.

04 · Animación con CSS

Dar movimiento a la interfaz sólo con CSS: transiciones, microinteracciones, animaciones con @keyframes, SVG que se dibujan solos y efectos visuales. Todavía sin JavaScript.

Transiciones y transformaciones

En 1.º viste las transiciones y dos transformaciones, translate y scale. Son la base de casi todo el movimiento de una interfaz, así que vamos a conocerlas a fondo.

Repaso: las partes de una transición

Cuando una propiedad cambia, por ejemplo al pasar el ratón por encima, el cambio es instantáneo. Una transición lo hace gradual: el navegador calcula los pasos intermedios.

.boton {
  transition: transform 0.5s ease;
}
.boton:hover {
  transform: scale(1.1);
}
ParteQué es
transformLa propiedad que se anima. Con all se animan todas las que cambien.
0.5sLa duración, en segundos (s) o milisegundos (ms).
easeLa curva: cómo se reparte la velocidad durante el cambio.

Recuerda: la transición se pone en el estado normal (.boton), que se aplica siempre. Si la pones en :hover, sólo existe mientras el ratón está encima: al quitarlo, el botón vuelve de golpe.

Las curvas

Dos movimientos de la misma duración pueden sentirse muy distintos según cómo se reparta la velocidad.

CurvaCómo se mueve
linearSiempre a la misma velocidad. Queda mecánico.
easeArranca suave, acelera y frena al final. Es la que se usa si no pones ninguna.
ease-inEmpieza lenta y termina rápida. Va bien para cosas que salen.
ease-outEmpieza rápida y frena al final. Va bien para cosas que entran.
ease-in-outLenta al principio y al final. Va bien para movimientos de ida y vuelta.
cubic-bezier()Una curva propia. Se diseña en cubic-bezier.com y se copian los números.

Compáralas: todas las bolas tardan lo mismo en llegar. Cambia la duración o prueba otra curva en el código.

Las funciones de transform

FunciónQué hace
translate(x, y)Desplaza. Con porcentajes, se mide respecto al propio elemento: translate(-50%, -50%) lo mueve la mitad de su tamaño.
scale(1.1)Agranda o encoge. scale(-1, 1) lo refleja como en un espejo.
rotate(45deg)Gira, en grados. 1turn es una vuelta entera.
skew(10deg)Inclina, como la herramienta Distorsionar de Illustrator.

Se pueden combinar varias, separadas por espacios. El orden importa: se aplican de derecha a izquierda.

Con transform-origin se elige el punto desde el que se transforma: por defecto es el centro, pero un giro desde una esquina (transform-origin: top left) da un efecto muy distinto.

Qué animar y qué no

Se puede animar casi todo lo que tiene un número o un color: transform, opacity, background-color, border-radius, width… Lo que no se puede animar es display: un elemento aparece o desaparece de golpe.

Para el navegador no todas las propiedades cuestan lo mismo. Animar width, height, top o margin le obliga a recolocar toda la página en cada fotograma, y la animación va a tirones, sobre todo en el móvil. En cambio, transform y opacity se animan con la tarjeta gráfica y van siempre fluidas.

Idea clave: para mover, usa transform: translate(), no top ni margin. Para aparecer y desaparecer, opacity. Para crecer, scale(), no width.

Microinteracciones

Son las pequeñas respuestas de la interfaz a lo que hace la persona: un botón que cambia al pasar el ratón y se hunde al pulsarlo, un enlace que se subraya, una tarjeta que se levanta. Duran décimas de segundo, pero hacen que la web se sienta viva y ayudan a entender qué se puede pulsar.

Los estados de un elemento

EstadoCuándo se aplica
:hoverCon el ratón encima.
:activeMientras se pulsa.
:focus-visibleAl llegar con el teclado (tecla Tab).
:disabledCuando no se puede usar.

Pasa el ratón, pulsa y recorre los elementos con Tab:

Pautas

  • Rápidas: entre 0,15 y 0,3 segundos. Si tardan más, la web parece lenta.
  • Coherentes: todos los botones de la web reaccionan igual.
  • No sólo con ratón: en el móvil no existe :hover, así que nada importante puede depender de él.
  • El foco, siempre visible: puedes cambiar su aspecto con :focus-visible, pero nunca quitarlo.

Idea clave: una microinteracción responde a algo que hace la persona. Si nadie la ha provocado, no es una microinteracción: es decoración.

Animaciones con @keyframes

Las transiciones de 1.º animan un cambio entre dos estados (normal y :hover). Las animaciones van más allá: se reproducen solas, pueden tener muchos pasos intermedios y repetirse. Se crean en dos partes:

  1. Con @keyframes se define la animación y se le da un nombre: los fotogramas clave, como en un programa de animación.
  2. Con la propiedad animation se aplica a un elemento.
@keyframes aparecer {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

h1 {
  animation: aparecer 0.8s ease-out;
}

from y to son el principio y el final. Para más pasos, se usan porcentajes:

@keyframes latido {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.25); }
  100% { transform: scale(1); }
}

.punto {
  animation: latido 1.5s ease-in-out infinite;
}
Un punto que late, como los hotspots de «HTML5 y CSS3 avanzado»

Las partes de animation

La propiedad animation junta varios valores en una línea:

.punto {
  animation: latido 1s ease-in-out infinite alternate;
}
ParteQué es
latidoEl nombre de la animación. Tiene que ser igual que en @keyframes.
1sLo que dura una vuelta.
ease-in-outLa curva, igual que en las transiciones.
infiniteCuántas veces se repite. También puede ser un número: 3.
alternateVa y vuelve. Sin esto, al acabar cada vuelta salta de golpe al principio.

Con porcentajes no hace falta alternate si el primer paso y el último son iguales, como en el latido de arriba: el bucle no salta.

Cuidado con los elementos que ya tienen transform

Si un elemento ya tenía un transform, por ejemplo un giro, la animación lo sustituye y el elemento pierde su giro mientras se anima. Para que no pase, repite el giro en cada paso:

.etiqueta {
  transform: rotate(-8deg);
  animation: vaiven 1s ease-in-out infinite alternate;
}

@keyframes vaiven {
  from { transform: rotate(-8deg) translateX(0); }
  to   { transform: rotate(-8deg) translateX(10px); }
}

Respetar a quien prefiere menos movimiento

A algunas personas el movimiento en pantalla les provoca mareos, náuseas o dolor de cabeza (por ejemplo, con trastornos vestibulares), y a otras les impide concentrarse en el contenido. Por eso los sistemas operativos tienen una opción para reducir el movimiento, y CSS puede detectarla con prefers-reduced-motion.

Escribe tus animaciones dentro de una media query que sólo se cumple si la persona no ha pedido reducir el movimiento:

/* Sólo si no se ha pedido menos movimiento */
@media (prefers-reduced-motion: no-preference) {
  h1 {
    animation: aparecer 0.8s ease-out;
  }

  .punto {
    animation: latido 1.5s ease-in-out infinite;
  }
}

Secuencias de entrada

Es un recurso muy usado en motion graphics y en las portadas de muchas webs: al cargar, los elementos aparecen uno detrás de otro. Se hace con una misma animación y un retraso distinto para cada elemento.

Cuando hay dos tiempos, el primero es la duración y el segundo el retraso. Para volver a ver la secuencia, cambia cualquier cosa en el código.

Fíjate en el both: hace que cada elemento esté invisible mientras espera su turno y que se quede como en el último paso al terminar. Sin él, el elemento se ve un momento, desaparece y luego entra.

Varias formas de entrar

No todos los elementos tienen que entrar igual. Crea varias @keyframes y cambia lo que hay en from:

EntradaEn from
Desde abajotransform: translateY(40px)
Desde un ladotransform: translateX(-100%)
Creciendotransform: scale(0)
Girandotransform: rotate(-180deg) scale(0)
Fundidoopacity: 0

Entrar y quedarse en movimiento

Un elemento puede tener dos animaciones a la vez, separadas por una coma. Por ejemplo, entrar y después quedarse latiendo. La segunda lleva un retraso mayor que lo que tarda la primera:

.logo {
  animation: entra 0.8s ease-out both,
             latido 2s ease-in-out 1s infinite alternate;
}

Si algo no funciona

  • La animación no hace nada: revisa que el nombre sea igual en @keyframes y en animation, y que la duración tenga unidad (1s, no 1).
  • El elemento pierde su giro al animarse: la animación sustituye su transform. Repite el giro en cada paso.
  • Se ve un momento antes de entrar: falta both.
  • Al repetirse da un salto: usa alternate o haz iguales el primer paso y el último.
  • El :hover no responde: otro elemento está encima y lo tapa. Súbelo con z-index.

Idea clave: decide el orden antes de escribir código. ¿Qué tiene que verse primero? ¿Qué se lee al final? Y que sólo se muevan en bucle uno o dos elementos: si todo se mueve a la vez, no se lee nada.

Animar SVG

Un SVG es código, así que sus formas se pueden animar con CSS como cualquier otro elemento. El efecto más conocido es el de una línea que se dibuja sola: perfecto para un logotipo, una firma o una ilustración de líneas.

Una línea que se dibuja

Se basa en dos propiedades del trazo: stroke-dasharray convierte la línea en rayas y stroke-dashoffset desplaza esas rayas. Si la raya y el hueco miden lo mismo que toda la línea, al llevar el desplazamiento a cero la línea aparece poco a poco.

El atributo pathLength="1" le dice al navegador que la línea mide 1, así no hay que calcular su longitud real.

Tus propios SVG

  • Exporta el dibujo desde Illustrator con Archivo › Exportar › Exportar como… y el formato SVG.
  • Abre el archivo con VS Code y copia el <svg> dentro de tu HTML. Si lo pones con <img>, se ve, pero tu CSS no puede llegar a sus formas.
  • Pon una clase a cada forma que quieras animar, por ejemplo <path class="hoja">.

Truco: para girar o escalar una forma de un SVG desde su centro, añádele transform-box: fill-box y transform-origin: center. Si no, gira desde la esquina del dibujo.

Para saber más (opcional)

Contenidos para ir más allá, si te sobra tiempo o te interesa el tema.

Más sobre animaciones: propiedades y aparición escalonada

Las propiedades de una animación

.elemento {
  animation-name: aparecer;
  animation-duration: 0.8s;
  animation-timing-function: ease-out;
  animation-delay: 0.2s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: both;
}

/* Todo junto, en una línea */
.elemento {
  animation: aparecer 0.8s ease-out 0.2s both;
}
PropiedadQué controla
animation-durationCuánto dura una vuelta.
animation-timing-functionLa curva de aceleración: ease, ease-out, linear…
animation-delayCuánto espera antes de empezar.
animation-iteration-countCuántas veces se repite (infinite para siempre).
animation-directionnormal, reverse (al revés) o alternate (ida y vuelta, sin saltos).
animation-fill-modeboth hace que el elemento se quede como en el primer fotograma durante la espera, y como en el último al terminar.

Aparición escalonada

Un efecto muy usado en portfolios: los elementos de una galería aparecen uno detrás de otro, con un pequeño retraso entre cada uno.

.galeria .tarjeta {
  animation: aparecer 0.6s ease-out both;
}

.galeria .tarjeta:nth-child(2) { animation-delay: 0.1s; }
.galeria .tarjeta:nth-child(3) { animation-delay: 0.2s; }
.galeria .tarjeta:nth-child(4) { animation-delay: 0.3s; }

Truco: anima siempre que puedas opacity y transform. Son las propiedades que el navegador anima con más fluidez. Animar width, height, top o margin obliga a recalcular toda la página en cada fotograma, y en móviles se nota a saltos.

Movimiento y accesibilidad: la red de seguridad y pautas

Una red de seguridad

Además, muchas webs añaden al final de su CSS una regla que reduce casi a cero cualquier animación o transición cuando se pide menos movimiento:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Es uno de los pocos casos en los que !important está justificado: tiene que ganar a todo lo demás.

Pautas para animar con criterio

  • Que ayude: el movimiento debe indicar algo (que algo se puede pulsar, que algo ha cambiado, de dónde viene un elemento). Si sólo decora, mejor poco y sutil.
  • Breve: las animaciones de interfaz, por debajo de medio segundo. Las de entrada, como mucho un segundo.
  • Sin destellos: nunca hagas que algo parpadee más de tres veces por segundo. Puede provocar crisis en personas con epilepsia fotosensible; es una de las pautas de accesibilidad más estrictas.
  • Con control: si una animación dura más de cinco segundos (un carrusel, un fondo animado), la persona debe poder pausarla.

Truco: para probarlo sin cambiar la configuración de tu ordenador, usa el mismo atajo del modo oscuro (Ctrl + Mayús + P en el inspector), escribe reduced y elige Emulate CSS prefers-reduced-motion: reduce.

Filtros

CSS puede aplicar a cualquier elemento efectos que conoces de Photoshop: desenfocar, pasar a blanco y negro, cambiar el brillo o el contraste. Se aplican en el navegador, sin modificar el archivo original.

Filtros: filter

sin filtro
grayscale(1)
blur(3px)
brightness(1.3)
contrast(1.6)
saturate(2)
sepia(1)
hue-rotate(120deg)

Se pueden combinar varios separándolos con espacios (filter: grayscale(1) contrast(1.2)) y animarlos con una transición. Un efecto clásico de portfolio: imágenes en blanco y negro que recuperan el color al pasar el ratón.

.galeria img {
  filter: grayscale(1);              /* en blanco y negro */
  transition: filter 0.4s ease;
}

.galeria img:hover {
  filter: grayscale(0);              /* recupera el color */
}

Hay también un filtro drop-shadow(), que a diferencia de box-shadow sigue la forma real de la imagen: en un PNG o un SVG con transparencia, la sombra rodea la silueta, no la caja.

Ojo: no apliques filtros pesados (como blur) a elementos muy grandes o animados, porque ralentizan la página en el móvil. Y si pones texto sobre una imagen filtrada, comprueba que se lee bien sobre todo el fondo.

Más efectos: backdrop-filter y modos de fusión

Desenfocar lo que hay detrás: backdrop-filter

filter afecta al propio elemento. backdrop-filter afecta a lo que se ve a través de él, si tiene un fondo semitransparente. Es el efecto de cristal esmerilado:

header {
  position: sticky;
  top: 0;
  background: rgba(247, 246, 242, 0.8);   /* fondo semitransparente */
  backdrop-filter: blur(8px);             /* desenfoca lo que pasa por detrás */
}

La cabecera de esta web está hecha así: haz scroll y fíjate en cómo se ve el contenido al pasar por debajo.

Modos de fusión

Los mismos modos de fusión de las capas de Photoshop (multiplicar, trama, superponer, diferencia…) existen en CSS:

  • mix-blend-mode fusiona un elemento con lo que tiene detrás.
  • background-blend-mode fusiona entre sí las capas de fondo de un mismo elemento (una imagen y un color, por ejemplo).
.portada {
  position: relative;
  background: url("../img/portada.jpg") center / cover;
}

.portada h1 {
  color: white;
  mix-blend-mode: difference;   /* el texto se invierte según el fondo */
}
.duotono {
  background-image: url("../img/foto.jpg");
  background-color: #546D78;
  background-blend-mode: multiply;   /* la foto se tiñe del color */
  background-size: cover;
}
normal
multiply
screen
luminosity
Jazz
mix-blend-mode: difference

Ojo: los filtros y los modos de fusión son muy vistosos, pero cuidado con el texto: un título con difference o sobre una imagen filtrada puede volverse ilegible en algunas zonas. Comprueba siempre que se lee bien sobre todo el fondo, y no apliques filtros pesados (como blur) a elementos muy grandes o animados, porque ralentizan la página en el móvil.

Transformaciones 3D: una tarjeta que se da la vuelta

Con perspective el navegador simula profundidad, y con rotateY() un elemento gira como una puerta. Con dos caras, una delante y otra detrás, se consigue una tarjeta con reverso. Pasa el ratón:

backface-visibility: hidden esconde cada cara cuando está de espaldas, y transform-style: preserve-3d hace que las dos caras compartan el mismo espacio 3D.

Fotograma a fotograma: steps()

Las curvas como ease hacen el movimiento continuo. steps(n) lo divide en saltos, como la manecilla de un reloj o una animación tradicional dibujada fotograma a fotograma.

Con una tira de imágenes (un sprite, con todos los fotogramas uno al lado de otro) como fondo y steps() moviendo el background-position, se anima un personaje como en un GIF.

Animaciones con el scroll, sin JavaScript

Una novedad de CSS permite que una animación avance a medida que el elemento entra en pantalla al hacer scroll, sin JavaScript:

.tarjeta {
  animation: aparecer linear both;
  animation-timeline: view();
  animation-range: entry 0% cover 30%;
}

Todavía no funciona en todos los navegadores: compruébalo en Can I use. Donde no funciona, el elemento simplemente aparece sin animación, así que no rompe nada. Para que funcione en todas partes, se hace con JavaScript, como verás en «Interactividad aplicada al diseño».

Repasa la unidad

En PDF

Ponlo en práctica

Seguimos con tu web de apuntes. Todo con CSS, sin JavaScript.

  1. Da a los botones y enlaces de tu web una microinteracción al pasar el ratón, al pulsar y al llegar con el teclado.
  2. Haz que las tarjetas de temas se levanten al pasar el ratón.
  3. Añade una secuencia de entrada a la portada con @keyframes, dentro de prefers-reduced-motion: no-preference.
  4. Revisa tus transiciones: ¿animas sólo transform y opacity?

Retos opcionales

  • Haz que los hotspots de tu imagen interactiva latan suavemente.
  • Anima tu logotipo o una ilustración en SVG para que se dibuje sola.
  • Haz que las capturas se vean en blanco y negro y recuperen el color al pasar el ratón, con filter.
  • Convierte una tarjeta de tema en una tarjeta que se da la vuelta, con una pregunta delante y la respuesta detrás.

Comprueba: con el movimiento reducido activado en el emulador del inspector, ¿sigue viéndose todo sin animaciones? ¿Alguna animación distrae más de lo que ayuda?

05 · JavaScript para interfaces

Los fundamentos de JavaScript (variables, operadores, condicionales y funciones) y cómo usarlos en la página: el DOM y los eventos.

JavaScript y la consola

JavaScript es el lenguaje de programación de la web, el tercero de los tres que entiende el navegador. Nació en 1995 para dar interactividad a las páginas y hoy se usa también en servidores, aplicaciones y herramientas de diseño.

Ojo: JavaScript no tiene nada que ver con Java, aunque se llamen parecido. El nombre fue una estrategia de marketing de la época, porque Java estaba de moda. Es como confundir «coche» con «cochera».

La consola del navegador

Todos los navegadores tienen una consola: una ventana donde puedes escribir JavaScript y ver el resultado al momento. Es el mejor sitio para hacer las primeras pruebas, y también donde aparecen los mensajes y errores de tus programas.

  1. Abre el inspector con F12 (en Mac, Cmd + Option + I).
  2. Ve a la pestaña Consola (Console).
  3. Escribe una instrucción y pulsa Intro.

La primera instrucción que aprende todo el mundo es console.log(), que muestra en la consola lo que pongas entre los paréntesis:

console.log("Hola, mundo");
console.log(2 + 2);
console.log("Diseño " + "web");

Los textos van entre comillas; los números, no. Fíjate en que 2 + 2 da 4, pero "Diseño " + "web" une los dos textos.

Un poco de magia

Abre cualquier web, por ejemplo la de un periódico, abre la consola y escribe:

document.body.style.background = "pink";
document.title = "¡He cambiado el título!";

Acabas de cambiar la página con JavaScript. No te preocupes: el cambio sólo existe en tu navegador y desaparece al recargar. Un poco más adelante, en esta unidad, aprenderemos a hacer esto en nuestras propias webs.

JavaScript en un archivo

La consola sirve para probar, pero lo que escribes ahí se pierde al recargar. En una web, el JavaScript va en un archivo .js que se enlaza desde el HTML con la etiqueta <script>, igual que el CSS se enlaza con <link>:

<head>
  <meta charset="UTF-8">
  <title>Mi web</title>
  <link rel="stylesheet" href="css/estilos.css">
  <script src="js/main.js" defer></script>
</head>
  • src es la ruta al archivo, como en las imágenes.
  • defer le dice al navegador que espere a que la página esté cargada antes de ejecutar el JavaScript. Si no, el programa podría intentar cambiar elementos que todavía no existen.

Y dentro de main.js:

// Esto es un comentario de una línea

/* Y esto, un comentario
   de varias líneas */

console.log("El archivo main.js está funcionando");

Reglas básicas al escribir JavaScript

  • Distingue mayúsculas y minúsculas: console.log funciona; Console.Log, no.
  • Cada instrucción termina en punto y coma (;). Muchas veces funciona sin él, pero es mejor acostumbrarse a ponerlo.
  • Los comentarios se escriben con // para una línea o entre /* */ para varias, como en CSS.
  • Las comillas de los textos pueden ser dobles ("hola") o simples ('hola'), pero tienen que ser rectas, nunca tipográficas (“ ”).

Idea clave: los errores no son un fracaso, son parte del trabajo. Hasta los programadores con experiencia se equivocan constantemente. Cuando algo no funcione, mira la consola: los errores aparecen en rojo, con una descripción y el número de línea donde está el problema. Aprender a leer esos mensajes es la habilidad más útil que vas a desarrollar.

Variables y tipos de datos

Cómo usar los ejemplos: a partir de aquí, los ejemplos con un botón «Ejecutar» se pueden editar. Cambia valores, rompe cosas a propósito y vuelve a ejecutar: es la mejor forma de aprender. Si te pierdes, «Restaurar» devuelve el ejemplo a su estado original.

Un programa trabaja con datos: un nombre, un número de columnas, un color… Para guardarlos y usarlos después se usan variables. Una variable es como una caja con una etiqueta: la etiqueta es el nombre, y dentro está el valor.

let y const

  • const crea una variable cuyo valor no va a cambiar (una constante).
  • let crea una variable cuyo valor puede cambiar después.

Una buena costumbre: usa const siempre, y cambia a let sólo si necesitas cambiar el valor. Verás también var en tutoriales antiguos: es la forma vieja de crear variables y hoy no se recomienda.

Nombres de variables

  • Sin espacios. Si son varias palabras, se juntan con la segunda y siguientes en mayúscula: colorPrincipal, anchoColumna. Se llama camelCase, por las «jorobas».
  • Que digan qué contienen: numeroDeColumnas mejor que n o dato1.
  • Mejor sin tildes ni eñes (aunque funcionan), y nunca empezando por un número.

Tipos de datos

TipoQué guardaEjemplo
Texto (string)Letras, palabras, frases. Siempre entre comillas."Helvetica"
Número (number)Enteros o decimales (con punto, no con coma). Sin comillas.12, 1.5
Booleano (boolean)Sólo dos valores: verdadero o falso. Para preguntas de sí o no.true, false

typeof dice de qué tipo es un dato. Fíjate en la diferencia: 16 es un número, pero "16" (con comillas) es un texto, y JavaScript los trata de forma distinta.

Unir textos y datos

Para construir un texto con datos dentro, la forma más cómoda es escribirlo entre comillas invertidas (`, la tecla a la derecha de la P) y poner cada dato dentro de ${ }:

Idea clave: una variable es un nombre para un dato. En lugar de escribir el mismo valor en muchos sitios, lo guardas una vez y lo usas por su nombre, igual que las variables de CSS que ya conoces.

Operadores

Los operadores hacen operaciones con los datos: cálculos, comparaciones y combinaciones de condiciones.

Operaciones con números

OperadorQué haceEjemploResultado
+Suma10 + 212
-Resta10 - 28
*Multiplica10 * 220
/Divide10 / 25
%Resto de una división10 % 31

Un ejemplo de diseño: calcular el ancho total de una retícula, como harías al configurar las columnas en InDesign.

Como en matemáticas, la multiplicación va antes que la suma, y los paréntesis cambian el orden.

Ojo: + hace dos cosas: con números, suma; con textos, une. Si mezclas un texto y un número, los une como texto: "5" + 3 da "53", no 8. Es uno de los despistes más habituales; pruébalo en cualquier ejemplo.

Comparaciones

Comparan dos valores y el resultado siempre es true o false:

OperadorPregunta
===¿Son iguales?
!==¿Son distintos?
> / <¿Mayor que? / ¿Menor que?
>= / <=¿Mayor o igual? / ¿Menor o igual?

Ojo: un solo = guarda un valor en una variable; tres === comparan. Confundirlos es el error número uno al empezar. Existe también == (con dos), pero hace comparaciones poco fiables (considera iguales 5 y "5"), así que usa siempre ===.

Condicionales

Los condicionales son las decisiones que vimos en los algoritmos: hacer una cosa u otra según se cumpla una condición. Se escriben con if («si») y else («si no»):

  • La condición va entre paréntesis.
  • Lo que se hace si se cumple va entre llaves { }, con sangría.
  • else es opcional: si no lo pones y la condición no se cumple, simplemente no pasa nada.

Compáralo con el pseudocódigo del principio del tema: SI … ENTONCES … SI NO … FIN SI. Es exactamente lo mismo, con otra forma de escribirlo.

Varias opciones: else if

Se comprueban en orden, de arriba abajo, y sólo se ejecuta el primer bloque cuya condición se cumpla. Cambia la hora y prueba.

Truco: si no sabes por qué un if no hace lo que esperas, pon un console.log() justo antes con la condición: console.log(peso > 300). Verás si da true o false.

Funciones

Una función es un bloque de código con nombre que puedes usar todas las veces que quieras. Es como una receta: la escribes una vez y la «cocinas» cada vez que la necesitas, a veces con ingredientes distintos.

Parámetros: los ingredientes

Entre los paréntesis se pueden indicar parámetros: datos que la función recibe cada vez que se usa, y que cambian el resultado.

Devolver un resultado: return

Muchas funciones calculan algo y lo devuelven con return, para poder guardarlo en una variable y usarlo después. Recuperamos el cálculo de la retícula, ahora reutilizable:

Idea clave: si te encuentras copiando y pegando el mismo código varias veces, probablemente debería ser una función. Así, si hay que cambiar algo, se cambia en un solo sitio.

Fíjate: en internet verás funciones escritas de otra forma, con una flecha: const saludar = (nombre) => { … }. Se llaman funciones flecha y hacen lo mismo. No te asustes si las encuentras; las usaremos más adelante en esta unidad, con los eventos.

El DOM

Cuando el navegador carga una página, lee el HTML y construye con él un modelo en memoria: un árbol en el que cada etiqueta es un objeto que JavaScript puede leer y modificar. Ese árbol se llama DOM (Document Object Model, modelo de objetos del documento).

html
├── head
│   └── title
└── body
    ├── header
    │   └── h1
    └── main
        ├── p
        └── img

Cada elemento es un «nodo» del árbol: body es el padre de header y main; h1 es hijo de header… Es la misma estructura de cajas dentro de cajas que ya conoces del HTML.

Fíjate: la pestaña Elementos del inspector no muestra tu archivo HTML, sino el DOM: la página tal y como está ahora. Por eso, cuando JavaScript cambia algo, lo ves ahí al momento, aunque tu archivo no haya cambiado.

Trabajar con el DOM siempre sigue los mismos tres pasos, que vamos a ver en este tema:

  1. Seleccionar el elemento con el que quieres trabajar.
  2. Escuchar lo que hace el usuario (un clic, escribir, pulsar una tecla).
  3. Cambiar algo en la página como respuesta.

Seleccionar elementos

Para trabajar con un elemento, primero hay que encontrarlo. La buena noticia: se buscan con los mismos selectores que usas en CSS.

  • document.querySelector("selector") devuelve el primer elemento que coincide.
  • document.querySelectorAll("selector") devuelve todos los que coinciden, en una lista que puedes recorrer con for…of.

Lo habitual es guardar el elemento en una variable con const, para usarlo después las veces que haga falta.

Ojo: si el selector no encuentra nada, querySelector devuelve null («nada»), y la siguiente línea dará un error como Cannot read properties of null. Cuando lo veas, revisa el selector: ¿falta el punto de la clase? ¿Está bien escrito el nombre? ¿Existe el elemento en el HTML?

Cambiar el texto y las clases

Cambiar el texto

textContent lee o cambia el texto de un elemento:

Cambiar las clases: la forma recomendada

Se puede cambiar el estilo de un elemento directamente desde JavaScript (elemento.style.color = "red"), pero casi siempre es mejor dejar el diseño en el CSS y que JavaScript sólo ponga o quite clases. Para eso está classList:

MétodoQué hace
.classList.add("clase")Añade la clase.
.classList.remove("clase")Quita la clase.
.classList.toggle("clase")La pone si no está y la quita si está. Como un interruptor.
.classList.contains("clase")Pregunta si la tiene: devuelve true o false.

Idea clave: reparto de tareas. CSS define cómo se ve cada estado (.abierto, .activo, .oscuro); JavaScript decide cuándo se activa cada uno. Así el diseño sigue estando en un solo sitio, y casi todos los componentes interactivos se reducen a «al pulsar aquí, pon o quita esta clase».

Eventos

Un evento es algo que ocurre en la página: un clic, una tecla, escribir en un campo, hacer scroll. Con addEventListener le dices a un elemento: «cuando ocurra esto, ejecuta esta función».

  • El primer dato es el nombre del evento, entre comillas: "click".
  • El segundo es la función que se ejecutará cada vez que ocurra.

Funciones flecha

() => { … } es una función flecha, la forma corta de escribir una función que te presentamos en el apartado de funciones. Es lo mismo que function () { … }, y es muy habitual dentro de addEventListener porque la función no necesita nombre: sólo se usa ahí.

Eventos más usados

EventoCuándo ocurre
clickAl hacer clic (o tocar, en el móvil).
inputCada vez que cambia el valor de un campo: al escribir, mover un deslizador, elegir un color…
submitAl enviar un formulario.
keydownAl pulsar una tecla.
mouseenter / mouseleaveCuando el ratón entra en un elemento / sale de él.
scrollAl hacer scroll en la página.

Ratón encima y scroll

Además de click, hay eventos para cuando el ratón entra en un elemento (mouseenter) o sale de él (mouseleave). Pero ojo: para cambiar el aspecto al pasar el ratón, basta con CSS (:hover). Usa estos eventos sólo cuando haga falta lógica, como mostrar un dato distinto según el elemento.

El evento scroll permite reaccionar al desplazamiento de la página. window.scrollY dice cuántos píxeles se ha bajado. Un uso clásico: una cabecera que se compacta al empezar a bajar. Haz scroll dentro del ejemplo:

Para hacer que los elementos aparezcan al llegar a ellos con el scroll, hay una herramienta mejor que este evento. La veremos en «Interactividad aplicada al diseño».

Truco: dentro de la función se puede recibir el evento, normalmente con el nombre e: (e) => { … }. Trae información útil, como qué tecla se ha pulsado (e.key).

Proyecto: menú desplegable

El clásico menú de móvil que se abre y se cierra con un botón. Fíjate en que toda la lógica es poner y quitar una clase:

Además de la clase, el código actualiza aria-expanded, un atributo que dice a los lectores de pantalla si el menú está abierto. La expresión abierto ? "Cerrar" : "Menú" es un if abreviado: «si abierto es verdadero, "Cerrar"; si no, "Menú"».

Fíjate: el menú de móvil de esta web funciona exactamente así. Abre script.js y búscalo.

Proyecto: hotspots en el móvil

En «HTML5 y CSS3 avanzado» hicimos una imagen interactiva cuyas fichas aparecían con :hover. Pero en el móvil no hay ratón: como prometimos, ahora la completamos con JavaScript para que cada punto se abra con un toque, se cierre con otro, y sólo haya una ficha abierta a la vez.

El algoritmo, en palabras: «al pulsar un punto, cierra todos; después, abre el pulsado, salvo que ya estuviera abierto». Antes de programar algo así, escríbelo en pseudocódigo como vimos en «Introducción a la programación y al entorno»: te ahorrará muchos errores.

Para saber más (opcional)

Contenidos para ir más allá, si te sobra tiempo o te interesa el tema.

Combinar condiciones: &&, || y !
  • && (y): verdadero sólo si se cumplen las dos condiciones.
  • || (o): verdadero si se cumple al menos una.
  • ! (no): da la vuelta a un valor: !true es false.
Generador de titulares: el evento input

Un ejemplo muy de diseño con el evento input: un generador de titulares que cambia en directo al escribir, mover el deslizador o elegir un color.

Proyecto: botón de modo oscuro

En «Para saber más» de «Responsive Web Design» vimos cómo hacer que la web cambie de modo según la configuración del sistema. Ahora añadimos un botón para que cada persona pueda elegir. La idea es la misma de siempre: los colores están en variables, y el botón pone o quita una clase en la etiqueta <html> que cambia esas variables.

Recordar la elección

Si recargas la página, vuelve al modo claro. Para que el navegador recuerde la elección, se puede guardar con localStorage, una pequeña memoria que cada web tiene en el navegador de cada visitante:

// Al pulsar el botón: guardar la elección
localStorage.setItem("modo", oscuro ? "oscuro" : "claro");

// Al cargar la página: recuperarla
if (localStorage.getItem("modo") === "oscuro") {
  document.documentElement.classList.add("oscuro");
}

setItem guarda un dato con un nombre, y getItem lo recupera, incluso después de cerrar el navegador.

Repasa la unidad

En PDF

Ponlo en práctica

Trabaja en el archivo js/main.js de tu web de apuntes.

  1. Crea la carpeta js con el archivo main.js, enlázalo con defer y comprueba en la consola que funciona un console.log().
  2. Crea variables con tu nombre y tu ciudad y muestra una frase que las use, con comillas invertidas y ${ }.
  3. Crea una función anchoReticula() como la de esta unidad y úsala con un if que avise si la retícula mide más de 1200px.
  4. Haz un menú desplegable para el móvil con un botón, classList.toggle() y aria-expanded. En pantallas grandes, el menú debe verse siempre (usa una media query).
  5. Haz que los hotspots de tu imagen interactiva se abran y se cierren con un toque.

Retos opcionales

  • Haz que la cabecera se compacte al hacer scroll.
  • Añade un botón de modo oscuro que recuerde la elección.

Comprueba: prueba todo en tu móvil, no sólo en el ordenador. ¿Funciona también con el teclado (Tab, Intro)? ¿La consola muestra algún error en rojo?

06 · Interactividad aplicada al diseño

Colecciones de datos y lógica para construir componentes visuales: galerías generadas a partir de datos, ventanas modales, sliders y animaciones que se ponen en marcha al pulsar o al hacer scroll.

Arrays y bucles

Los bucles son las repeticiones que vimos en los algoritmos: hacer lo mismo varias veces sin escribirlo varias veces.

Hasta ahora, cada variable guardaba un solo dato. Pero muchas veces trabajamos con listas: los colores de una paleta, los proyectos del portfolio, las imágenes de una galería.

Arrays: listas de datos

Un array es una lista de valores entre corchetes, separados por comas:

  • Cada elemento tiene una posición (índice) y se cuenta desde 0: el primero es [0], el segundo [1]… Es raro al principio, pero es así en casi todos los lenguajes.
  • .length dice cuántos elementos tiene.
  • .push() añade un elemento al final:

Recorrer una lista: for…of

Es el bucle más útil y el más fácil de leer: «para cada elemento de esta lista, haz esto».

En cada vuelta, la variable color toma el valor del siguiente elemento, hasta recorrerlos todos.

Componentes a partir de datos

JavaScript también puede crear elementos y añadirlos a la página. Combinado con un array de objetos y un bucle, permite generar una galería entera a partir de los datos:

  1. document.createElement("article") crea un elemento nuevo, todavía fuera de la página.
  2. Se le dan clases y contenido. innerHTML funciona como textContent, pero entiende etiquetas HTML.
  3. .append() lo mete dentro de otro elemento, al final.

Añade un proyecto más al array y ejecuta: aparece una tarjeta nueva sin tocar el HTML. Así funcionan las webs que muestran contenido que cambia: los datos por un lado y la plantilla por otro.

Ojo: usa innerHTML sólo con contenido tuyo. Nunca metas con innerHTML texto que haya escrito un usuario (por ejemplo, en un formulario): podría incluir código malicioso. Para el texto de los usuarios, usa siempre textContent.

Proyecto: ventana modal

Una ventana modal es un panel que se abre por encima de la página y no deja usar lo de detrás hasta que se cierra. Su uso más habitual en un portfolio es el visor de imágenes: al pulsar una imagen de la galería, se abre en grande, y se cierra con un botón o con la tecla Esc.

  • El visor es un elemento position: fixed que cubre toda la pantalla (Programación I). Empieza oculto con el atributo hidden.
  • Al pulsar una imagen, se copian su src y su alt a la imagen grande y se muestra el visor.
  • Un evento keydown en todo el documento cierra el visor con Esc, gracias al objeto del evento (e.key).

Ojo: las imágenes del ejemplo vienen de un servicio de fotos de prueba, así que necesitan conexión a internet. En tu web, usa tus propias imágenes con su ruta relativa.

Para saber más: HTML tiene un elemento pensado para esto, <dialog>. Con dialog.showModal() se abre como ventana modal, ya trae el cierre con Esc y mantiene el foco del teclado dentro mientras está abierta. Es la opción más accesible para modales más complejas, como un formulario.

Proyecto: slider

Un slider (o carrusel) muestra varias imágenes o tarjetas, una detrás de otra, en el mismo espacio. Es un componente muy útil para enseñar un proyecto con varias imágenes. Combina casi todo lo de esta unidad: un array, un número que guarda la posición y eventos.

  1. Todas las diapositivas están en fila dentro de la pista, y el slider esconde con overflow: hidden todo lo que no cabe.
  2. La variable actual guarda qué diapositiva se ve: 0, 1 o 2.
  3. Los botones suman o restan 1 a actual, con un if para dar la vuelta al llegar a un extremo.
  4. La función mostrar() desplaza la pista con transform, y la transition del CSS lo anima.

Ojo: los sliders que pasan solos cada pocos segundos son muy molestos: no da tiempo a leer, y a quien usa un lector de pantalla le cambia el contenido sin avisar. Deja siempre que sea la persona quien avance, y que el último contenido importante no quede escondido en la quinta diapositiva.

Animaciones disparadas con JavaScript

En «Animación con CSS» viste que las transiciones y las animaciones se ponen en marcha solas (al cargar) o con :hover. Con JavaScript podemos decidir cuándo empiezan: al pulsar un botón, al llegar con el scroll, al enviar un formulario. La técnica es siempre la misma: el movimiento lo define el CSS, y JavaScript sólo añade o quita una clase.

Una clase que lo cambia todo

JavaScript no calcula ningún movimiento: sólo pone la clase abierto, y la transition del CSS hace el resto. Así el código es más corto y la animación, más fluida.

Aparecer al hacer scroll

Para que los elementos aparezcan al llegar a ellos, se usa IntersectionObserver: un «vigilante» que avisa cuando un elemento entra en la pantalla. Es mucho más eficiente que escuchar el evento scroll, que se dispara decenas de veces por segundo. Haz scroll dentro del ejemplo:

  • new IntersectionObserver(…) crea el vigilante, con la función que se ejecutará cuando algún elemento entre o salga de la pantalla.
  • threshold: 0.2 indica cuánto del elemento tiene que verse para avisar: un 20 %.
  • vigilante.observe(el) le dice qué elementos vigilar.

Fíjate: esta misma web usa esta técnica para que los bloques aparezcan suavemente al bajar. Y fíjate en el CSS: el estado oculto está dentro de prefers-reduced-motion: no-preference. Si alguien ha pedido menos movimiento, todo se ve desde el principio, sin animación.

Para saber más (opcional)

Contenidos para ir más allá, si te sobra tiempo o te interesa el tema.

Objetos: fichas con datos

Un proyecto del portfolio no es un solo dato: tiene título, año, tipo… Para agrupar varios datos de una misma cosa se usa un objeto, que es como una ficha con campos. Se escribe entre llaves, con parejas de nombre: valor:

Se accede a cada dato con un punto: proyecto.titulo. Y lo más útil: un array puede contener objetos. Así se guarda una colección entera, por ejemplo, todos los proyectos de un portfolio:

Idea clave: los arrays de objetos son la forma en la que casi todas las webs guardan sus contenidos: los productos de una tienda, los artículos de un blog, las fotos de una galería. En esta unidad usamos uno para crear una galería automáticamente.

Más bucles: el for clásico y bucles con condicionales

Repetir un número de veces: for

Cuando no recorres una lista, sino que quieres repetir algo un número concreto de veces, se usa el for clásico, con un contador:

Entre los paréntesis hay tres partes, separadas por punto y coma:

  1. let i = 1 — el contador empieza en 1.
  2. i <= 5 — el bucle sigue mientras el contador sea menor o igual que 5.
  3. i++ — al final de cada vuelta, el contador suma 1 (es lo mismo que i = i + 1).

Bucles y condicionales juntos

La verdadera potencia aparece al combinar las piezas. Por ejemplo, recorrer los proyectos y marcar sólo los recientes:

Ojo: un bucle cuya condición no deja nunca de cumplirse se repite para siempre y bloquea el navegador (un bucle infinito). Si te pasa, cierra la pestaña. Por eso, en un for, comprueba siempre que el contador avanza hacia el final.

Repasa la unidad

En PDF

Ponlo en práctica

Trabaja en el js/main.js de tu web de apuntes.

  1. Añade botones para filtrar las tarjetas del índice de temas por curso (1.º o 2.º). Dale a cada tarjeta un data-curso y, al pulsar un botón, oculta con classList las que no son de ese curso.
  2. Haz que al pulsar una captura se abra en grande en una ventana modal, que se cierre con un botón y con Esc.
  3. Explica un proceso paso a paso en un slider: por ejemplo, cómo se publica una web o cómo se hace un menú desplegable.

Retos opcionales

  • Añade al slider unos puntos debajo que indiquen la posición y permitan saltar a cada diapositiva.
  • Haz que el slider también avance con las flechas del teclado.
  • Haz que las tarjetas de temas aparezcan al llegar a ellas con el scroll, con IntersectionObserver.

Comprueba: ¿todo funciona con el teclado? ¿Al cerrar la ventana modal vuelves a donde estabas? ¿La consola muestra algún error en rojo?

07 · Arquitectura web y WordPress

Cómo funciona una web dinámica por dentro (servidor, bases de datos, CMS) y cómo llevar una maquetación propia a WordPress. El uso de WordPress y Elementor se ve en Medios Informáticos II.

Webs estáticas y dinámicas

En el «Cómo funciona la web», de 1.º viste que visitar una web es una conversación entre el navegador (el cliente) y el servidor. Hasta ahora, en esa conversación el servidor se limitaba a buscar un archivo y enviarlo tal cual. Es lo que se llama una web estática, como tu portfolio.

En una web dinámica, el servidor no guarda las páginas hechas: las fabrica en el momento, para cada visita. Por eso un periódico puede mostrar las últimas noticias sin que nadie escriba un HTML nuevo cada vez, o una tienda puede enseñarte tu carrito.

Web estáticaWeb dinámica
Qué guarda el servidorArchivos HTML, CSS, JS e imágenes ya terminadosUn programa y una base de datos con el contenido
Qué hace al recibir una peticiónEnvía el archivo pedidoEjecuta el programa, que consulta la base de datos y genera el HTML
Lenguajes en el servidorNingunoPHP, Python, JavaScript (Node.js)…
Para actualizar el contenidoHay que editar el códigoSe usa un panel de administración
EjemplosUn portfolio, una página de presentaciónUn blog, una tienda, una red social

Así, los lenguajes se reparten el trabajo. En el cliente (el navegador) trabajan HTML, CSS y JavaScript, lo que ya conoces. En el servidor trabaja otro lenguaje, que en el caso de WordPress es PHP, y la base de datos, que habla un lenguaje llamado SQL.

  1. 1PeticiónEl navegador pide /blog/.
  2. 2PHPEn el servidor, el programa recibe la petición y decide qué hace falta.
  3. 3Base de datosPHP pide con SQL las diez últimas entradas.
  4. 4HTMLPHP mete los datos en una plantilla y envía el HTML. El navegador no nota la diferencia.

Bases de datos

Una base de datos es un almacén organizado de información. La más habitual en la web, MySQL, guarda los datos en tablas, como una hoja de cálculo:

Tabla entradas
idtitulofechacategoria
1Cartel para el festival2026-10-02Ilustración
2Nueva identidad del estudio2026-10-15Identidad
3Taller de tipografía2026-11-03Noticias
  • Cada fila es un registro: una entrada del blog.
  • Cada columna es un dato de ese registro: el título, la fecha.
  • El id es un número único que identifica cada fila, como el DNI.

Para pedir datos se usa SQL, un lenguaje que se lee casi como una frase en inglés:

SELECT titulo, fecha
FROM entradas
WHERE categoria = 'Ilustración'
ORDER BY fecha DESC;

«Selecciona el título y la fecha, de la tabla de entradas, cuando la categoría sea Ilustración, ordenadas por fecha de la más nueva a la más antigua». No hace falta que aprendas SQL: WordPress lo escribe por ti. Pero entender que tu contenido vive en tablas te ayudará a saber qué pasa cuando, por ejemplo, mueves una web a otro servidor y hay que llevarse también la base de datos.

Fíjate: se parece mucho al array de objetos de «Interactividad aplicada al diseño». Cada objeto era un registro y cada propiedad, una columna. La diferencia es que la base de datos guarda la información de forma permanente, en el servidor, y puede manejar millones de registros.

WordPress por dentro

WordPress es un CMS (gestor de contenidos): una web dinámica ya programada, en PHP y MySQL, que se instala en un servidor y se maneja desde un panel. Cómo se usa (el contenido, Elementor, la publicación) lo ves en Medios Informáticos II. Aquí miramos cómo está hecho por dentro, para poder llevar a WordPress tus propias maquetaciones.

Instalarlo en local

Igual que en Medios II, instala WordPress en tu ordenador con Local (los pasos están en el «Instalación y primeros pasos», de Medios II). En Local, el botón Go to site folder abre la carpeta con todos sus archivos.

Local es para trabajar en tu ordenador. Para que la web se vea en internet hay que instalar WordPress en un servidor, con un hosting y un dominio: cómo se hace, en Medios II, «¿Y en un servidor?», y qué son el hosting y el dominio, en Programación I: 0.5 Direcciones: IP, dominios y DNS y 0.6 Hosting y publicación.

Las carpetas de WordPress

app/public/
├── wp-admin/          ← el panel de administración (no se toca)
├── wp-includes/       ← el núcleo de WordPress (no se toca)
├── wp-content/        ← TODO lo tuyo está aquí
│   ├── themes/        ← los temas (el diseño)
│   ├── plugins/       ← los plugins (las funciones)
│   └── uploads/       ← las imágenes y archivos subidos
└── wp-config.php      ← la conexión con la base de datos

Idea clave: nunca modifiques los archivos de wp-admin ni de wp-includes: se sustituyen en cada actualización y perderías los cambios. Todo lo que hagas va en wp-content, sobre todo en tu tema.

Qué es un tema, por dentro

Un tema es una carpeta dentro de wp-content/themes con plantillas y estilos. Los temas actuales de WordPress son temas de bloques, y su estructura mínima es ésta:

mi-tema/
├── style.css          ← el nombre del tema y tu CSS
├── theme.json         ← colores, tipografías y espacios
├── templates/
│   └── index.html     ← la plantilla general
└── parts/
    ├── header.html    ← la cabecera
    └── footer.html    ← el pie

El archivo style.css empieza con un comentario que WordPress lee para saber cómo se llama el tema:

/*
Theme Name: Web de apuntes
Author: Tu nombre
Version: 1.0
*/

Las plantillas son HTML con bloques de WordPress, que se escriben como comentarios especiales. En la práctica, no se escriben a mano: se diseñan en el editor del sitio (Apariencia › Editor) y se exportan.

Tu maquetación en WordPress

¿Cómo se lleva a WordPress un diseño que ya tienes hecho en HTML y CSS? La forma más sencilla de hacerlo hoy es crear un tema de bloques propio con el plugin oficial Create Block Theme, y trasladar a él tu sistema de diseño.

1. Crear el tema

  1. Instala el plugin Create Block Theme desde Plugins › Añadir nuevo plugin.
  2. Abre el editor del sitio (Apariencia › Editor): el plugin añade un icono con sus opciones. Elige crear un tema en blanco y ponle nombre. El plugin crea la carpeta con style.css, theme.json y las plantillas.
  3. Actívalo en Apariencia › Temas.

2. Tus variables, en theme.json

El archivo theme.json es el equivalente de tus variables en :root. Lo que pongas aquí aparece en el editor como la paleta y las tipografías de la web, para que quien escriba el contenido use siempre las tuyas:

{
  "version": 3,
  "settings": {
    "color": {
      "palette": [
        { "slug": "fondo",  "name": "Fondo",  "color": "#F7F6F2" },
        { "slug": "texto",  "name": "Texto",  "color": "#21231F" },
        { "slug": "acento", "name": "Acento", "color": "#546D78" }
      ]
    },
    "layout": { "contentSize": "720px", "wideSize": "1200px" }
  }
}

WordPress convierte cada color en una variable de CSS: --wp--preset--color--acento. Puedes usarla en tu style.css como cualquier otra variable.

3. Maquetar con bloques y tu CSS

  1. En Apariencia › Editor, construye la cabecera, el pie y las plantillas con bloques: Grupo, Fila y Pila son, por dentro, contenedores Flexbox; Cuadrícula, un Grid.
  2. Lo que los bloques no permitan, añádelo en style.css. A cualquier bloque se le puede poner una clase en Avanzado › Clases CSS adicionales, como harías en tu HTML.
  3. Al terminar, guarda los cambios en los archivos del tema con la opción Guardar cambios en el tema del plugin. Así tu tema queda listo para instalarlo en cualquier WordPress.

Fíjate: en Medios II se maqueta con Elementor, un maquetador visual que guarda el diseño en la base de datos. Aquí construyes un tema propio, cuyo diseño está en archivos de código que tú controlas. Las dos formas existen en el trabajo real, y conocerlas te permite elegir la adecuada para cada proyecto.

Repasa la unidad

En PDF

Ponlo en práctica

  1. Dibuja un esquema de lo que pasa cuando alguien visita el blog de una web hecha con WordPress, desde que escribe la dirección hasta que ve la página. Señala qué ocurre en el cliente y qué en el servidor.
  2. Instala WordPress con Local y localiza las carpetas themes, plugins y uploads. Sube una imagen desde el panel y búscala en uploads.
  3. Crea un tema de bloques con Create Block Theme y traslada a theme.json la paleta y el ancho de contenido de tu web de apuntes.
  4. Construye en el editor del sitio la cabecera y el pie de tu web de apuntes, y guárdalos en el tema.

Retos opcionales

  • Añade a theme.json las tipografías de tu web de apuntes.
  • Abre style.css de tu tema y añade algún detalle que los bloques no permitan, con una clase CSS adicional.

08 · Accesibilidad y proyecto final

Las pautas de accesibilidad, la navegación por teclado y cómo auditar una web. Con todo ello, el proyecto final: tu web de apuntes, completa y publicada.

Principios de accesibilidad

Una web accesible es una web que puede usar todo el mundo: también las personas ciegas o con poca visión, sordas, con dificultades de movimiento o cognitivas, y quien navega con el móvil a pleno sol o con un brazo escayolado. En España, más de cuatro millones de personas tienen alguna discapacidad, y con la edad, todos acabamos necesitando webs más accesibles.

Además, desde junio de 2025 la Ley Europea de Accesibilidad obliga a muchas empresas (tiendas online, bancos, transportes…) a que sus webs sean accesibles. Saber hacerlo es ya un requisito profesional.

Las pautas WCAG

Las WCAG (Web Content Accessibility Guidelines) son las pautas internacionales de accesibilidad, publicadas por el W3C, el mismo organismo que define HTML y CSS. Tienen tres niveles de exigencia (A, AA y AAA). La ley pide el nivel AA. Se organizan en cuatro principios:

PrincipioQué significaEjemplos
PerceptibleToda la información se puede percibir con algún sentido.Texto alternativo en las imágenes, subtítulos en los vídeos, contraste suficiente.
OperableTodo se puede usar, con cualquier dispositivo.Todo funciona con el teclado, hay tiempo suficiente, nada parpadea de forma peligrosa.
ComprensibleEl contenido y el funcionamiento se entienden.Idioma de la página declarado, menús coherentes, errores de formulario explicados.
RobustoFunciona con distintos navegadores y tecnologías de apoyo.HTML válido y semántico, botones que son <button>.

Muchas de estas pautas ya las aplicas: el alt, los <label>, la estructura semántica, el contraste, prefers-reduced-motion. Las tienes resumidas en el apartado de accesibilidad visual de Recursos, con un comprobador de contraste.

Navegación por teclado

Muchas personas no usan ratón: por una discapacidad motora, porque usan un lector de pantalla o, simplemente, porque es más rápido. Navegan con el teclado:

TeclaQué hace
Tab / Mayús + TabPasa al siguiente / al anterior elemento interactivo (enlaces, botones, campos).
IntroSigue un enlace o pulsa un botón.
EspacioPulsa un botón, marca una casilla o baja la página.
EscCierra una ventana modal o un menú.
FlechasSe mueven dentro de un grupo de opciones o un desplegable.

Las cuatro reglas

  1. Que todo se pueda alcanzar. Usa elementos que ya funcionan con el teclado: <a href> para ir a otra página, <button> para hacer algo. Un <div> con un evento click no se puede alcanzar con Tab.
  2. Que se vea dónde está el foco. Nunca escribas outline: none sin poner otra cosa a cambio. Dale estilo con :focus-visible.
  3. Que el orden tenga sentido. El foco sigue el orden del HTML, no el visual. Si con Grid o con order cambias mucho el orden en pantalla, el recorrido con Tab saltará de un lado a otro.
  4. Que nadie se quede atrapado. Una ventana modal se tiene que poder cerrar con Esc, y al cerrarla el foco debe volver al botón que la abrió.

El enlace para saltar al contenido

Si una página tiene un menú con veinte enlaces, quien usa el teclado tiene que pulsar Tab veinte veces en cada página antes de llegar al contenido. Para evitarlo se pone, como primer elemento, un enlace que sólo aparece al recibir el foco:

<a class="saltar" href="#contenido">Saltar al contenido</a>
…
<main id="contenido">…</main>
.saltar {
  position: absolute;
  left: 16px;
  top: -100px;              /* escondido fuera de la pantalla… */
}
.saltar:focus {
  top: 16px;                /* …hasta que recibe el foco */
}

Pruébalo ahora: deja el ratón y recorre esta misma página con Tab. ¿Ves siempre dónde estás? Haz lo mismo con tu web de apuntes. Es la prueba de accesibilidad más rápida y la que más problemas descubre.

Auditorías

Una auditoría es una revisión sistemática de la web para encontrar problemas. Combina herramientas automáticas con revisión manual, porque las herramientas sólo detectan una parte de los problemas (en accesibilidad, más o menos un tercio).

Herramientas automáticas

HerramientaQué revisa
LighthouseViene en Chrome (inspector › pestaña Lighthouse). Puntúa de 0 a 100 el rendimiento, la accesibilidad, las buenas prácticas y el SEO, con una lista de qué mejorar. Analiza en modo Móvil e intenta superar 90 en accesibilidad.
WAVEUna extensión que marca sobre la propia página los errores de accesibilidad: imágenes sin alt, campos sin <label>, saltos en los encabezados, contrastes bajos.
Validador del W3CQue el HTML no tenga errores, la base de todo lo demás.
Comprobador de contrasteEl de Recursos, o el del propio inspector al seleccionar un color.

Revisión manual

Idea clave: una puntuación de 100 en Lighthouse no garantiza que la web sea accesible, sólo que no tiene los errores que la máquina sabe detectar. La revisión manual es la que de verdad cuenta.

El encargo

El proyecto final consiste en rediseñar y completar tu web de apuntes: una web que explique lo que has aprendido en Programación I y II, con las demos interactivas de este curso. Partes de la versión que pusiste a punto en «Introducción a la programación y al entorno» y la mejoras con lo que has aprendido.

Fíjate: esta web no es tu portfolio, que lo haces en Medios Informáticos II. Cuando la publiques, puedes enseñarla en tu portfolio como un proyecto más.

Trabájalo como un encargo real de diseño, en tres fases:

  1. Planificación: qué vas a contar, a quién y cómo se organiza.
  2. Desarrollo: construir la web por capas, de lo básico a lo interactivo.
  3. Revisión y publicación: comprobar que todo funciona para todo el mundo y publicarla.

Requisitos obligatorios

Usa esta lista para ir comprobando tu avance. Puedes marcar las casillas mientras trabajas (se borran al recargar la página).

Para subir nota

Idea clave: los requisitos son el mínimo, no el objetivo. Lo que hará destacar tu web es lo mismo que en cualquier proyecto de diseño: una idea clara, coherencia visual y atención al detalle. La técnica está al servicio del diseño, no al revés.

Fase 1: planificación

Antes de abrir el editor de código, decide qué vas a hacer. Una web bien planificada se programa mucho más rápido.

1. Objetivo y público

Escribe en dos o tres frases para qué sirve tu web y quién la va a leer. No es lo mismo escribir para alguien de tu clase que para alguien que nunca ha visto una línea de código: la forma de explicar y el tono cambian.

2. Inventario de contenidos

Haz una lista de todo lo que va a aparecer: los temas que vas a explicar, las capturas, los ejemplos de código, las demos interactivas, la página de autoría y el formulario de dudas. Mejor pocos temas muy bien explicados que muchos a medias.

3. Arquitectura de la información

Dibuja el mapa del sitio: qué páginas tendrá la web y cómo se enlazan. Recuerda lo que vimos sobre el hipertexto en 1.º: mucha gente entrará directamente a la página de un tema desde un enlace, así que cada página debe entenderse por sí sola y dejar claro cómo volver.

4. Bocetos (wireframes)

Dibuja la estructura de cada tipo de página, primero en móvil y después en pantalla grande. Sólo cajas y textos de relleno, sin colores ni tipografías definitivas: el objetivo es decidir la distribución. Puedes hacerlo en papel o en Figma.

5. Guía de estilo

Define tu sistema visual antes de programarlo: paleta de colores (con su versión para el modo oscuro), las dos fuentes y sus tamaños, la escala de espacios y el estilo de los componentes (botones, tarjetas, enlaces). Todo esto se convertirá directamente en las variables de tu CSS.

6. Calendario

Reparte el tiempo disponible entre las tres fases y ponte fechas para cada una. Reserva al menos un cuarto del tiempo para la revisión: siempre hay más cosas que arreglar de las que parece.

Entrega de esta fase: un documento (o un tablero en Figma) con el objetivo, el mapa del sitio, los bocetos en móvil y escritorio, y la guía de estilo.

Fase 2: desarrollo

Construye la web por capas, de lo más básico a lo más avanzado. Cada capa debe funcionar antes de pasar a la siguiente. Así, si algo falla en JavaScript, la web sigue siendo usable: es lo que se llama mejora progresiva.

Organización de los archivos

web-apuntes/
├── index.html
├── html.html
├── css.html
├── javascript.html
├── dudas.html
├── css/
│   └── estilos.css
├── js/
│   └── main.js
└── img/
    ├── capturas/
    └── logo.svg

Capa 1: contenido y estructura (HTML)

Escribe todas las páginas con su contenido real y el HTML semántico, sin nada de CSS. Pásalas por el validador. Una página sin estilos tiene que poder leerse y usarse de principio a fin.

Capa 2: aspecto (CSS)

Empieza por las variables de tu guía de estilo y los estilos base, después la estructura (layout) para el móvil, luego los componentes, y al final las media queries para pantallas grandes. Ordena tu hoja de estilos en secciones con comentarios para encontrar cada cosa:

/* =========================================
   1. Variables (colores, fuentes, espacios)
   2. Base (box-sizing, body, img, enlaces)
   3. Layout (cabecera, main, pie, retículas)
   4. Componentes (botones, tarjetas, menú, visor)
   5. Utilidades y estados (.oculto, .activo…)
   6. Modo oscuro y movimiento reducido
   ========================================= */

Capa 3: comportamiento (JavaScript)

Añade la interactividad al final, componente a componente: primero el menú, después los hotspots y, si te da tiempo, lo opcional. Prueba cada uno antes de empezar el siguiente, y vigila la consola.

Truco: guarda copias de tu proyecto a medida que avanzas (por ejemplo, una carpeta comprimida con la fecha al final de cada sesión). Si algo se rompe y no sabes qué has cambiado, podrás volver a la última versión que funcionaba. Los profesionales lo hacen con un sistema de control de versiones llamado Git; si te interesa, la aplicación GitHub Desktop es una buena forma de empezar, y además facilita publicar en GitHub Pages.

Ojo: está bien buscar ayuda en internet, en tutoriales o en asistentes de inteligencia artificial, pero no copies código que no entiendes. Si usas un fragmento, asegúrate de que sabes explicar qué hace cada línea: en la presentación final te lo podemos preguntar.

Fase 3: revisión y publicación

Lista de revisión

Publicar

Como en Programación I, publica tu web con Netlify (arrastrando la carpeta a su web) o con GitHub Pages. Comprueba la versión publicada en el ordenador y en el móvil: a veces aparecen problemas que no se veían en local, casi siempre por mayúsculas en los nombres de archivo o rutas mal escritas.

Presentación

Prepara una presentación breve de tu web (unos cinco minutos), como si la enseñaras a un estudio en una entrevista:

  • Para quién es y qué querías transmitir.
  • Las decisiones de diseño más importantes: estructura, tipografía, color.
  • La parte técnica de la que estás más satisfecho o satisfecha, y cómo la resolviste.
  • Un problema que te costó resolver y qué aprendiste.

Fíjate: lo último es importante. Saber explicar cómo resolviste un problema dice más de ti a un estudio que una web sin ningún fallo.

Para saber más (opcional)

Una dirección propia

Si quieres que tu web tenga una dirección propia (tunombre.com o tunombre.es), puedes registrar un dominio por unos pocos euros al año y conectarlo a Netlify o a GitHub Pages siguiendo sus instrucciones.

Repasa la unidad

En PDF

Ponte a prueba

Al final de la página tienes un test con preguntas de toda la asignatura. Ir al test final

Ponte a prueba

¿Qué es un algoritmo?

  • Una serie de pasos ordenados y precisos para resolver un problema
  • Un lenguaje de programación
  • Un error en el código
  • Un tipo de archivo de JavaScript

Antes de escribir código hay que pensar los pasos con precisión: eso es el algoritmo. El pseudocódigo sirve para escribirlo en lenguaje normal.

¿Qué hace Emmet en Visual Studio Code?

  • Convierte abreviaturas, como nav>a*4, en código HTML completo
  • Sube la web al servidor
  • Corrige los errores de JavaScript
  • Comprime las imágenes

Ahorra mucho tiempo al escribir HTML: con una línea corta se genera toda una estructura.

¿Qué etiqueta crea un bloque que se abre y se cierra sin necesidad de JavaScript?

  • <details>, con <summary>
  • <dialog>
  • <aside>
  • <section>

El summary es el texto que se ve siempre, y al pulsarlo se despliega el resto del contenido.

¿Qué elementos selecciona .menu a?

  • Los enlaces que están dentro de un elemento con la clase menu
  • Los elementos con la clase menu y todos los enlaces
  • Sólo el primer enlace del menú
  • Los enlaces que tienen la clase menu

El espacio entre los dos selectores significa «dentro de»: es un selector descendiente.

¿Qué consigue font-size: clamp(1rem, 1rem + 4vw, 3rem)?

  • Que el texto crezca con la ventana, pero nunca baje de 1rem ni pase de 3rem
  • Que haya tres tamaños fijos, uno por dispositivo
  • Que el texto se reduzca si es muy largo
  • Que el tamaño cambie al pasar el ratón

Es la tipografía fluida: cambia de forma continua, no a saltos como con las media queries.

¿Qué valor de object-fit hace que una imagen llene su caja sin deformarse, recortando lo que sobra?

  • cover
  • contain
  • fill
  • none

Con contain la imagen se ve entera aunque sobre espacio, y con fill se deforma para ocupar toda la caja.

¿Qué resultado da "5" + 3 en JavaScript?

  • "53"
  • 8
  • Un error
  • "8"

Si uno de los dos es un texto, el + los une en lugar de sumarlos.

¿Qué hace elemento.classList.toggle("abierto")?

  • Añade la clase si no la tiene y la quita si la tiene
  • La añade siempre
  • La quita siempre
  • Comprueba si el elemento tiene esa clase

Es lo que se usa, por ejemplo, para abrir y cerrar un menú con el mismo botón.

En un array, ¿en qué posición está el primer elemento?

  • En la 0
  • En la 1
  • En la −1
  • Depende del array

Los arrays se cuentan desde 0: el primer elemento es lista[0].

¿Qué etiqueta de HTML usamos para crear una ventana modal?

  • <dialog>
  • <modal>
  • <popup>
  • <aside>

Con dialog.showModal() se abre por encima del resto de la página.

¿Con qué regla de CSS se definen los fotogramas clave de una animación?

  • @keyframes
  • @media
  • @animation
  • transition

Después, la animación se aplica a un elemento con la propiedad animation.

Al disparar animaciones con JavaScript, ¿cómo se reparten el trabajo CSS y JavaScript?

  • El CSS define el movimiento, y JavaScript sólo añade o quita una clase
  • JavaScript calcula cada fotograma de la animación
  • El CSS sólo pone los colores
  • No se pueden combinar

Así el código queda más limpio y el navegador anima de forma más fluida.

¿Qué diferencia una web dinámica de una estática?

  • La dinámica genera las páginas en el momento, a partir de una base de datos
  • La dinámica tiene animaciones
  • La dinámica se adapta al móvil
  • La dinámica usa JavaScript

WordPress es una web dinámica: cada página se fabrica con PHP y los datos de la base de datos.

¿En qué carpeta de WordPress se guardan los temas, los plugins y las imágenes subidas?

  • wp-content
  • wp-admin
  • wp-includes
  • themes

Es la carpeta con todo lo propio de tu web. wp-admin y wp-includes son de WordPress y no se tocan.

¿Por qué no se debe quitar el contorno del foco con outline: none?

  • Porque quien navega con el teclado deja de ver dónde está
  • Porque ralentiza la página
  • Porque es obligatorio para usar el ratón
  • Porque cambia los colores de los enlaces

Si no te gusta el contorno por defecto, cámbialo con :focus-visible, pero no lo quites.

¿Qué nivel de las pautas WCAG se toma como referencia habitual para que una web sea accesible?

  • AA
  • A
  • AAA
  • B

El nivel A es el mínimo, el AAA es muy exigente, y el AA es el que piden las normas, como la Ley Europea de Accesibilidad.