Examen de defensa · Unidad 1 · Front-End Esencial

Guía de estudio: 20 retos + 20 preguntas

Banco de práctica completo. En el examen real solo te toca uno de los 20 retos y una o dos de las 20 preguntas.

Todo sale de tu código real de la Práctica 2 (Unidad 1/DSM4-2da/index.html, título interno Semana 2 PDB, y su hermana Unidad 1/DSM4-1-2da/index.html) y de lo ya fijado en lista-cotejo-evaluacion.html y guion-defensa-oral.html.

Cómo se reparten tus 3 minutos

0:00–0:15

El docente elige uno de los 20 retos y te lo lee.

0:15–1:45

Lo resuelves en VS Code, hablando mientras escribes.

1:45–2:00

Guardas y muestras el resultado en el navegador.

2:00–2:30

Primera pregunta teórica, respuesta de una frase.

2:30–3:00

Segunda pregunta teórica si alcanza el tiempo.

El rastreo de commits (20%) y el entregable publicado (15%) de la Matriz Anti-IA se revisan aparte, mirando tu repo y tu URL de Render — no ocupan minutos de tu turno hablado.

Saltar a un reto de Live Coding

Parte 1 — 20 ejercicios de Live Coding

Te toca uno, en 2 minutos. Cada tarjeta trae el problema que te plantea el docente, el código exacto y la explicación línea por línea de cómo resolverlo.

Reto 1 Oficial · lista de cotejo

Agregar una sección semántica nueva ("Testimonios")

📋 Problema: el docente te pide agregar una sección nueva llamada "Testimonios", enlazada desde el nav, con al menos un testimonio dentro.
Código a escribir
<!-- li + a: quinto enlace del nav, mismo patrón de clase que los otros cuatro --> <li><a class="hover:text-emerald-400" href="#testimonios">Testimonios</a></li>
<!-- section nueva: id="testimonios" debe ser IGUAL al href de arriba --> <section id="testimonios" class="max-w-5xl mx-auto px-6 py-14"> <!-- h2: título de la sección, mismo estilo que las demás --> <h2 class="text-2xl font-bold mb-6">Testimonios</h2> <!-- grid-cols-1 md:grid-cols-2: una columna en celular, dos desde 768px --> <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <!-- article: el testimonio se entiende leído solo, por eso NO es un div --> <article class="bg-white rounded-2xl border border-slate-200 p-6 shadow-sm"> <!-- p: la cita del testimonio --> <p class="text-slate-600 text-sm mb-3">"Excelente predisposición para aprender."</p> <!-- p: autor de la cita, más chico y en negrita --> <p class="font-semibold text-sm">— Docente, UTH</p> </article> </div> </section>

🔧 Paso a paso

  1. Agregas el <li><a> en el nav como quinto enlace, con href="#testimonios" y la misma clase hover que los demás.
  2. Creas un <section id="testimonios"> — el id debe ser idéntico al href del paso 1 para que el enlace funcione.
  3. Le pones un <h2> con el título, mismo estilo (text-2xl font-bold mb-6) que las otras secciones.
  4. Armas el contenedor con grid grid-cols-1 md:grid-cols-2 gap-6: una columna en celular, dos desde tablet en adelante.
  5. Cada testimonio va en un <article>, no en un <div>, porque el contenido se entiende leído solo, fuera de contexto.
  6. Dentro pones un <p> con la cita entre comillas y otro <p> más chico y en negrita con el autor.
  7. Cierras article, div y section en orden.
🗣️ Dices mientras lo haces: "agrego la sección con su id, la enlazo desde el nav, y uso <article> porque el testimonio se lee solo, fuera de contexto."
Reto 2

Convertir las "Cajas" sueltas en una sección semántica

📋 Problema: hay un bloque de "Cajas" fuera de cualquier <section>, sin id navegable. Te piden convertirlo en una sección semántica correcta.
Antes
<!-- ANTES: div suelto, sin id, sin section que lo contenga --> <div class="flex flex-col md:flex-row gap-4"> <div class="bg-sky-500 p-4">Caja 1</div> <div class="bg-emerald-300 p-4">Caja 2</div> </div>
Después
<!-- DESPUÉS: envuelto en section semántica con id navegable --> <section id="destacados"> <!-- div contenedor: flex flex-col apila en celular, md:flex-row en fila --> <div class="flex flex-col md:flex-row gap-4"> <!-- primera caja: fondo celeste, esquinas redondeadas --> <div class="bg-sky-500 p-4 rounded-lg text-white">Caja 1</div> <!-- segunda caja: mismo patrón, otro color --> <div class="bg-emerald-300 p-4 rounded-lg">Caja 2</div> </div> </section>

