Skip to content

~/nube/p00 $ cat 04-web-html-y-tailwind.md

  • Introducción a la nube pública
  • P00
  • lección 04/06

Web HTML y Tailwind CSS

Edita una web en p00-lab, sírvela mediante Nginx y aplica Tailwind CSS de forma guiada.

En P00/03 creaste una página inicial en web/index.html. Ahora la convertirás en una pequeña página de comprobación. La editarás desde tu contenedor p00-lab y Nginx la servirá desde un segundo contenedor llamado p00-web. Finalmente mejorarás su presentación con Tailwind CSS.

No son dos copias de la página. Los dos contenedores leen la misma carpeta del anfitrión, pero cada uno la ve en una ruta distinta:

Carpeta del anfitrión
optativa-nube/p00-puesto-nube/web/index.html
│ │
│ │
▼ ▼
p00-lab (alumno) p00-web (Nginx)
/optativa-nube/.../web /usr/share/nginx/html
edita el archivo lo sirve por HTTP
│
▼
navegador: http://localhost:8080/

Al terminar podrás explicar esta idea: el archivo permanece en la carpeta compartida; p00-lab lo modifica y Nginx lo publica sin copiarlo entre contenedores.

Antes de empezar: HTML, servidor web, puerto y Tailwind

Section titled “Antes de empezar: HTML, servidor web, puerto y Tailwind”

HTML describe la estructura y el contenido de una página: títulos, párrafos, enlaces y secciones. El navegador interpreta ese archivo y lo muestra.

Nginx es un servidor web. En esta práctica no lo instalas dentro de p00-lab: ya está incluido en una imagen Docker. Nginx leerá tu carpeta web/ mediante un montaje de solo lectura.

Un puerto es una puerta numerada para comunicar programas. Nginx escucha en el puerto 80 dentro de su contenedor. Publicaremos ese puerto como 8080 en el anfitrión, por eso abrirás http://localhost:8080/.

CSS es el lenguaje que controla la presentación: tamaño, color, separación y distribución. Tailwind CSS reúne estilos preparados en pequeñas clases de utilidad que aplicarás a las etiquetas HTML. Primero comprobarás HTML, Nginx y HTTP; después aprenderás a usar esas clases desde un ejemplo con una sola clase.

1. Terminal A: preparar la página en p00-lab

Section titled “1. Terminal A: preparar la página en p00-lab”

Abre una primera terminal. Esta será la Terminal A, que conservarás abierta mientras trabajas. Desde el anfitrión, entra en p00-lab como alumno y comprueba la página creada en P00/03:

Terminal window
docker start -ai p00-lab
su - alumno
cd /optativa-nube/p00-puesto-nube
ls -l web/index.html

Abre el archivo:

Terminal window
nano web/index.html

Sustituye su contenido por esta versión inicial, sin estilos:

<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>P00 · Web local</title>
</head>
<body>
<main>
<p>P00 · Docker</p>
<h1>Mi web local funciona</h1>
<p>Nginx sirve este archivo desde la carpeta compartida.</p>
</main>
</body>
</html>

Guarda con Ctrl+O, confirma con Intro y sal con Ctrl+X. No salgas de p00-lab: la Terminal A seguirá siendo tu lugar para editar.

2. Terminal B: iniciar Nginx desde el anfitrión

Section titled “2. Terminal B: iniciar Nginx desde el anfitrión”

Abre una segunda terminal. Esta será la Terminal B y se queda en el anfitrión. No ejecutes estas órdenes dentro de p00-lab.

En macOS o Linux, sitúate en la carpeta del proyecto:

Terminal window
cd "$HOME/optativa-nube/p00-puesto-nube"

En Windows PowerShell, usa:

Terminal window
Set-Location "$HOME\optativa-nube\p00-puesto-nube"

Inicia Nginx con el montaje de la carpeta web/:

