Ilustración y tipografía.
Unidad 1 · Introducción a la programación y al entorno
Ponemos a punto el portfolio 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 1º: 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 tu portfolio 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 portfolio
- Busca la carpeta de tu portfolio de 1º. Si sólo lo tienes publicado, descárgalo desde GitHub o Netlify.
- Ábrela en Visual Studio Code (Archivo → Abrir carpeta) y comprueba que la estructura está ordenada:
index.htmlen la raíz y carpetascsseimg. - Abre
index.htmlen el navegador y recorre todas las páginas. Apunta lo que no funcione o no te guste. - Haz una copia de seguridad de la carpeta tal y como está ahora, con la fecha en el nombre (
portfolio-septiembre). Al final del curso podrás comparar.
Ojo: si no tienes portfolio de 1º o no lo encuentras, no pasa nada: empieza uno nuevo con la estructura básica y una página de inicio con tu nombre, una presentación y tres proyectos. La revisión del apartado siguiente te servirá de guía.
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ón | Para qué |
|---|---|
| Spanish Language Pack | Pone los menús de VS Code en español. |
| Live Server | Abre tu web en el navegador y la recarga sola cada vez que guardas. |
| Prettier | Ordena el código siempre igual (sangrías, comillas, espacios). Se combina con Format On Save. |
| Auto Rename Tag | Al cambiar una etiqueta de apertura, cambia también la de cierre. |
| Error Lens | Muestra 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:
| Escribes | Obtienes |
|---|---|
! | La estructura básica completa de un documento HTML. |
ul>li*3 | Una lista con tres elementos. |
.tarjeta | <div class="tarjeta"></div> |
nav>a*4 | Un nav con cuatro enlaces. |
img | <img src="" alt=""> |
Atajos imprescindibles
| Acción | Windows | Mac |
|---|---|---|
| Comentar o descomentar la línea | Ctrl + / | Cmd + / |
| Mover la línea arriba o abajo | Alt + ↑ / ↓ | Opción + ↑ / ↓ |
| Duplicar la línea | Mayús + Alt + ↓ | Mayús + Opción + ↓ |
| Seleccionar la siguiente palabra igual | Ctrl + D | Cmd + D |
| Buscar un archivo del proyecto | Ctrl + P | Cmd + 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:
| Idea | Qué es | En diseño |
|---|---|---|
| Descomposición | Dividir un problema grande en partes pequeñas. | Diseñar una identidad: logotipo, paleta, tipografías, aplicaciones… |
| Patrones | Detectar lo que se repite. | Todas las tarjetas del portfolio tienen la misma estructura. |
| Abstracción | Quedarse con lo esencial e ignorar los detalles que no importan. | Un pictograma: un hombre con muletas no tiene cara ni ropa, pero se entiende. |
| Algoritmo | Escribir 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:
| Estructura | Qué hace | Ejemplo cotidiano |
|---|---|---|
| Secuencia | Pasos uno detrás de otro, en orden. | Encender el ordenador, abrir el navegador, escribir la dirección. |
| Decisión | Hacer una cosa u otra según una condición. | Si llueve, coge el paraguas; si no, las gafas de sol. |
| Repetición | Repetir 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:
| Forma | Significado |
|---|---|
| Óvalo | Inicio o fin. |
| Rectángulo | Una acción o proceso. |
| Rombo | Una decisión: una pregunta de sí o no, con dos salidas. |
| Paralelogramo | Entrada o salida de datos (recibir o mostrar algo). |
| Flecha | El orden: hacia dónde sigue el algoritmo. |
Este diagrama decide qué texto alternativo poner a una imagen, como vimos en Programación 1º:
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.
Práctica
Empieza sin ordenador y termina con el editor listo para todo el curso.
- 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?
- 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?). - Configura VS Code con los ajustes y las extensiones de este tema, y abre tu portfolio 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 portfolio: ¿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?
Unidad 2 · HTML5 y CSS3 avanzado
Repasamos lo esencial de 1º y damos un paso más: semántica, selectores avanzados, formularios de interfaz, estructuras complejas como las imágenes interactivas, Flexbox y Grid a fondo, y buenas prácticas.
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>
- Escribe el HTML.
- Dale estilo: fondo blanco, esquinas redondeadas, una sombra suave y relleno en el texto.
- Haz que la imagen ocupe todo el ancho de la tarjeta sin deformarse.
- Coloca tres tarjetas en una retícula que se adapte sola al ancho de la pantalla, con Grid.
- 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º.
Revisión guiada
Revisa tu portfolio 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 portfolio corregido y publicado de nuevo, con una lista breve de los cambios que has hecho. Será el punto de partida de todas las prácticas del curso.
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.
| Elemento | Para 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 la Unidad 5. |
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 la Unidad 8.
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 la Unidad 4 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:
| Combinador | Ejemplo | Selecciona |
|---|---|---|
| Descendiente (espacio) | nav a | Los a que estén dentro de un nav, a cualquier profundidad. |
Hijo directo > | nav > a | Sólo los a que estén justo en el primer nivel dentro del nav, no más adentro. |
Hermano siguiente + | h2 + p | El 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 ~ p | Todos 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;
}
| Proyecto | Año |
|---|---|
| Identidad cafetería | 2025 |
| Cartel festival | 2025 |
| Revista nº 3 | 2026 |
| Web del estudio | 2026 |
: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 Tema 4 de 1º según su estado:
| Pseudoclase | Cuándo se aplica |
|---|---|
:focus | Cuando el campo está activo, escribiendo en él. |
:checked | Una casilla o un botón de opción marcados. |
:disabled | Un campo desactivado. |
:required | Un campo obligatorio. |
:invalid / :valid | Un campo cuyo contenido no cumple / sí cumple lo que se pide (por ejemplo, un correo sin @). |
:user-invalid | Como :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:
| Pseudoelemento | Selecciona |
|---|---|
::before / ::after | Una 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-letter | La primera letra, para hacer una capitular. |
::first-line | La primera línea del párrafo, sea cual sea el ancho de la pantalla. |
::placeholder | El texto de ejemplo de un campo de formulario. |
::marker | Las viñetas o números de una lista. |
::selection | El texto que se selecciona con el ratón. |
/* Capitular en el primer párrafo de cada artículo */
article p:first-of-type::first-letter {
float: left;
font-size: 3.2em;
line-height: 1;
margin-right: 6px;
color: #576F6F;
}
/* Viñetas del color de la marca */
li::marker {
color: #C0812E;
}
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 portfolio: 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 (Tema 4 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):
| Estado | Selector | Qué debe comunicar |
|---|---|---|
| Normal | input | Que es un campo donde se puede escribir: un borde visible, no sólo una línea gris muy clara. |
| Foco | :focus-visible | Dónde estás escribiendo. Imprescindible para quien usa el teclado. |
| Error | :user-invalid | Que algo está mal, y qué. El color solo no basta: acompáñalo de un texto. |
| Desactivado | :disabled | Que 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 { /* 1. la capa oscura */
content: "";
position: absolute;
inset: 0;
background: linear-gradient(transparent 40%, rgba(0, 0, 0, 0.75));
}
.tarjeta h3 { /* 2. el título, encima de la capa */
position: absolute;
left: 16px;
bottom: 12px;
z-index: 1;
color: white;
}
- La tarjeta lleva
relativepara ser la referencia. ::aftercrea una capa coninset: 0que cubre toda la tarjeta, con un degradado de transparente a negro.- El título se coloca con
absoluteabajo a la izquierda, y conz-indexpor 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.
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; /* 1. la imagen es la referencia */
margin: 0;
}
.mapa img {
display: block;
width: 100%;
height: auto;
}
.punto {
position: absolute; /* 2. cada punto, colocado en % */
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; /* 3. la ficha, encima del punto */
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 { /* 4. visible al pasar el ratón o con el teclado */
opacity: 1;
visibility: visible;
}
- La
<figure>llevarelative: es la referencia de los puntos. - Cada punto se coloca con
leftytopen porcentaje. Las coordenadas se pasan como variables en el atributostyle(--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. - La ficha va dentro del punto, colocada encima con
absolute, y empieza oculta. - Con
:hovery:focus-visiblese 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 la Unidad 4.
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
/* 1. Logotipo a un lado y menú al otro */
.cabecera {
display: flex;
justify-content: space-between;
align-items: center;
}
/* 2. Empujar un elemento hasta el final con un margen automático */
.menu .boton-contacto {
margin-left: auto;
}
/* 3. Tarjetas con el botón siempre abajo, aunque el texto mida distinto */
.tarjeta {
display: flex;
flex-direction: column;
}
.tarjeta .boton {
margin-top: auto;
}
/* 4. Etiquetas que saltan de línea cuando no caben */
.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
auto-fit: las columnas vacías desaparecen y los elementos se estiran
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; }
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:
.avisomejor 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 aes mejor queheader nav ul li a, que se rompe en cuanto cambias el HTML. - No uses
!importantpara 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 {
/* Colores con nombre de FUNCIÓN, no de aspecto */
--color-fondo: #F7F6F2;
--color-texto: #21231F;
--color-suave: #5B5D57;
--color-acento: #576F6F;
/* Una escala de espacios a partir de un valor base */
--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.
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); /* mezcla % y rem */
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: #C0812E; /* solo cambia la variable, no las reglas */
}
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: #576F6F;
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). Conviene conocerlo porque aparece en webs antiguas, pero hoy se usa la técnica siguiente.
Práctica
Partimos del portfolio que pusiste a punto en la Unidad 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>. - Diseña el formulario de contacto con todos sus estados: normal, foco, error y desactivado.
- Convierte las tarjetas de tu galería en tarjetas con el título sobre la imagen: capa con degradado y título encima.
- Elige un trabajo tuyo (un cartel, una ilustración, una infografía) y crea una versión interactiva con al menos cuatro hotspots que expliquen tus decisiones de diseño.
- 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)oa[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?
Unidad 3 · 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.
Mobile first y media queries
En 1º aprendiste a escribir media queries y a trabajar mobile first: primero los estilos del móvil, y después los cambios para pantallas más grandes con min-width. En esta unidad 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 por | El diseño de ordenador, y se va quitando | El diseño de móvil, y se va añadiendo |
| El móvil carga | Todos los estilos de ordenador, más los que los deshacen | Sólo los estilos que necesita |
| Resultado habitual | Muchas reglas para «arreglar» el móvil | Un 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.
- Abre tu web en el inspector con el modo de dispositivo (Ctrl + Mayús + M).
- Ve ensanchando la ventana poco a poco desde el ancho del móvil.
- 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 query | Se 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 (Unidad 6). |
/* El efecto de levantar la tarjeta, sólo con ratón */
@media (hover: hover) {
.tarjeta:hover {
transform: translateY(-6px);
}
}
Lista de comprobación responsive
Tipografía fluida con clamp()
Con las media queries de 1º, 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:
- El mínimo: nunca será más pequeño (en el móvil).
- El valor ideal, que depende del ancho de la pantalla (lleva
vw). - 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); /* más aire en pantallas grandes */
}
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 deformacontain: cabe entera, deja huecoscover: rellena y recortaLa 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: #576F6F;
}
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: #A5BEBE; /* el verde, más claro para que contraste */
}
}
Y ya está: como todo el CSS usa las variables, todo cambia a la vez.
Fondo claro, texto oscuro y el verde original.
BotónLas mismas variables con otros valores.
BotónPaso 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 la Unidad 4.
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
| Unidad | Altura 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; /* 1. este elemento es un contenedor «consultable» */
}
.tarjeta {
display: grid; /* 2. por defecto: imagen arriba, texto abajo */
gap: 1rem;
}
@container (min-width: 400px) { /* 3. si el CONTENEDOR mide 400px o más… */
.tarjeta {
grid-template-columns: 150px 1fr; /* …imagen a la izquierda, texto a la derecha */
}
}
La misma tarjeta, en un contenedor estrecho…
…y en uno ancho
Ilustración y tipografía.
- Al contenedor se le da
container-type: inline-size, que significa «se puede consultar mi ancho». - Se escriben los estilos del componente para el caso pequeño.
- 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.
Práctica
Seguimos con tu portfolio.
- Revisa tu CSS: ¿es mobile first? Si usas
max-width, pásalo amin-width, empezando por los estilos del móvil. - 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.
- Pon el tamaño de los títulos con
clamp(), con una parte enrem. Comprueba que el texto sigue creciendo al hacer zoom. - Iguala las imágenes de la galería con
aspect-ratioyobject-fit: cover. - Mete los efectos de
:hoverdentro 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.
Unidad 4 · 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.
- Abre el inspector con F12 (en Mac, Cmd + Option + I).
- Ve a la pestaña Consola (Console).
- 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>
srces la ruta al archivo, como en las imágenes.deferle 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.logfunciona;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
constcrea una variable cuyo valor no va a cambiar (una constante).letcrea 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:
numeroDeColumnasmejor quenodato1. - Mejor sin tildes ni eñes (aunque funcionan), y nunca empezando por un número.
Tipos de datos
| Tipo | Qué guarda | Ejemplo |
|---|---|---|
| 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
| Operador | Qué hace | Ejemplo | Resultado |
|---|---|---|---|
+ | Suma | 10 + 2 | 12 |
- | Resta | 10 - 2 | 8 |
* | Multiplica | 10 * 2 | 20 |
/ | Divide | 10 / 2 | 5 |
% | Resto de una división | 10 % 3 | 1 |
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:
| Operador | Pregunta |
|---|---|
=== | ¿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. elsees 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:
- Seleccionar el elemento con el que quieres trabajar.
- Escuchar lo que hace el usuario (un clic, escribir, pulsar una tecla).
- 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 confor…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étodo | Qué 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
| Evento | Cuándo ocurre |
|---|---|
click | Al hacer clic (o tocar, en el móvil). |
input | Cada vez que cambia el valor de un campo: al escribir, mover un deslizador, elegir un color… |
submit | Al enviar un formulario. |
keydown | Al pulsar una tecla. |
mouseenter / mouseleave | Cuando el ratón entra en un elemento / sale de él. |
scroll | Al 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 la Unidad 6.
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 la Unidad 2 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 la Unidad 1: 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:!trueesfalse.
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 la Unidad 3 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.
Práctica
Trabaja en el archivo js/main.js de tu portfolio.
- Crea la carpeta
jscon el archivomain.js, enlázalo condefery comprueba en la consola que funciona unconsole.log(). - Crea variables con tu nombre y tu ciudad y muestra una frase que las use, con comillas invertidas y
${ }. - Crea una función
anchoReticula()como la de esta unidad y úsala con unifque avise si la retícula mide más de 1200px. - Haz un menú desplegable para el móvil con un botón,
classList.toggle()yaria-expanded. En pantallas grandes, el menú debe verse siempre (usa una media query). - 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?
Unidad 5 · Interactividad aplicada al diseño
Colecciones de datos y lógica para construir componentes visuales: galerías generadas a partir de datos, ventanas modales y sliders.
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. .lengthdice 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:
document.createElement("article")crea un elemento nuevo, todavía fuera de la página.- Se le dan clases y contenido.
innerHTMLfunciona comotextContent, pero entiende etiquetas HTML. .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: fixedque cubre toda la pantalla (Programación 1º). Empieza oculto con el atributohidden. - Al pulsar una imagen, se copian su
srcy sualta la imagen grande y se muestra el visor. - Un evento
keydownen 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 portfolio, 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.
- Todas las diapositivas están en fila dentro de la pista, y el slider esconde con
overflow: hiddentodo lo que no cabe. - La variable
actualguarda qué diapositiva se ve: 0, 1 o 2. - Los botones suman o restan 1 a
actual, con unifpara dar la vuelta al llegar a un extremo. - La función
mostrar()desplaza la pista contransform, y latransitiondel 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.
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:
let i = 1— el contador empieza en 1.i <= 5— el bucle sigue mientras el contador sea menor o igual que 5.i++— al final de cada vuelta, el contador suma 1 (es lo mismo quei = 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.
Práctica
Trabaja en el js/main.js de tu portfolio.
- Guarda tus proyectos en un array de objetos (título, año, imagen) y genera con un bucle las tarjetas de la galería.
- Haz que al pulsar una imagen de la galería se abra en grande en una ventana modal, que se cierre con un botón y con Esc.
- En la página de uno de tus proyectos, enseña el proceso (boceto, versiones, resultado) en un slider.
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.
- Añade botones para filtrar la galería por tipo de proyecto.
Comprueba: ¿todo funciona con el teclado? ¿Al cerrar la ventana modal vuelves a donde estabas? ¿La consola muestra algún error en rojo?
Unidad 6 · Animaciones y efectos visuales
Transiciones, transformaciones y animaciones de CSS, y cómo ponerlas en marcha con JavaScript: al pulsar un botón o al llegar con el scroll.
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.
Las funciones de transform
| Función | Qué 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
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.
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:
- Con
@keyframesse define la animación y se le da un nombre: los fotogramas clave, como en un programa de animación. - Con la propiedad
animationse 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;
}
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:
/* Las animaciones solo se aplican si la persona NO 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;
}
}
Animaciones disparadas con JavaScript
Las transiciones y las animaciones de CSS 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.2indica 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.
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; /* espera antes de empezar */
animation-iteration-count: 1; /* o infinite */
animation-direction: normal; /* o alternate: ida y vuelta */
animation-fill-mode: both; /* conserva el primer y el último fotograma */
}
/* Todo junto, en una línea */
.elemento {
animation: aparecer 0.8s ease-out 0.2s both;
}
| Propiedad | Qué controla |
|---|---|
animation-duration | Cuánto dura una vuelta. |
animation-timing-function | La curva de aceleración: ease, ease-out, linear… |
animation-delay | Cuánto espera antes de empezar. |
animation-iteration-count | Cuántas veces se repite (infinite para siempre). |
animation-direction | alternate hace ida y vuelta, sin saltos. |
animation-fill-mode | both 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 filtrograyscale(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-modefusiona un elemento con lo que tiene detrás.background-blend-modefusiona 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: #576F6F;
background-blend-mode: multiply; /* la foto se tiñe del color */
background-size: cover;
}
normalmultiplyscreenluminositymix-blend-mode: differenceOjo: 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.
Práctica
Seguimos con tu portfolio.
- Añade una animación de entrada al título de la portada con
@keyframes, dentro deprefers-reduced-motion: no-preference. - Haz que los hotspots de tu imagen interactiva latan suavemente.
- Haz que las tarjetas de la galería aparezcan al llegar a ellas con el scroll, con
IntersectionObserver. - Revisa tus transiciones: ¿animas sólo
transformyopacity?
Retos opcionales
- Haz que las tarjetas aparezcan escalonadas, una detrás de otra.
- Haz que las imágenes de la galería se vean en blanco y negro y recuperen el color al pasar el ratón, con
filter.
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?
Unidad 7 · 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 Tema 0 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ática | Web dinámica | |
|---|---|---|
| Qué guarda el servidor | Archivos HTML, CSS, JS e imágenes ya terminados | Un programa y una base de datos con el contenido |
| Qué hace al recibir una petición | Envía el archivo pedido | Ejecuta el programa, que consulta la base de datos y genera el HTML |
| Lenguajes en el servidor | Ninguno | PHP, Python, JavaScript (Node.js)… |
| Para actualizar el contenido | Hay que editar el código | Se usa un panel de administración |
| Ejemplos | Un portfolio, una página de presentación | Un 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.
- 01PeticiónEl navegador pide
/blog/. - 02PHPEn el servidor, el programa recibe la petición y decide qué hace falta.
- 03Base de datosPHP pide con SQL las diez últimas entradas.
- 04HTMLPHP 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:
| id | titulo | fecha | categoria |
|---|---|---|---|
| 1 | Cartel para el festival | 2026-10-02 | Ilustración |
| 2 | Nueva identidad del estudio | 2026-10-15 | Identidad |
| 3 | Taller de tipografía | 2026-11-03 | Noticias |
- 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 la Unidad 5. 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 Tema 1 de Medios II). En Local, el botón Go to site folder abre la carpeta con todos sus archivos.
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: Mi portfolio 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
- Instala el plugin Create Block Theme desde Plugins › Añadir nuevo plugin.
- 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.jsony las plantillas. - 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": "#576F6F" }
]
},
"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
- 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.
- 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. - 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.
Práctica
- 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.
- Instala WordPress con Local y localiza las carpetas
themes,pluginsyuploads. Sube una imagen desde el panel y búscala enuploads. - Crea un tema de bloques con Create Block Theme y traslada a
theme.jsonla paleta y el ancho de contenido de tu portfolio. - Construye en el editor del sitio la cabecera y el pie de tu portfolio, y guárdalos en el tema.
Retos opcionales
- Añade a
theme.jsonlas tipografías de tu portfolio. - Abre
style.cssde tu tema y añade algún detalle que los bloques no permitan, con una clase CSS adicional.
Unidad 8 · 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 portfolio, completo y publicado.
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:
| Principio | Qué significa | Ejemplos |
|---|---|---|
| Perceptible | Toda la información se puede percibir con algún sentido. | Texto alternativo en las imágenes, subtítulos en los vídeos, contraste suficiente. |
| Operable | Todo se puede usar, con cualquier dispositivo. | Todo funciona con el teclado, hay tiempo suficiente, nada parpadea de forma peligrosa. |
| Comprensible | El contenido y el funcionamiento se entienden. | Idioma de la página declarado, menús coherentes, errores de formulario explicados. |
| Robusto | Funciona 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:
| Tecla | Qué hace |
|---|---|
| Tab / Mayús + Tab | Pasa al siguiente / al anterior elemento interactivo (enlaces, botones, campos). |
| Intro | Sigue un enlace o pulsa un botón. |
| Espacio | Pulsa un botón, marca una casilla o baja la página. |
| Esc | Cierra una ventana modal o un menú. |
| Flechas | Se mueven dentro de un grupo de opciones o un desplegable. |
Las cuatro reglas
- 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 eventoclickno se puede alcanzar con Tab. - Que se vea dónde está el foco. Nunca escribas
outline: nonesin poner otra cosa a cambio. Dale estilo con:focus-visible. - Que el orden tenga sentido. El foco sigue el orden del HTML, no el visual. Si con Grid o con
ordercambias mucho el orden en pantalla, el recorrido con Tab saltará de un lado a otro. - 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 portfolio. 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
| Herramienta | Qué revisa |
|---|---|
| Lighthouse | Viene 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. |
| WAVE | Una 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 W3C | Que el HTML no tenga errores, la base de todo lo demás. |
| Comprobador de contraste | El 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 ampliar tu portfolio para que sea tu carta de presentación profesional: la web que enseñarías en una entrevista de prácticas o de trabajo. Partes de la versión que pusiste a punto en la Unidad 1 y la mejoras con lo que has aprendido este curso.
Trabájalo como un encargo real de diseño, en tres fases:
- Planificación: qué vas a contar, a quién y cómo se organiza.
- Desarrollo: construir la web por capas, de lo básico a lo interactivo.
- 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 portfolio 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 portfolio y quién lo va a ver. No es lo mismo buscar prácticas en un estudio de identidad corporativa que en una agencia de diseño web o en una editorial: la selección de trabajos y el tono cambian.
2. Inventario de contenidos
Haz una lista de todo lo que va a aparecer: los proyectos que vas a enseñar (mejor seis muy buenos que quince irregulares), tu presentación, tus datos de contacto, tus redes. Para cada proyecto, reúne las imágenes y escribe un texto breve: el encargo, tu solución y las herramientas que usaste.
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 proyecto 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
mi-portfolio/
├── index.html
├── proyectos.html
├── contacto.html
├── css/
│ └── estilos.css
├── js/
│ └── main.js
└── img/
├── proyectos/
└── 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 1º, 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 portfolio (unos cinco minutos), como si se lo 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 portfolio 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.