🔧 Paso a paso

  1. Detectas que las cajas están en un <div> suelto, sin id y sin ninguna <section> que las contenga.
  2. Envuelves todo el bloque en <section id="destacados"> para que sea una región con nombre, navegable por ancla.
  3. Dejas el div contenedor con flex flex-col md:flex-row gap-4: en celular las cajas se apilan, desde md: van en fila.
  4. A cada caja le agregas rounded-lg (y a la primera text-white) para que se vean como tarjetas, no como bloques de color planos.
  5. Cierras la section.
🗣️ Dices mientras lo haces: "envuelvo las cajas en un <section> con id, así quedan navegables y dejan de ser un div suelto sin significado."
Reto 3

Completar el <p> vacío de "Sobre mí"

📋 Problema: en la sección "Sobre mí" quedó un <p> vacío de relleno. Te piden completarlo con contenido real.
Antes → Después
<!-- ANTES: quedó vacío de relleno --> <p class="text-slate-500 text-sm"></p> <!-- DESPUÉS: italic le da tono de cita destacada --> <p class="text-slate-500 text-sm italic">"Aprender haciendo, un commit a la vez."</p>

🔧 Paso a paso

  1. Ubicas el <p> vacío dentro de "Sobre mí" — no tiene texto ni cumple ninguna función así.
  2. Escribes una frase real entre comillas, a modo de cita personal.
  3. Le agregas la clase italic para que se lea como una cita destacada, no como texto de relleno.
🗣️ Dices mientras lo haces: "relleno el <p> vacío con una frase real; uso italic porque es una cita destacada, no texto de relleno."
Reto 4

Corregir el alt de la foto de perfil

📋 Problema: el atributo alt de la foto describe el estilo CSS ("Rounded corners") en vez de la imagen. Te piden corregirlo.
Antes → Después
<!-- ANTES: describe el estilo CSS, no la foto --> <img src="img/foto1.png" class="rounded-lg w-64 h-64 object-cover" alt="Rounded corners"> <!-- DESPUÉS: alt describe QUÉ muestra la imagen --> <img src="img/foto1.png" class="rounded-lg w-64 h-64 object-cover" alt="Foto de perfil de Prado Diaz Bernardo">

🔧 Paso a paso

  1. Ubicas el <img> de la foto de perfil y miras su atributo alt.
  2. Ves que dice "Rounded corners" — describe una clase CSS (rounded-lg), no la foto.
  3. Lo reemplazas por una descripción real de la imagen: "Foto de perfil de Prado Diaz Bernardo".
  4. Dejas el resto de atributos (src, class) exactamente igual, porque el problema era solo el alt.
🗣️ Dices mientras lo haces: "cambio el alt para que describa la foto en sí, no la clase CSS que le aplico."
Reto 5

Agregar una quinta tarjeta a la grilla de Skills

📋 Problema: te piden agregar una quinta skill a la grilla, manteniendo exactamente el mismo patrón de clases que las otras cuatro.
Código a escribir
<!-- misma clase exacta que las otras cuatro, solo cambia el contenido --> <article class="bg-white rounded-xl border border-slate-200 p-5 shadow-sm hover:shadow-md transition"> <!-- h3: nombre de la skill, mismo estilo que las demás --> <h3 class="font-semibold mb-1">Django</h3> <!-- p: descripción breve, mismo estilo que las demás --> <p class="text-sm text-slate-500">Framework web en Python, patrón MTV.</p> </article>

🔧 Paso a paso

  1. Copias la clase exacta de una tarjeta de Skills existente (bg-white rounded-xl border border-slate-200 p-5 shadow-sm hover:shadow-md transition) para no romper la consistencia visual.
  2. Dentro pones un <h3> con el nombre de la nueva skill (Django).
  3. Debajo, un <p> con una descripción breve, mismo tamaño y color que las demás (text-sm text-slate-500).
  4. Pegas esta quinta tarjeta dentro de la misma grilla que las otras cuatro.
🗣️ Dices mientras lo haces: "copio la clase exacta de una tarjeta existente para mantener consistencia, y solo cambio el h3 y el p."
Reto 6 Oficial · lista de cotejo

Cambiar el breakpoint de Skills de md: a lg:

📋 Problema: la grilla de Skills pasa a 3 columnas desde 768px (tablet). Te piden que pase a 3 columnas recién desde 1024px (escritorio).
Antes → Después
<!-- ANTES: 3 columnas ya desde 768px (tablet) --> <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-5"> <!-- DESPUÉS: 3 columnas recién desde 1024px (escritorio) --> <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5">