Terminal window
docker run --detach --rm --name p00-web \
--publish 127.0.0.1:8080:80 \
--volume "$PWD/web:/usr/share/nginx/html:ro" \
nginx@sha256:adad2ae9204d0fd7a34f40299bc838c3782be1293b10005eac4315ff5a1abf4e

En Windows PowerShell, usa el montaje equivalente:

Terminal window
docker run --detach --rm --name p00-web --publish 127.0.0.1:8080:80 --mount "type=bind,source=$($PWD.Path)\web,target=/usr/share/nginx/html,readonly" nginx@sha256:adad2ae9204d0fd7a34f40299bc838c3782be1293b10005eac4315ff5a1abf4e

Lee la orden de izquierda a derecha:

  • --detach deja Nginx en funcionamiento mientras usas la Terminal A.
  • --rm elimina este contenedor temporal al detenerlo.
  • --name p00-web permite identificarlo sin dudas.
  • 127.0.0.1:8080:80 conecta el puerto 8080 del anfitrión con el puerto 80 de Nginx. Solo se puede abrir desde tu propio equipo.
  • El montaje une web/ con /usr/share/nginx/html. :ro significa que Nginx puede leer el HTML, pero no modificarlo.

En el navegador del anfitrión, abre:

http://localhost:8080/

Debes ver «Mi web local funciona». En la Terminal B, confirma que el contenedor está activo:

Terminal window
docker ps --filter name=p00-web

En macOS o Linux, comprueba también la respuesta HTTP:

Terminal window
curl --head --show-error http://localhost:8080/

En Windows PowerShell, usa:

Terminal window
curl.exe --head --show-error http://localhost:8080/

La respuesta debe incluir HTTP/1.1 200 OK. Si la página no aparece, consulta solo los registros de este contenedor:

Terminal window
docker logs p00-web

4. Demostrar que ambos contenedores ven el mismo archivo

Section titled “4. Demostrar que ambos contenedores ven el mismo archivo”

Vuelve a la Terminal A, que sigue dentro de p00-lab. Edita el párrafo de la página:

Antes de guardar, decide qué esperas que ocurra: ¿tendrás que reiniciar p00-web para ver el cambio? Compruébalo en el siguiente paso y explica el resultado con tus palabras.

Terminal window
nano web/index.html

Cambia el texto por otro que te identifique, guarda y actualiza el navegador con F5. El cambio debe aparecer sin ejecutar docker restart, sin crear otro contenedor y sin volver a ejecutar docker run.

La razón es el montaje: Nginx no tiene una copia independiente de tu página. Lee el mismo archivo que acabas de guardar desde p00-lab.

5. Tailwind CSS: clases de utilidad, una mejora cada vez

Section titled “5. Tailwind CSS: clases de utilidad, una mejora cada vez”

Tu página ya responde por HTTP. Ahora mejorarás su presentación editando el mismo web/index.html, en la Terminal A, como alumno dentro de p00-lab, desde /optativa-nube/p00-puesto-nube. Nginx sigue funcionando; no tienes que reconstruir una imagen ni reiniciar contenedores.

Trabaja con este ciclo: cambia una cosa → guarda → recarga el navegador → observa su efecto. Conserva los cambios al pasar al siguiente paso, salvo que se indique sustituirlos. Los ejemplos de una misma etiqueta son versiones sucesivas: no añadas varios títulos o varios body.

5.1 Entender class antes de escribir clases

Section titled “5.1 Entender class antes de escribir clases”

Una clase es un nombre que asignas a un elemento HTML mediante el atributo class para poder seleccionarlo y aplicarle estilos CSS. Puedes reutilizar la misma clase en varios elementos y asignar varias clases a un elemento, separándolas por espacios. Tailwind usa clases de utilidad: cada una tiene estilos ya definidos para una tarea concreta, como cambiar el tamaño del texto, el color o la separación. Al escribirlas en class, eliges qué estilos aplicar; el nombre de una clase por sí solo no crea un estilo si no hay CSS que lo defina.

Un ID es un identificador que asignas mediante el atributo id, por ejemplo, id="titulo-principal". Su valor debe ser único dentro de la página: te permite identificar un elemento concreto, enlazar directamente a él o seleccionarlo desde CSS o JavaScript. Una clase se puede compartir entre elementos; un ID identifica uno solo. En esta práctica aplicarás los estilos de Tailwind mediante class; un elemento puede tener también un id si necesitas identificarlo.

Una etiqueta indica qué contenido tienes. Por ejemplo, h1 es el título principal. Mira cómo le añades una clase:

<h1>Mi web local funciona</h1>
<h1 class="text-3xl">Mi web local funciona</h1>

En la segunda línea, text-3xl es el nombre de una clase de Tailwind que establece un tamaño de letra grande. Se escribe en la etiqueta de apertura; el texto y el cierre </h1> se conservan. Este ejemplo es para comparar: en tu página mantendrás un único h1.

Puedes combinar varias clases dentro de las mismas comillas, separadas por espacios: class="text-3xl font-bold". No se separan por comas. Cada utilidad tiene un propósito: una ajusta el tamaño y otra el grosor. Una clase inventada o mal escrita no produce el efecto esperado.

5.2 Cargar Tailwind y reconocer sus estilos iniciales

Section titled “5.2 Cargar Tailwind y reconocer sus estilos iniciales”

Abre web/index.html con nano, como en el apartado 4. Dentro de head, justo después de la etiqueta title, añade esta línea:

<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Esta línea carga Tailwind 4 en el navegador desde una CDN, una red que distribuye archivos por Internet. No instala Tailwind en Debian ni en Nginx. Necesitas conexión a Internet para que el navegador lo descargue. Este método se utiliza aquí para aprender y hacer pruebas locales; la documentación oficial lo reserva a desarrollo.

Guarda y recarga. La página puede cambiar incluso sin añadir clases: Tailwind incluye unos estilos de base llamados Preflight, que eliminan márgenes predeterminados y hacen que los títulos pierdan su tamaño y grosor habituales. Si el título parece ahora un párrafo, es un resultado esperado. A continuación recuperarás su jerarquía de forma explícita. Documentación de Preflight.

5.3 Primera utilidad: el tamaño del título

Section titled “5.3 Primera utilidad: el tamaño del título”

La clase text-3xl establece el tamaño del texto. Sustituye solamente tu línea h1 por esta:

<h1 class="text-3xl">Mi web local funciona</h1>

Guarda y recarga: el título debe verse mayor que los párrafos. Si no ocurre, comprueba la escritura de class, las comillas y la carga del script. Que Nginx responda 200 OK no demuestra que el navegador haya podido descargar Tailwind.

Ahora compara otros tamaños. Cambia solo text-3xl por text-xl, guarda y observa. Después recupera text-3xl. No dejes ambas clases de tamaño en la misma etiqueta: sustituye la que quieres cambiar.

La clase font-bold aplica negrita. Añádela al título que ya tienes:

<h1 class="text-3xl font-bold">Mi web local funciona</h1>

Guarda y recarga: el tamaño se mantiene y cambia el grosor.

Para el color del texto usarás text-teal-700: teal identifica una familia de tonos verde azulado y 700 un tono de esa familia. En estas paletas, los números menores suelen ser más claros y los mayores más oscuros. Añade la clase:

<h1 class="text-3xl font-bold text-teal-700">Mi web local funciona</h1>

Guarda y recarga: ahora puedes reconocer tres decisiones independientes. Aunque empiezan por text-, text-3xl controla tamaño y text-teal-700 controla color. Lee el nombre completo.

5.5 Fondo y espacio interior: distinguir bg- y p-

Section titled “5.5 Fondo y espacio interior: distinguir bg- y p-”

bg- cambia el fondo del elemento. Aplica primero solo bg-slate-100 a la etiqueta de apertura de body; slate es una familia de grises y 100 un tono claro:

<body class="bg-slate-100">