🔧 Paso a paso

  1. Ubicas el <div> de la grilla de Skills y localizas la clase md:grid-cols-3.
  2. Entiendes que md: activa esa regla desde 768px — o sea, ya en tablet.
  3. La reemplazas por lg:grid-cols-3, que recién activa la regla desde 1024px.
  4. Dejas grid-cols-1 y sm:grid-cols-2 sin tocar, porque el enunciado solo pide mover el breakpoint de 3 columnas.
🗣️ Dices mientras lo haces: "cambio el prefijo md: por lg: para que las 3 columnas aparezcan recién en escritorio, no en tablet."
Reto 7

Agregar una segunda tarjeta a "Proyectos"

📋 Problema: la sección "Proyectos" solo tiene una tarjeta. Te piden agregar una segunda, con el mismo patrón visual.
Código a escribir
<!-- mismas clases que la primera, incluido el hover --> <article class="bg-white rounded-2xl border border-slate-200 p-6 shadow-sm hover:shadow-lg hover:-translate-y-1 transition"> <!-- h3: nombre del proyecto --> <h3 class="text-lg font-bold mb-2">Portafolio Personal</h3> <!-- p: descripción breve --> <p class="text-slate-600 text-sm mb-4">Sitio web propio con HTML5 semántico y Tailwind CSS.</p> <!-- a: enlace verde con subrayado al pasar el mouse --> <a href="#" class="text-emerald-700 font-semibold text-sm hover:underline">Ver repositorio →</a> </article>

🔧 Paso a paso

  1. Ubicas la tarjeta de "Proyectos" ya existente y copias su <article> completo, con las mismas clases (incluido hover:shadow-lg hover:-translate-y-1).
  2. Pegas la copia justo después de la original, dentro del mismo contenedor.
  3. Cambias el <h3> por el nombre del nuevo proyecto.
  4. Cambias el <p> por su descripción.
  5. Dejas el <a> "Ver repositorio →" con el mismo estilo, solo actualizando el href si corresponde.
🗣️ Dices mientras lo haces: "duplico la tarjeta existente con las mismas clases, incluido el hover, y cambio solo el contenido."
Reto 8

Ordenar la tarjeta de perfil "flotante" del final del archivo

📋 Problema: al final del archivo quedó un bloque de perfil suelto, fuera de cualquier section, en inglés y con un alt genérico. Te piden integrarlo dentro de "Sobre mí", traducido y con datos reales.
Antes
<!-- ANTES: bloque suelto al final del body, sin section, textos en inglés --> <div class="flex items-center space-x-4 p-4 bg-white rounded-xl shadow-md max-w-sm"> <img class="w-16 h-16 rounded-full object-cover border-2 border-indigo-500 shadow-sm" src="img/foto1.png" alt="Student profile photo" /> <div> <h3 class="text-lg font-semibold text-gray-900">Prado Diaz Bernardo</h3> <p class="text-sm font-medium text-indigo-600">Computer Science Engineer</p> <p class="text-xs text-gray-500">ID: #84920</p> </div> </div>
Después
<!-- DESPUÉS: integrada dentro de "sobre-mi", en español, con alt real --> <div class="flex items-center space-x-4 p-4 bg-white rounded-xl shadow-md max-w-sm mt-6"> <!-- img: alt describe la foto, no el rol --> <img class="w-16 h-16 rounded-full object-cover border-2 border-indigo-500 shadow-sm" src="img/foto1.png" alt="Foto de perfil de Prado Diaz Bernardo" /> <!-- div: agrupa nombre, rol y dato adicional, todo en español --> <div> <h3 class="text-lg font-semibold text-gray-900">Prado Diaz Bernardo</h3> <p class="text-sm font-medium text-indigo-600">Estudiante de Desarrollo Web</p> <p class="text-xs text-gray-500">UTH · APLICAWEB 4to</p> </div> </div>

🔧 Paso a paso

  1. Buscas el bloque de perfil suelto al final del body — está fuera de cualquier <section>.
  2. Ves que su alt dice "Student profile photo" y los textos están en inglés.
  3. Cortas el bloque y lo pegas dentro de la sección "sobre-mi", como contenido adicional (le agregas mt-6 para separarlo).
  4. Traduces "Computer Science Engineer" a "Estudiante de Desarrollo Web" y "ID: #84920" a algo real como "UTH · APLICAWEB 4to".
  5. Corriges el alt de la imagen para que describa la foto, no el rol de la persona.
🗣️ Dices mientras lo haces: "muevo el bloque suelto dentro de sobre-mi, traduzco los textos al español y corrijo el alt para que describa la foto, no el rol."
Reto 9

Agregar un botón "Cancelar" con sus propios estados