Guarda y recarga. El fondo debe cambiar, pero el contenido todavía puede quedar pegado al borde.

El padding es el espacio interior entre el borde de un elemento y su contenido. La clase p-4 añade ese espacio a sus cuatro lados. Añádela:

<body class="bg-slate-100 p-4">

Guarda y recarga: el texto se separa de los bordes de la página. Predice qué ocurrirá si cambias p-4 por p-8, compruébalo y después deja p-4.

Los números de espaciado representan pasos de una escala, no píxeles escritos directamente. Con la configuración predeterminada, p-4 equivale a 1rem y p-8 a 2rem; si el tamaño raíz es 16 píxeles, son 16 y 32 píxeles respectivamente. Para empezar basta con reconocer que p-8 deja más espacio que p-4.

5.6 Construir una tarjeta con clases que puedas explicar

Section titled “5.6 Construir una tarjeta con clases que puedas explicar”

Una tarjeta agrupa información relacionada sobre un fondo delimitado. No es una etiqueta especial ni una clase llamada card: la construirás combinando HTML y utilidades. Tu main contendrá la tarjeta de comprobación.

Primero dale un fondo blanco con bg-white:

<main class="bg-white">

Guarda y observa el rectángulo blanco. El contenido aún toca sus bordes. Añade el padding que acabas de aprender:

<main class="bg-white p-4">

Guarda y compara: p-4 en body separa la tarjeta del borde de la ventana; p-4 en main separa el texto del borde de la tarjeta.

Ahora limita y centra la tarjeta. max-w-2xl fija una anchura máxima; permite que se estreche si no cabe. mx-auto reparte automáticamente los márgenes izquierdo y derecho para centrarla cuando sobra espacio. Añade primero max-w-2xl, guarda y observa; después añade mx-auto y vuelve a comprobar:

<main class="bg-white p-4 max-w-2xl mx-auto">

Por último, rounded-lg redondea las esquinas y shadow-md añade una sombra. Añade una, guarda y observa; después añade la otra:

<main class="bg-white p-4 max-w-2xl mx-auto rounded-lg shadow-md">

La tarjeta ya tiene fondo, espacio interior, anchura máxima, centrado, esquinas y sombra. Puedes leer la línea como una lista de decisiones, sin memorizarla como una fórmula.

5.7 Separar los textos: margen frente a padding

Section titled “5.7 Separar los textos: margen frente a padding”

El margen es espacio exterior: separa un elemento de los demás. El padding que has usado deja espacio dentro. En mt-4, m indica margen y t indica arriba (top). Antes de combinar más estilos, añade solo ese margen al párrafo situado después del título:

<p class="mt-4">Nginx sirve este archivo desde la carpeta compartida.</p>

Guarda y recarga: aparece separación entre el título y este párrafo.

Ya conoces los colores de texto. Para diferenciar los textos secundarios, usarás también text-sm, que reduce el tamaño. Aplica al párrafo anterior al título las clases text-sm y text-slate-600; al párrafo posterior añádele text-slate-600, conservando mt-4:

<p class="text-sm text-slate-600">P00 · Docker</p>
<h1 class="text-3xl font-bold text-teal-700">Mi web local funciona</h1>
<p class="mt-4 text-slate-600">Nginx sirve este archivo desde la carpeta compartida.</p>

Este es el resultado acumulado del texto de la tarjeta. Si habías personalizado el párrafo en el apartado 4, conserva tu mensaje.

Para leer las variantes de espaciado, usa esta referencia:

Clase Dónde deja espacio
p-4 Dentro, en los cuatro lados.
px-4 Dentro, a izquierda y derecha: eje horizontal.
py-2 Dentro, arriba y abajo: eje vertical.
mt-4 Fuera, por encima del elemento.
mb-4 Fuera, por debajo del elemento.
mx-auto Márgenes horizontales automáticos; permite centrar un bloque con anchura limitada.

Además de tarjetas, las páginas suelen usar avisos: bloques breves que comunican un resultado. Añade este párrafo después de la descripción y antes de </main>:

<p class="mt-4">HTTP 200 · Nginx activo</p>

Guarda y comprueba que aparece. Después aplica las utilidades conocidas: bg-teal-100 para un fondo verde azulado claro, text-teal-900 para texto oscuro y p-4 para espacio interior. Por último añade rounded-lg, como en la tarjeta. El resultado será:

<p class="mt-4 bg-teal-100 text-teal-900 p-4 rounded-lg">HTTP 200 · Nginx activo</p>

El texto comunica el resultado, además del color. Es una etiqueta estática escrita por ti: úsala para reflejar la comprobación del apartado 3. No consulta Nginx ni cambia automáticamente si el servidor falla.

5.9 Un enlace con aspecto de botón: estados hover y focus

Section titled “5.9 Un enlace con aspecto de botón: estados hover y focus”

Un enlace a lleva a una dirección; su atributo href indica el destino. Un botón HTML button se usa para acciones, como enviar un formulario. Aquí necesitas volver a abrir la página, por lo que usarás un enlace, aunque tenga aspecto de botón.

Primero añade este enlace debajo del aviso:

<a href="http://localhost:8080/">Actualizar comprobación</a>

Guarda y púlsalo: navega a tu página. Todavía no tiene fondo ni espacio interior.

Ahora introduce inline-block: permite que el enlace conserve su tamaño según el contenido y se comporte como una caja a la que puedes aplicar margen vertical y padding. Añade inline-block y mt-4; guarda y observa la separación respecto al aviso.

Combina después dos clases que ya sabes interpretar: bg-sky-700 para el fondo azul y text-white para el texto blanco. Guarda y observa. Añade luego px-4 py-2 para separar el texto de los bordes horizontal y verticalmente, y rounded-lg para redondear. Antes de añadir interacciones, tendrás:

<a class="inline-block mt-4 bg-sky-700 text-white px-4 py-2 rounded-lg" href="http://localhost:8080/">Actualizar comprobación</a>

Una variante aplica una utilidad solo bajo cierta condición. hover:bg-sky-800 significa «al situar el puntero encima, usa este fondo». Añádela, guarda y mueve el ratón sobre el enlace. En dispositivos sin un puntero que permita hover, esa prueba puede no producir el mismo efecto.

El foco identifica el elemento seleccionado para usarlo con teclado. focus:outline-2 dibuja un contorno cuando el enlace tiene foco; focus:outline-offset-2 lo separa del borde. Añade las dos y prueba con Tab hasta llegar al enlace, y con Intro para activarlo. La versión final es:

<a class="inline-block mt-4 bg-sky-700 text-white px-4 py-2 rounded-lg hover:bg-sky-800 focus:outline-2 focus:outline-offset-2" href="http://localhost:8080/">Actualizar comprobación</a>

La navegación la proporciona HTML. Tailwind define su presentación y sus estados visuales; no realiza una comprobación HTTP adicional.

5.10 Reconocer otros componentes habituales

Section titled “5.10 Reconocer otros componentes habituales”

Ya has construido una tarjeta, un aviso y un enlace con aspecto de botón. Un componente es una pieza de interfaz con una función reconocible; puedes construirlo con varias etiquetas y utilidades. Tailwind aporta las utilidades, no la lógica de una aplicación.

Los siguientes ejemplos son de consulta para reconocer dos componentes frecuentes. No forman parte de la página mínima ni añaden entregables.

Navegación. nav agrupa enlaces de navegación. La utilidad flex coloca sus hijos en una fila por defecto y gap-4 deja separación entre ellos. Los destinos #inicio y #estado apuntan a elementos de la misma página con esos identificadores id:

<nav class="flex gap-4" aria-label="Secciones de la página">
<a class="text-sky-700" href="#inicio">Inicio</a>
<a class="text-sky-700" href="#estado">Estado</a>
</nav>
<h2 id="inicio" class="font-bold">Inicio</h2>
<p id="estado">Estado de la prueba local.</p>