📋 Problema: el formulario solo tiene el botón "Enviar". Te piden agregar un botón "Cancelar" con sus propios estados, sin que dispare el envío.
Código a escribir
<!-- div: agrupa ambos botones en fila --> <div class="flex gap-3"> <!-- botón Enviar: el que ya tenías, sin cambios --> <button type="submit" class="bg-emerald-600 hover:bg-emerald-700 transition text-white font-semibold px-6 py-2.5 rounded-lg focus:outline-none focus:ring-2 focus:ring-emerald-400">Enviar</button> <!-- botón Cancelar: type="button" para que NO dispare el envío del form --> <button type="button" class="bg-transparent border border-slate-600 hover:bg-slate-800 transition text-white font-semibold px-6 py-2.5 rounded-lg focus:outline-none focus:ring-2 focus:ring-slate-400">Cancelar</button> </div>

🔧 Paso a paso

  1. Ubicas el botón "Enviar" del formulario y ves que no tiene un botón "Cancelar" al lado.
  2. Envuelves ambos botones en un <div class="flex gap-3"> para que queden en fila con espacio entre ellos.
  3. Agregas el nuevo <button type="button">: el type="button" es la parte crítica, porque evita que dispare el submit del formulario.
  4. Le das sus propios colores (bg-transparent border) y sus propios estados hover:bg-slate-800 y focus:ring-2 focus:ring-slate-400, distintos a los del botón Enviar.
🗣️ Dices mientras lo haces: "agrego el botón con type="button" para que no dispare el envío del formulario, y le doy sus propios estados de hover y focus."
Reto 10

Volver el header sticky

📋 Problema: te piden que el header quede fijo en la parte superior al hacer scroll.
Código a escribir
<!-- sticky top-0: se pega arriba al hacer scroll · z-10: queda por encima del resto --> <header class="bg-slate-900 text-white flex flex-col gap-4 md:flex-row md:items-center md:justify-between px-6 py-6 md:px-10 sticky top-0 z-10">

🔧 Paso a paso

  1. Ubicas la etiqueta <header> y revisas sus clases actuales.
  2. Agregas sticky, que hace que el elemento se comporte como estático hasta que llega al top del viewport, y ahí se "pega".
  3. Agregas top-0, que define en qué punto exacto se pega (el borde superior).
  4. Agregas z-10 para que el header quede por encima del contenido que sigue scrolleando debajo.
🗣️ Dices mientras lo haces: "agrego sticky top-0 z-10 para que el header quede pegado arriba al hacer scroll, por encima del resto del contenido."
Reto 11

Centrar la sección "Destacados" con contenedor

📋 Problema: la sección "Destacados" no tiene el mismo ancho y centrado que las demás secciones. Te piden unificarlo.
Código a escribir
<!-- max-w-5xl: mismo ancho máximo que las demás secciones · mx-auto: la centra · px-6: mismo relleno --> <section id="destacados" class="max-w-5xl mx-auto px-6 py-10">

🔧 Paso a paso

  1. Ubicas la <section id="destacados"> y ves que no tiene clases de ancho ni centrado, a diferencia de las demás secciones.
  2. Le agregas max-w-5xl, el mismo ancho máximo que usan las otras secciones del sitio.
  3. Le agregas mx-auto para centrar ese ancho máximo horizontalmente en la pantalla.
  4. Le agregas px-6 para que tenga el mismo relleno lateral que las demás, y no toque los bordes en celular.
🗣️ Dices mientras lo haces: "agrego max-w-5xl mx-auto px-6 para que la sección use el mismo ancho y centrado que las demás."
Reto 12

Cambiar la paleta de acento de emerald a indigo

📋 Problema: te piden cambiar el color de acento del sitio de emerald a indigo, en el nav y en el botón principal.
Código a escribir
<!-- nav: emerald-400 → indigo-400 --> <li><a class="hover:text-indigo-400" href="#sobre-mi">Sobre mí</a></li> <!-- botón enviar: emerald-600/700/400 → indigo-600/700/400 --> <button type="submit" class="bg-indigo-600 hover:bg-indigo-700 transition text-white font-semibold px-6 py-2.5 rounded-lg focus:ring-2 focus:ring-indigo-400">Enviar</button>

🔧 Paso a paso

  1. Ubicas cada lugar donde aparece la palabra emerald: el hover del nav y el botón "Enviar".
  2. En el <a> del nav, cambias hover:text-emerald-400 por hover:text-indigo-400.
  3. En el <button>, cambias bg-emerald-600 hover:bg-emerald-700 por bg-indigo-600 hover:bg-indigo-700.
  4. Cambias también focus:ring-emerald-400 por focus:ring-indigo-400, para que el foco del teclado use el mismo color nuevo.
  5. Mantienes los mismos números de intensidad (400, 600, 700) en cada caso — solo cambia el nombre del color.
🗣️ Dices mientras lo haces: "reemplazo cada clase emerald por indigo en el nav y en el botón, manteniendo los mismos números de intensidad (400/600/700)."
Reto 13

Agregar transición suave al hover del nav

📋 Problema: el cambio de color al pasar el mouse por el nav es instantáneo. Te piden que sea una transición suave.
Antes → Después
<!-- ANTES: el cambio de color es instantáneo --> <li><a class="hover:text-emerald-400" href="#sobre-mi">Sobre mí</a></li> <!-- DESPUÉS: transition-colors anima el cambio --> <li><a class="hover:text-emerald-400 transition-colors" href="#sobre-mi">Sobre mí</a></li>

🔧 Paso a paso

  1. Ubicas cualquier <a> del nav y ves que solo tiene hover:text-emerald-400.
  2. Le agregas la clase transition-colors al mismo elemento.
  3. Con eso el navegador anima el cambio de color en vez de aplicarlo de golpe, sin tocar nada de CSS aparte.
🗣️ Dices mientras lo haces: "agrego transition-colors para que el cambio de color al pasar el mouse sea suave, no instantáneo."
Reto 14 Explicación, no código

Explicar por qué el formulario SÍ está bien vinculado

📋 Problema: el docente señala el label y el input del campo Correo y te pide explicar, sin tocar código, por qué ya están bien vinculados.
Código que te señala
<!-- for="correo" es IGUAL al id de abajo: así el label queda vinculado al input --> <label for="correo" class="block text-sm font-semibold mb-1">Correo</label> <input type="email" id="correo" name="correo" required placeholder="tu@correo.com" ...>

🔧 Paso a paso (cómo lo defiendes en voz alta)

  1. Señalas el atributo for="correo" del <label> y lo comparas con el id="correo" del <input>: son idénticos, letra por letra.
  2. Explicas que esa coincidencia es lo que "vincula" ambos elementos en el DOM.
  3. Mencionas el primer beneficio: al enfocar el input con el teclado, el lector de pantalla anuncia también el texto del label.
  4. Mencionas el segundo beneficio: hacer clic en el texto "Correo" también activa/enfoca el input, aunque el clic no caiga justo sobre el campo.
🗣️ Qué defender: "al enfocar el input se anuncia también su label (lector de pantalla), y hacer clic en el texto 'Correo' también activa el campo."
Reto 15

Foto de perfil responsiva (mobile-first)

📋 Problema: la foto de perfil tiene un tamaño fijo (w-64 h-64) incluso en celular. Te piden hacerla responsiva, mobile-first.
Antes → Después
<!-- ANTES: 64 unidades fijas siempre, incluso en celular --> <img src="img/foto1.png" class="rounded-lg w-64 h-64 object-cover" alt="..."> <!-- DESPUÉS: w-full por defecto (celular), tamaño fijo recién desde sm: --> <img src="img/foto1.png" class="rounded-lg w-full max-w-xs h-64 object-cover sm:w-64" alt="...">

🔧 Paso a paso

  1. Ubicas el <img> de la foto de perfil y ves w-64 h-64 fijos, incluso en celular.
  2. Reemplazas w-64 por w-full, que es la base sin prefijo — se aplica primero, en cualquier ancho, incluido celular.
  3. Agregas max-w-xs para que en pantallas grandes esa "base" no crezca de más antes de llegar al breakpoint.
  4. Agregas sm:w-64 al final: recién desde 640px el ancho vuelve a ser fijo — ese es el orden mobile-first.
🗣️ Dices mientras lo haces: "cambio el ancho fijo por w-full max-w-xs como base para celular, y reservo sm:w-64 para pantallas más grandes — eso es mobile-first."
Reto 16

De grid a flex en Skills

📋 Problema: te piden cambiar el layout de Skills de grid de columnas fijas a flex-wrap.
Antes → Después
<!-- ANTES: columnas iguales por breakpoint --> <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-5"> <!-- DESPUÉS: flex-wrap acomoda tarjetas según el espacio disponible --> <div class="flex flex-wrap gap-5">

🔧 Paso a paso

  1. Ubicas el div de la grilla de Skills con grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3.
  2. Borras las tres clases de grid-cols y grid.
  3. Escribes flex flex-wrap en su lugar.
  4. Entiendes la diferencia: ahora las tarjetas fluyen una al lado de la otra y saltan de línea solas cuando no entran, en vez de forzar un número fijo de columnas por breakpoint.
🗣️ Dices mientras lo haces: "cambio grid por flex flex-wrap para que las tarjetas se acomoden según el espacio disponible en vez de columnas fijas."
Reto 17