Campo de entrada. label proporciona el nombre visible y su atributo for lo asocia al id del campo input. border dibuja un borde; border-slate-400 le da color y p-2 usa un padding menor que p-4. block hace que la etiqueta ocupe su propia línea:

<label class="block" for="nombre-prueba">Nombre de la prueba</label>
<input class="border border-slate-400 rounded-lg p-2" id="nombre-prueba" type="text" placeholder="Web local" />

Puedes escribir en el campo, pero este ejemplo no envía ni guarda información: no tiene formulario conectado a un servidor. No necesitas añadir un inicio de sesión ni solicitar contraseñas para comprobar una web estática.

5.11 Extensión opcional DAM: dos tarjetas adaptables

Section titled “5.11 Extensión opcional DAM: dos tarjetas adaptables”

Si has terminado el núcleo, puedes mostrar el editor y el servidor en dos tarjetas. Primero conoce las tres utilidades nuevas: grid crea una cuadrícula para sus hijos, grid-cols-1 fija una columna y gap-4 separa las celdas.

Añade este bloque después del aviso, antes del enlace, y comprueba su aspecto:

<section class="mt-4 grid grid-cols-1 gap-4">
<article class="border border-slate-400 rounded-lg p-4">
<h2 class="font-bold">Editor</h2>
<p class="mt-4 text-slate-600">p00-lab modifica el archivo compartido.</p>
</article>
<article class="border border-slate-400 rounded-lg p-4">
<h2 class="font-bold">Servidor</h2>
<p class="mt-4 text-slate-600">Nginx lo entrega al navegador.</p>
</article>
</section>

Las dos tarjetas aparecen una debajo de otra. Ahora introduce una regla responsive, que adapta la distribución a la anchura de la ventana. sm:grid-cols-2 aplica dos columnas desde el umbral sm, cuyo valor predeterminado es 40rem —habitualmente 640 píxeles—. Por debajo se mantiene la columna inicial. No significa «solo en móviles» ni identifica un dispositivo concreto.

Añade esa clase a la apertura de section:

<section class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2">

Guarda, recarga y estrecha o ensancha la ventana. Explica el cambio leyendo la condición sm: y la utilidad grid-cols-2 por separado. Las tarjetas describen dos funciones; no crean más contenedores.

Recorre el HTML desde body hasta el enlace. Antes de mirar el navegador, identifica una clase que controle cada aspecto: fondo, tamaño de texto, grosor, espacio interior, espacio exterior y estado interactivo. Después comprueba si el resultado visible coincide.

Si una clase falla, revisa su nombre y el elemento donde la has puesto. Si no funciona ninguna, comprueba que el script se haya descargado y que conservas la conexión a Internet. La página puede seguir respondiendo por HTTP aunque falten los estilos externos. Tu prueba funcional sigue siendo la del apartado 3.

5.13 Actividad guiada TW01: presenta tu laboratorio

Section titled “5.13 Actividad guiada TW01: presenta tu laboratorio”

Modalidad: individual. Vas a reorganizar tu página como una tarjeta de presentación del laboratorio. Elige el tema visual y los colores; conserva la explicación real de qué hacen p00-lab y Nginx. Trabaja sobre web/index.html, con el script de Tailwind ya cargado y Nginx en marcha. Mantén la comprobación HTTP del apartado 3.