Versionar el cambio con Git y verificar el redeploy

📋 Problema: hiciste un cambio en el código. Te piden versionarlo con Git y verificar que Render lo despliega solo.
Comandos a correr
# git add .: agrega TODOS los archivos modificados al área de preparación git add . # git commit -m: guarda una fotografía del proyecto con mensaje descriptivo git commit -m "Corregir alt de la foto y agregar seccion Testimonios" # git push: sube el commit a GitHub y dispara el redeploy automático en Render git push

🔧 Paso a paso

  1. Abres la terminal integrada de VS Code, parado en la carpeta del proyecto.
  2. Corres git add . para mandar todos los archivos modificados al área de preparación (staging).
  3. Corres git commit -m "..." con un mensaje que describe qué cambiaste, para guardar esa fotografía del proyecto.
  4. Corres git push para subir el commit a GitHub.
  5. Ese push dispara automáticamente el webhook que hace que Render redespliegue el sitio, sin que hagas nada manual ahí.
🗣️ Dices mientras lo haces: "hago add, commit con un mensaje descriptivo y push; eso dispara el redeploy automático en Render sin tocar nada manualmente."
Reto 18

Corregir un problema de contraste (Lighthouse)

📋 Problema: Lighthouse marca un problema de contraste de color insuficiente en un texto. Te piden corregirlo.
Antes → Después
<!-- ANTES: gris muy claro sobre fondo blanco, contraste insuficiente --> <p class="text-slate-400">Estudiante de Desarrollo Web · UTH</p> <!-- DESPUÉS: slate-600 cumple el contraste mínimo AA de WCAG --> <p class="text-slate-600">Estudiante de Desarrollo Web · UTH</p>

🔧 Paso a paso

  1. Corres Lighthouse (o miras el reporte) y ves que marca contraste insuficiente en un texto.
  2. Ubicas el <p> señalado y ves que usa text-slate-400, un gris muy claro sobre fondo blanco.
  3. Lo cambias por text-slate-600, un gris más oscuro.
  4. Verificas que ese tono sí cumple la relación de contraste mínima 4.5:1 que pide el nivel AA de WCAG.
🗣️ Dices mientras lo haces: "cambio slate-400 por slate-600 porque el gris claro no cumple el contraste mínimo AA sobre fondo blanco."
Reto 19

Agregar maxlength al campo "Nombre"

📋 Problema: el campo "Nombre" del formulario solo tiene minlength. Te piden agregarle también un maxlength razonable.
Antes → Después
<!-- ANTES: solo tiene minlength --> <input type="text" id="nombre" name="nombre" minlength="2" placeholder="Tu nombre" ...> <!-- DESPUÉS: maxlength evita que se escriba de más --> <input type="text" id="nombre" name="nombre" required minlength="2" maxlength="60" placeholder="Tu nombre" ...>

🔧 Paso a paso

  1. Ubicas el <input> del campo "Nombre" y ves que solo tiene minlength="2".
  2. Entiendes que minlength pone un piso (mínimo de caracteres) pero no un techo.
  3. Agregas maxlength="60" al mismo input, como límite superior razonable para un nombre.
  4. Dejas required y minlength="2" intactos — solo sumas la restricción que faltaba.
🗣️ Dices mientras lo haces: "agrego maxlength="60" junto al minlength que ya tenía, para poner un tope razonable al campo."
Reto 20 Integrador · guion oficial

Ejercicio integrador — el ejemplo oficial del guion de defensa oral

📋 Problema: el ejemplo oficial del guion: agregar una tarjeta de proyecto nueva reutilizando las clases existentes, y versionarla con Git. Tal como figura en guion-defensa-oral.html para Unidad 1.
Código a escribir
<!-- article nuevo dentro de #proyectos, mismas clases que el ya existente --> <article class="bg-white rounded-2xl border border-slate-200 p-6 shadow-sm hover:shadow-lg hover:-translate-y-1 transition"> <h3 class="text-lg font-bold mb-2">Portafolio Personal</h3> <p class="text-slate-600 text-sm mb-4">Sitio web propio con HTML5 semántico y Tailwind CSS.</p> <a href="#" class="text-emerald-700 font-semibold text-sm hover:underline">Ver repositorio →</a> </article>

🔧 Paso a paso

  1. Ubicas la sección #proyectos y copias el <article> existente completo, con todas sus clases (incluido hover:-translate-y-1).
  2. Pegas la copia como segunda tarjeta, dentro del mismo contenedor.
  3. Cambias el <h3>, el <p> y el href del <a> por los datos del nuevo proyecto ("Portafolio Personal").
  4. Guardas, y en la terminal corres git add ., git commit -m "..." y git push.
  5. Abres la URL de Render y refrescas para mostrar que el redeploy ya se aplicó solo.
🗣️ Guion: "agrego la tarjeta reutilizando las mismas clases para mantener consistencia visual, hago git add, commit y push, y muestro que Render redesplegó solo."

Parte 2 — 20 preguntas teóricas

Te tocan 1-2, en 1 minuto. Cada respuesta tiene que salir en una frase, sin dudar. Cada tarjeta te muestra cómo construirla paso a paso y las palabras clave mínimas si te trabas.

Saltar a una pregunta

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Las 5 oficiales de la lista de cotejo

Pregunta 1Oficial

¿Diferencia entre <section> y <div>?

Paso 1<section> tiene significado semántico y puede ser una región navegable para un lector de pantalla.

Paso 2<div>, en cambio, es un contenedor genérico sin ningún significado.

✅ Respuesta completa: "<section> tiene significado semántico y puede ser una región navegable para un lector de pantalla; <div> es un contenedor genérico sin significado."
semánticoregión navegablelector de pantalla
Pregunta 2Oficial

¿Qué es "utility-first" en Tailwind?

Paso 1Aplicas clases pequeñas de un solo propósito (p-4, bg-emerald-600).

Paso 2Las escribes directo en el HTML, en vez de armar un archivo .css aparte.

✅ Respuesta completa: "Aplicas clases pequeñas de un solo propósito directo en el HTML (p-4, bg-emerald-600) en vez de escribir un .css aparte."
clases utilitariasdirecto en el HTMLsin CSS aparte
Pregunta 3Oficial

¿Qué es "mobile-first"?

Paso 1La clase sin prefijo es la base, pensada para celular.

Paso 2Los prefijos (md:, lg:) agregan reglas recién desde ese ancho hacia arriba.

✅ Respuesta completa: "La clase sin prefijo es la base para celular; los prefijos (md:, lg:) agregan reglas recién desde ese ancho hacia arriba."
base = celularprefijos hacia arribasm/md/lg
Pregunta 4Oficial

¿required vs. type="email"?

Paso 1required exige que el campo no esté vacío.

Paso 2type="email" además valida el formato (arroba y dominio).

✅ Respuesta completa: "required exige que no esté vacío; type="email" además valida el formato (@ y dominio)."
no vacíoformato válido@ y dominio
Pregunta 5Oficial

¿Qué revisa Lighthouse en Accessibility?

Paso 1Revisa reglas automatizables, no todo lo posible de accesibilidad.

Paso 2Ejemplos concretos: alt en imágenes, contraste de color, label vinculado a inputs, orden de encabezados.

✅ Respuesta completa: "Reglas automatizables: alt en imágenes, contraste de color, label vinculado a inputs, orden de encabezados."
altcontrastelabel-inputencabezados

15 de refuerzo, de las guías de Semana 1 y 2

Pregunta 6

¿Cuántas veces va <header>, <nav>, <main>, <footer>?

Paso 1header, nav, main y footer van una sola vez cada uno.

Paso 2<section> y <article>, en cambio, sí pueden repetirse.

✅ Respuesta completa: "Una sola vez cada uno; <section> y <article> sí pueden repetirse."
una sola vezsection/article sí repiten
Pregunta 7

¿Por qué cada skill/proyecto es un <article>?

Paso 1El contenido tiene sentido leído solo, sin depender de lo que está alrededor.

Paso 2Por eso no es un <div> genérico, sino un bloque independiente.

✅ Respuesta completa: "Porque tiene sentido leído solo, aislado del resto de la página."
se lee solofuera de contexto
Pregunta 8

¿Diferencia entre git init, git add y git commit?

Paso 1init crea el repositorio local.

Paso 2add prepara (staging) los archivos modificados.

Paso 3commit los guarda como una fotografía del proyecto, con un mensaje.

✅ Respuesta completa: "init crea el repo local; add prepara los archivos modificados; commit los guarda como fotografía con mensaje."
init = crea repoadd = preparacommit = guarda foto
Pregunta 9

¿Por qué el historial de commits pesa 20%?

Paso 1Una progresión semanal real de commits queda registrada con fecha.

Paso 2Eso prueba que el trabajo se hizo con el tiempo, no de una sola vez la noche anterior.

✅ Respuesta completa: "Porque una progresión semanal real prueba que el trabajo se hizo con el tiempo, no de una sola vez."
progresión semanaltrabajo real en el tiempo
Pregunta 10

¿Por qué este portafolio usa Static Site en Render y no otro tipo?

Paso 1El proyecto es HTML/CSS/JS puro.

Paso 2No hay backend ni base de datos que procesar en el servidor.