Sigue los pasos en orden. En cada uno, consulta el enlace, elige las clases, guarda y comprueba el cambio. Las pistas te orientan; no necesitas copiar una página completa de los ejemplos de la documentación. Aquí «panel» o «contenedor HTML» significa una etiqueta que agrupa contenido, no otro contenedor Docker.

  1. Prepara dos paneles dentro de main. Usa un article para el contenido principal y un aside para la información complementaria. En una ventana ancha se colocarán uno al lado del otro: aproximadamente 75 % a la izquierda y 25 % a la derecha, descontando la separación. Pista: aplica flex y gap-4 al padre; en los hijos, una proporción flex-[3_1_0%] y flex-[1_1_0%] reparte el espacio disponible en tres partes y una. Los números indican crecimiento, reducción y tamaño inicial. Añade min-w-0 a ambos para permitir que se encojan con su contenido. Consulta flex, gap y min-width. Comprueba: aparecen dos paneles con separación; evita sumar anchos de 75 % y 25 % más un hueco, porque superarías el espacio disponible.

    Usa esta estructura HTML como punto de partida, sin clases. Sustituye el main actual por este bloque; conserva el head, el script de Tailwind y el resto del documento. Ya tienes preparadas las etiquetas que completarás en los siguientes pasos. Añade tú los atributos class donde corresponda. La imagen aparecerá cuando la descargues y ajustes su ruta en el paso 4.

    <main>
    <article>
    <div>
    <img src="img/laboratorio.jpg" alt="Describe aquí la imagen que elijas" />
    </div>
    <div>
    <h1>Mi laboratorio local</h1>
    <p>Explica aquí cómo se relacionan el archivo compartido y Nginx.</p>
    </div>
    </article>
    <aside>
    <h2>Herramientas del laboratorio</h2>
    <ul>
    <li>Docker: crea y ejecuta los contenedores del laboratorio.</li>
    <li>Segunda herramienta y su función.</li>
    <li>Tercera herramienta y su función.</li>
    </ul>
    <a href="http://localhost:8080/">Volver a comprobar la web</a>
    </aside>
    </main>
  2. Distingue visualmente los paneles. Ambos tendrán borde fino, esquinas redondeadas, espacio interior y sombra. El derecho tendrá un fondo diferente y una sombra más marcada. Pista: combina border, un color border-slate-*, rounded-xl y p-4; compara shadow-sm con shadow-lg. Consulta bordes, color del borde, esquinas, sombras, fondos y padding. Comprueba: el texto no toca el borde y puedes distinguir ambos paneles.

  3. Divide el panel izquierdo en dos filas. La superior contendrá la imagen; la inferior, el título y la descripción. En la estructura de partida, cada fila ya está agrupada en un div. Pista: en el article, flex flex-col gap-4 organiza sus dos hijos verticalmente; no necesitan tener la misma altura. Consulta flex-direction. Comprueba: los dos grupos aparecen uno debajo del otro.

    En el panel izquierdo, conserva las clases de proporción y presentación de los pasos anteriores y añade flex flex-col gap-4. La parte que organiza las dos filas queda así; los comentarios representan el contenido que ya tienes:

    <article class="flex flex-col gap-4">
    <div>
    <!-- Fila superior: imagen -->
    </div>
    <div>
    <!-- Fila inferior: h1 y párrafo -->
    </div>
    </article>
  4. Busca y elige tu propia imagen. Puede representar tecnología, un paisaje, una afición o el tema que prefieras para tu laboratorio. Puedes buscar una imagen que puedas reutilizar o generarla con ChatGPT o una herramienta similar. Descarga el resultado como archivo JPG, PNG o WebP y guárdalo desde el anfitrión en optativa-nube/p00-puesto-nube/web/img/; crea la carpeta img/ si falta. Usa un nombre sencillo, por ejemplo laboratorio.jpg, conservando su extensión real. Anota la página de procedencia; si la has generado, indica la herramienta y el prompt utilizado. En el img de la fila superior, adapta src al nombre del archivo y sustituye alt por una descripción breve de la imagen elegida. Pista: src es la ruta desde web/index.html; alt describe el contenido, no el nombre del archivo. Usa w-full h-56 object-cover rounded-lg: la imagen llena el ancho y mantiene sus proporciones, aunque se recorten los extremos. Consulta width, height y object-fit. Comprueba: la imagen carga desde tu Nginx y no se ve estirada.

  5. Aplica un filtro a la imagen. Prueba primero grayscale, que la muestra en escala de grises. Después compara con grayscale-50 y decide qué versión conservar. Pista: la clase se añade al img; no tienes que editar el archivo de imagen ni añadir una clase llamada filter. Si prefieres otro efecto, prueba sepia o brightness-75, sustituyendo el anterior para comparar uno cada vez. Consulta grayscale, sepia y brightness. Comprueba: al quitar y volver a poner la clase cambia la imagen, pero el archivo original permanece igual.

  6. Escribe la presentación en la fila inferior. Completa el h1 y el párrafo descriptivo de la estructura de partida. Pon un nombre a tu laboratorio y explica, con tus palabras, cómo se relacionan el archivo compartido y Nginx. Pista: conserva un solo h1; para los títulos secundarios utiliza h2. Comprueba: puedes explicar el contenido sin recurrir a las clases visuales.

  7. Destaca el encabezado. El h1 debe tener mayor tamaño que el párrafo, letra gruesa y un color que se lea bien sobre el fondo. Pista: parte de text-3xl font-bold y elige un color oscuro de la familia text-slate-* o text-sky-*. Consulta tamaño, grosor y color del texto. Comprueba: el título se reconoce de un vistazo.

  8. Presenta el párrafo como un aviso. Añade un borde izquierdo grueso, fondo suave y espacio interior. Pista: prueba border-l-4, un color de borde, bg-sky-50 y p-4; mt-4 lo separa del título. Consulta bordes por lado, fondos y margin. Comprueba: el borde izquierdo destaca y el texto sigue siendo legible.

  9. Completa el panel derecho. Completa el h2 y los tres elementos li de la lista ul con las herramientas que has utilizado. Conserva el enlace a http://localhost:8080/ con el texto «Volver a comprobar la web». Pista: list-disc list-inside muestra las viñetas; recupera las clases del enlace del apartado 5.9 para darle fondo, espacio interior y esquinas redondeadas. Añade un cambio con hover: y un contorno con focus:. Consulta listas y estados hover y focus. Comprueba: el enlace cambia con el puntero, recibe un foco visible con Tab y funciona con Intro. Su aspecto no lo convierte en una prueba automática del servidor.

  10. Adapta la distribución a una ventana estrecha. Los paneles deben apilarse cuando falta anchura y recuperar la proporción 3:1 desde el umbral md (48rem por defecto). Pista: cambia el padre a flex flex-col gap-4 md:flex-row; sustituye las clases de proporción de los hijos por md:flex-[3_1_0%] y md:flex-[1_1_0%]. El prefijo aplica esa regla desde el umbral indicado; conserva min-w-0. Consulta diseño responsive. Comprueba: al estrechar la ventana la imagen queda encima del panel complementario y no aparece desplazamiento horizontal.

Extensión haz que la imagen recupere el color al pasar el puntero y que el cambio sea gradual. Pista: combina grayscale, hover:grayscale-0, transition y duration-300. Consulta grayscale, transiciones y duración. Comprueba que el efecto funciona con ratón y que la imagen sigue siendo comprensible en una pantalla táctil sin hover.

Cuando hayas terminado, en la Terminal A sal de alumno y de p00-lab:

Terminal window
exit
exit

En la Terminal B, detén el servidor Nginx y comprueba que se eliminó:

Terminal window
docker stop p00-web
docker ps --all --filter name=p00-web

Como se inició con --rm, p00-web desaparece al detenerlo. p00-lab queda detenido, pero conserva su configuración. En ambos casos, web/index.html continúa en la carpeta compartida del anfitrión.

En evidencias/web-local.md, anota:

  • La URL abierta en el navegador.
  • El resultado resumido de la respuesta HTTP 200.
  • Una explicación de dos frases sobre el papel de p00-lab y p00-web sobre el mismo archivo.
  • Una clase de Tailwind aplicada y su efecto visible.
  • La confirmación de que detuviste p00-web.

No hagas commit todavía: en el siguiente bloque añadirás el Dockerfile y Compose antes de versionar el conjunto.