✅ Respuesta completa: "Porque es HTML/CSS/JS puro, sin backend ni base de datos que procesar."
HTML/CSS/JS purosin backend ni BD
Pregunta 11

¿Qué dispara el redeploy automático en Render?

Paso 1Haces un git push.

Paso 2A la rama main conectada al servicio de Render.

✅ Respuesta completa: "Un git push a la rama main conectada al servicio."
git pushrama main conectada
Pregunta 12

¿Diferencia entre el Play CDN de Tailwind y una instalación con build?

Paso 1El CDN genera las clases al vuelo en el navegador, sin compilar nada antes.

Paso 2El build genera un archivo .css optimizado de antemano.

✅ Respuesta completa: "El CDN genera las clases al vuelo en el navegador, sin compilar; el build genera un .css optimizado de antemano."
CDN = al vuelobuild = .css optimizado antes
Pregunta 13

¿Por qué md:grid-cols-3 no reemplaza grid-cols-1?

Paso 1Tailwind es mobile-first: la clase base (grid-cols-1) aplica siempre.

Paso 2md: solo se suma como una regla extra desde 768px hacia arriba.

✅ Respuesta completa: "Porque Tailwind es mobile-first: la base aplica siempre, y md: solo se suma desde 768px hacia arriba."
mobile-firstbase siemprese suma desde 768px
Pregunta 14

¿Por qué focus:ring-2 no es solo decoración?

Paso 1Quien navega con teclado no usa el mouse para moverse por la página.

Paso 2Necesita ver claramente qué campo está activo — por eso el anillo de foco es funcional.

✅ Respuesta completa: "Porque quien navega con teclado necesita ver qué campo está activo sin usar el mouse."
navegación por tecladofoco visible
Pregunta 15

¿Diferencia entre :hover y :focus?

Paso 1:hover responde al mouse encima del elemento.

Paso 2:focus responde al elemento activo/seleccionado, también alcanzable por teclado.

✅ Respuesta completa: ":hover responde al mouse encima; :focus responde al elemento activo/seleccionado, también por teclado."
hover = mouse encimafocus = activo/teclado
Pregunta 16

¿Sobre qué URL corres Lighthouse?

Paso 1Sobre la URL pública de Render, publicada.

Paso 2No sobre localhost, porque esa es la que usa un visitante real.

✅ Respuesta completa: "Sobre la pública de Render, no localhost — es la que usa un visitante real."
URL pública de Renderno localhost
Pregunta 17

Si Lighthouse marca una imagen sin alt, ¿qué corriges?

Paso 1Agregas un alt con una descripción real de la imagen.

Paso 2No lo dejas vacío ni le pones un texto genérico sin sentido.

✅ Respuesta completa: "Agregar un alt con una descripción real de la imagen, no un texto vacío."
alt realno vacío
Pregunta 18

¿Pondrías una clave secreta directo en este HTML?

Paso 1No, nunca.

Paso 2Cualquier dato en el HTML/JS del cliente es visible con "Ver código fuente".

✅ Respuesta completa: "No — cualquier dato en el HTML/JS del cliente es visible con 'Ver código fuente'."
novisible en ver código fuente
Pregunta 19

¿Qué breakpoints de Tailwind usaste y desde qué ancho?

Paso 1sm: desde 640px.

Paso 2md: desde 768px.

Paso 3lg: desde 1024px.

✅ Respuesta completa: "sm: desde 640px, md: desde 768px, lg: desde 1024px."
sm 640pxmd 768pxlg 1024px
Pregunta 20

¿Qué pasaría con flex-row sin prefijo en el header?

Paso 1Se aplicaría siempre, incluso en celular, porque no tendría ningún prefijo que lo restrinja.

Paso 2Eso apretaría el nombre y el nav uno al lado del otro en una pantalla angosta.

✅ Respuesta completa: "Se aplicaría siempre, incluso en celular, apretando nombre y nav en una pantalla angosta."
se aplica siempreaprieta en celular

Checklist de 60 segundos antes de tu turno

  • ☐ URL de Render abierta y probada (Ctrl+F5 antes de entrar)
  • ☐ Repo de GitHub abierto en la pestaña de commits
  • ☐ VS Code abierto directo en Unidad 1/DSM4-2da/index.html
  • ☐ Practicaste los 20 ejercicios hasta poder resolver cualquiera sin dudar
  • ☐ Puedes recitar las 20 respuestas express sin mirar el papel

Fuentes: lista-cotejo-evaluacion.html, guion-defensa-oral.html, unidad1-semana1-guia-render.html, unidad1-semana2-guia-tailwind.html, y tu código en Unidad 1/DSM4-2da/index.html y Unidad 1/DSM4-1-2da/index.html.