Este tutorial adapta pedagógicamente el Día 58. Las secciones 📝 Contenido original del curso y 📝 Ejercicio original del curso provienen de las lecciones 412 a 416. Los archivos de inicio (
11.0 Bootstrap Intro,11.2 Bootstrap Componentsy el proyecto TinDog) están en los recursos de las lecciones del curso. Los retos 🟢🟡🟠🔴, la sección que une Bootstrap con Flask, el proyecto extra y el proyecto integrador final del bloque Flask (Días 54 a 58) son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.
Nota sobre las verificaciones: el 27 de septiembre de 2026 se comprobó que la versión actual de Bootstrap es la 5.3.8 (registro de npm y enlaces CDN de getbootstrap.com); que el sitio de ejercicios
appbrewery.github.io/bootstrap-layout/y la demostraciónappbrewery.github.io/tindog/están en línea (la demostración usa Bootstrap 5.3.0); y se revisaron en su código las clases de los ejemplos de los tres ejercicios de diseño y de las secciones de TinDog.
Tabla de contenidos
- Antes de empezar: ¿por qué un framework de CSS?
- ¿Qué es Bootstrap? Incluirlo y tu primera tarjeta
- El sistema de 12 columnas
- Componentes, ejemplos y utilidades
- 🔗 Bootstrap dentro de Flask
- 🚀 Proyecto del día: el sitio de la startup TinDog
- 🌟 Proyecto extra: la página del emprendimiento del colegio
- 🏆 Proyecto integrador final del bloque Flask (Días 54 a 58)
- 🧩 Comprueba lo aprendido
- 🤖 Programar con apoyo de IA
- 🛠️ Correcciones técnicas al material original
- 📋 Matriz de trazabilidad
- 📦 Evidencias de aprendizaje del Día 58
0. Antes de empezar: ¿por qué un framework de CSS?
(Fuente: 412-day-58-goals-what-you-ll-learn-by-the-end-of-today.md)
📝 Contenido original del curso
Hoy se presenta Bootstrap, uno de los toolkits de frontend más populares: permite maquetar y dar formato a los sitios con facilidad y escribir mucho menos CSS. "No es estrictamente programación en Python, pero es conocimiento esencial para cualquier desarrollador web". La profesora incluye aquí la sección completa de Bootstrap de su curso de desarrollo web; si ya la conoces, puedes ver los videos a doble velocidad o rehacer el proyecto final desde cero. "La repetición es la madre de toda habilidad".
Prerequisitos: HTML y CSS, incluido Flexbox (Días 41 a 44), herramientas de desarrollo de Chrome (Día 45), plantillas y archivos estáticos en Flask (Días 56 y 57).
📖 Por qué importa para un programador de Python (adaptación)
En los Días 56 y 57 tus páginas de Flask funcionaban, pero se veían "de 1998" salvo que usaras una plantilla ajena. Bootstrap te da un sistema de diseño completo: con clases en el HTML obtienes botones, tarjetas, menús y cuadrículas que se ven bien en celular y en computador. Es la herramienta que el curso usará en los proyectos Flask que siguen (Días 59 en adelante).
1. ¿Qué es Bootstrap? Incluirlo y tu primera tarjeta
(Fuente: 413 - What is Bootstrap-.md)
🎯 Objetivo de aprendizaje
Explicar qué es un framework de CSS, cuándo conviene usarlo e incluir Bootstrap en una página para usar un componente.
📝 Contenido original del curso
Historia. Bootstrap es un framework de CSS creado en 2010 por Mark Otto y Jacob Thornton, desarrolladores de Twitter. Se volvió popular por dos razones: trae archivos CSS prehechos (basta con agregar clases al HTML) y un sistema de diseño de 12 columnas basado en Flexbox, que facilita los sitios responsivos con un enfoque mobile first (primero el celular).
Ejemplo: un <button> común se ve simple; con unas pocas clases de Bootstrap se ve moderno, con colores, esquinas redondeadas y efecto al pasar el ratón. Todo el código de Bootstrap es abierto y está en GitHub.
Otros frameworks de CSS: Foundation, MUI, Tailwind y más. Entre los sitios que usan un framework externo, el curso muestra que Bootstrap tiene cerca del 80 % de participación; pero el grupo más grande son los sitios que no usan ninguno (CSS propio con Flexbox, Grid, etc.). Bootstrap no reemplaza lo que aprendiste de CSS.
| Ventajas | Desventajas |
|---|---|
| Rápido y fácil; muchos componentes prehechos (por ejemplo, tablas de precios) | Class bloat: el HTML se llena de clases de estilo y se mezcla estructura con presentación |
| Estilo consistente en todo el sitio, "como si hubieras contratado a un diseñador" | Personalización costosa si quieres controlar cada píxel |
| Buena compatibilidad con los navegadores, ya probada |
¿Cuándo usarlo? Para sitios responsivos que deben salir rápido, con componentes de diseño profesional y aspecto uniforme. ¿Cuándo no? Para un sitio muy simple (HTML y CSS bastan) o para un diseño totalmente personalizado.
Cómo incluirlo: CDN. Una CDN (Content Delivery Network) es una red de servidores repartidos por el mundo que entrega el archivo desde el más cercano al usuario. Se agrega:
- el CSS con un
<link>en el<head>; - el JavaScript (necesario para menús desplegables, carruseles, etc.) con un
<script>justo antes de cerrar el<body>.
La versión .min es el archivo minificado: sin espacios ni saltos, ilegible para humanos pero más rápido de descargar.
📝 Ejercicio original del curso: 11.0 Bootstrap Intro
El index.html de los archivos de inicio tiene 4 TODO; al terminarlos debe aparecer una tarjeta con la foto de un girasol:
- Incluir el CSS de Bootstrap por CDN (desde getbootstrap.com).
- Agregar el componente Card (Documentación → Components → Card; el primer ejemplo).
- Cambiar el
srcde la imagen aflower.jpgy agregar un textoaltpara lectores de pantalla. - Centrar la tarjeta vertical y horizontalmente con Flexbox, en un
<style>interno, apuntando a la claseflex-container.
La solución del paso 4:
.flex-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}Sobrescribir estilos de Bootstrap. Tu regla debe ser más específica o cargarse después: en un <style> interno, en un atributo style, o en tu hoja propia enlazada debajo del <link> de Bootstrap. "Si hay un choque, gana el último".
📖 La plantilla base actual (adaptación, verificada con getbootstrap.com)
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mi página</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="css/styles.css" rel="stylesheet"> <!-- tu CSS, DESPUÉS de Bootstrap -->
</head>
<body>
<h1>Hola, Bootstrap</h1>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>- La etiqueta
<meta name="viewport">es indispensable: sin ella, el celular muestra la versión de escritorio en miniatura y los puntos de corte no funcionan. - getbootstrap.com también ofrece los enlaces con un atributo
integrity(un código que el navegador usa para comprobar que el archivo no fue alterado). Copia el enlace completo de la página oficial. bootstrap.bundle.min.jsincluye Popper, que necesitan los menús desplegables y los tooltips.
⚠️ Errores frecuentes
| Error | Causa | Solución |
|---|---|---|
| La página se ve como HTML sin estilo | Falta el <link> de Bootstrap o está mal copiado |
Cópialo de getbootstrap.com; revisa la pestaña Red |
| El menú hamburguesa o el carrusel no responden | Falta el <script> de Bootstrap |
Agrégalo antes de </body> |
| Tu CSS no cambia nada | Tu hoja se carga antes que Bootstrap, o tu selector es menos específico | Enlázala después; usa un selector más específico |
| En el celular todo se ve diminuto | Falta <meta name="viewport"> |
Agrégala en el <head> |
| La tarjeta no se centra verticalmente | El contenedor no tiene altura | height: 100vh |
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1 — Aplicación: cambia la tarjeta para que muestre un animal o un lugar de tu región, con su título, texto y un botón
btn-success. - 🟡 Reto 2 — Ampliación: pon tres tarjetas lado a lado dentro del
flex-containercon un espacio entre ellas (propiedadgap). - 🟠 Reto 3 — Desafío: obtén el mismo centrado sin escribir CSS, solo con clases utilitarias de Bootstrap (busca "Flex" y "Sizing" en la documentación:
d-flex,justify-content-center,align-items-center,vh-100). - 🔴 Reto 4 — Pensamiento computacional: elige un sitio que uses a diario, dibuja su página principal en papel y marca qué partes serían componentes de Bootstrap (navbar, card, botón…) y qué partes necesitarían CSS propio.
2. El sistema de 12 columnas
(Fuente: 414 - Bootstrap Layout.md)
🎯 Objetivo de aprendizaje
Maquetar filas y columnas que cambien de proporción según el tamaño de la pantalla usando contenedores, filas, columnas y puntos de corte.
📝 Contenido original del curso
Los tres componentes: un div con clase container, dentro un div con clase row y, dentro de la fila, los elementos con clase col.
<div class="container">
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
</div>Con varias col, Bootstrap reparte el ancho por igual: seis columnas ocupan un sexto cada una; tres, un tercio.
Contenedores responsivos. container cambia de ancho según el tamaño de la pantalla (puntos de corte). Variantes: container-sm, container-md, container-lg, container-xl, container-xxl (ocupan el 100 % por debajo de ese punto de corte) y container-fluid (100 % siempre, "de borde a borde"). Los más usados son container (con márgenes a los lados) y container-fluid.
Columnas con tamaño. Cada fila se divide en 12 partes. col-2, col-4 y col-6 ocupan 2, 4 y 6 de 12 (col-6 = 50 %). Por ejemplo, una navegación lateral de 2/12 y un contenido de 10/12.
Puntos de corte. Los tamaños sm, md, lg, xl y xxl corresponden aproximadamente a celular, tableta, portátil, escritorio y pantallas enormes. Importante: col-sm-2 significa "2 de 12 desde el tamaño sm hacia arriba". Por debajo de un punto de corte no definido, cada columna ocupa el 100 %. Así casi no hacen falta media queries propias.
Se pueden combinar varios en un mismo elemento, y mezclar tamaños fijos con col automático:
<div class="col-lg-4 col-md-8 col-sm-12">…</div> <!-- 4/12 en lg+, 8/12 en md, 12/12 en sm -->
<div class="row">
<div class="col-2">…</div>
<div class="col-4">…</div>
<div class="col">…</div> <!-- toma lo que sobra: 6/12 -->
</div>Consejo: en las herramientas de desarrollo de Chrome, activa la barra de dispositivos y elige Responsive: al arrastrar el borde ves el ancho exacto y puedes identificar cuándo "salta" el diseño (por ejemplo, en 1200 px, el punto xl).
📖 La tabla de puntos de corte (documentación de Bootstrap 5.3)
| Punto de corte | Infijo de clase | Se aplica desde | Ancho de .container |
|---|---|---|---|
| Extra pequeño | (ninguno): col-6 |
0 px | 100 % |
| Pequeño | sm |
≥ 576 px | 540 px |
| Mediano | md |
≥ 768 px | 720 px |
| Grande | lg |
≥ 992 px | 960 px |
| Extra grande | xl |
≥ 1200 px | 1140 px |
| Extra extra grande | xxl |
≥ 1400 px | 1320 px |
Si las columnas de una fila suman más de 12, las que no caben bajan a la siguiente línea.
📝 Ejercicios originales del curso: appbrewery.github.io/bootstrap-layout
Tres ejercicios: arriba hay un área de demostración con el comportamiento buscado; debajo, un área que tú controlas editando el HTML y pulsando "aplicar cambios". El objetivo es que ambas se comporten igual en todos los tamaños.
| Ejercicio | Qué se ve en la demostración | Solución del video (coincide con el código de la demostración, verificado) |
|---|---|---|
| 1 | Dos columnas al 50 % en escritorio y al 100 % en celular | col-xl-6 en ambas (col-sm-12 sobra, porque el 100 % ya es el valor por defecto) |
| 2 | Tres columnas: 6-3-3 en lg; la primera al 100 % y las otras dos al 50 % desde sm; en el tamaño más pequeño, cada una de 10/12 |
Columna 1: col-lg-6 col-sm-12 col-10; columnas 2 y 3: col-lg-3 col-sm-6 col-10 |
| 3 | Dos columnas cuya proporción cambia en cada punto de corte | col-xxl-1/col-xxl-11, col-xl-2/col-xl-10, col-lg-4/col-lg-8, col-md-6/col-md-6 y 100 % por debajo |
El video resuelve el 2 y el 3 por prueba y error: probar un número, comparar y ajustar. "La prueba y el error no tienen nada de malo".
🔍 Antes de programar (ejercicio 3)
- Achica la ventana lentamente con la barra de dispositivos. Anota en qué anchos cambia el diseño: esos son los puntos de corte en uso.
- En cada tramo, estima qué fracción de 12 ocupa cada columna. ¿Siempre suman 12?
⚠️ Errores frecuentes
| Error | Causa | Solución |
|---|---|---|
| Las columnas no se ponen lado a lado | Falta el div.row, o las columnas no son hijas directas de la fila |
container > row > col-* |
| El diseño cambia en un tamaño distinto del esperado | Confundir "desde este tamaño hacia arriba" con "solo en este tamaño" | Recuerda: col-md-6 rige de 768 px hacia arriba, hasta que otro infijo mayor lo reemplace |
| Una columna baja a la siguiente línea | La suma pasa de 12 | Revisa la suma en cada punto de corte |
| Contenido pegado a los bordes | Usaste una row sin container |
Envuelve la fila en un contenedor |
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: una galería de 12 fotos que muestre 1 por fila en celular, 2 en tableta, 3 en portátil y 4 en escritorio.
- 🟡 Reto 2: el horario de clases (Día 54) como cuadrícula: 5 columnas de días en escritorio y una sola columna en celular. (Pista: 12 no se divide en 5; busca
row-cols-*en la documentación.) - 🟠 Reto 3: un diseño de "barra lateral + contenido": 3/9 en
lg, 4/8 enmdy la barra encima del contenido en celular. - 🔴 Reto 4 — Pensamiento computacional: escribe en una tabla el ancho en píxeles de cada columna del ejercicio 3 del curso a 800, 1000, 1250 y 1500 px de ventana (usa los anchos del
.container). Luego compruébalo en el navegador.
3. Componentes, ejemplos y utilidades
(Fuente: 415 - Bootstrap Components.md)
🎯 Objetivo de aprendizaje
Buscar, copiar y adaptar componentes de la documentación y de la sección de ejemplos de Bootstrap, y ajustar el espaciado con clases utilitarias.
📝 Contenido original del curso
Botones. Un <button> con la clase btn más una clase de color: btn-primary (azul, la acción principal: "Comprar", "Descargar"), btn-success (verde, "OK"), btn-danger (algo peligroso), btn-warning, etc. Reto con los archivos 11.2 Bootstrap Components: un botón verde que diga "Ok" → class="btn btn-success".
Tarjetas (cards). Se copia el código de la documentación y se reemplazan el src, el alt y los textos.
Barra de navegación (navbar). Se copia un ejemplo de Components → Navbar (o de Examples → Headers). En pantallas pequeñas muestra un menú hamburguesa que solo funciona si está el JavaScript de Bootstrap. La profesora construye el sitio de una empresa de mudanzas, Move It:
- Elimina el enlace con la clase
disabledy renombra los enlaces a "About" y "Services". - En la
navbar-brandpuede ir texto, una imagen (ajustando suheight) o un ícono. - Bootstrap Icons: íconos SVG gratuitos, incluso para sitios comerciales. Se pueden pegar como
<svg>o usar como<img src="...svg">. Elige la caja ("box-seam") conheight="30"y unalt. - En el formulario de búsqueda cambia "Search" por "Postcode" y el botón por "Check".
Examples: Heroes y Features. En la sección Examples hay bloques completos. El método: clic derecho → Inspeccionar, subir por el árbol hasta el div que contiene todo el bloque, Copiar elemento y pegarlo en tu HTML. Luego reemplazar imagen y textos (del archivo website-text de los archivos de inicio): "Move with joy", "Get a quote", "Contact us".
CSS personalizado de los ejemplos. En el bloque Features, los cuadrados de los íconos no se ven igual en tu página. Al inspeccionar, se ve que su estilo no viene de las utilidades de Bootstrap sino de un CSS propio del ejemplo (feature-icon). Hay que copiar ese CSS a tu <style> y reemplazar los SVG por los tuyos ("briefcase", "bus-front", "chat-square-heart", "chevron-right") con height="30".
Reto: el carrusel. Buscar en la documentación del Carousel el ejemplo con indicadores, ponerle las imágenes (pareja, perro, familia) y envolverlo en un container para que no ocupe todo el ancho.
Footer: copiado de Examples → Footers.
Espaciado. Formato propiedad + lados + tamaño:
- Propiedad:
m(margen) op(relleno). - Lados:
t(arriba),b(abajo),s(inicio, izquierda),e(fin, derecha),x(izquierda y derecha),y(arriba y abajo), o nada (los cuatro). - Tamaño:
0a5(yauto).
Ejemplos: mt-5 (margen superior grande), mb-2 (margen inferior 2), my-3 (margen arriba y abajo 3), py-5 (relleno arriba y abajo 5).
Modo oscuro: con el atributo data-bs-theme="dark" en la etiqueta <html>, todo el sitio cambia a colores oscuros.
Temas y plantillas: las plantillas de W3Schools (blog, portafolio, red social) para la estructura; los temas oficiales de Bootstrap (de pago, pago único); y muchos sitios de temas gratuitos. Incluso puedes crear y vender tus propios temas.
🛠️ Nota técnica: en la transcripción los ejes aparecen invertidos ("para arriba y abajo se usa el eje x"). Según la documentación de Bootstrap:
y= arriba y abajo (eje vertical) yx= izquierda y derecha. El mismo video lo dice bien más adelante (my-3) y en el proyecto TinDog (py-5). Además, en Bootstrap 5 los lados izquierdo y derecho se escribensye(start, end);ml-3ymr-3eran de Bootstrap 4 y ya no funcionan.
⚠️ Errores frecuentes
| Error | Causa | Solución |
|---|---|---|
| El bloque copiado de Examples se ve distinto | Le falta el CSS propio del ejemplo | Inspecciona, busca las reglas que no vienen de bootstrap.min.css y cópialas |
| Solo se copió una parte del bloque | Se copió un div interior |
Sube en el árbol hasta que se resalte todo el bloque |
| El carrusel ocupa toda la pantalla | Sin contenedor | Envuélvelo en div.container |
ml-3 no hace nada |
Clase de Bootstrap 4 | ms-3 |
| Ícono gigante | El SVG no tiene tamaño | height="30" o una clase de tamaño |
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: crea los 8 botones de colores de Bootstrap y, debajo, sus versiones
btn-outline-*. - 🟡 Reto 2: una navbar con el nombre de tu colegio y cuatro enlaces que, en celular, se convierta en menú hamburguesa funcional.
- 🟠 Reto 3: agrega un botón que cambie entre modo claro y oscuro. (Pista: pide a tu docente o busca en la documentación "Color modes"; necesita una línea de JavaScript que cambie
data-bs-theme.) - 🔴 Reto 4: usa solo clases utilitarias (sin CSS propio) para reproducir una tarjeta de producto: imagen redondeada, precio en negrita, margen entre elementos y sombra.
4. 🔗 Bootstrap dentro de Flask
(Sección creada para esta adaptación; une el Día 58 con los Días 56 y 57.)
🎯 Objetivo de aprendizaje
Servir con Flask una página que use Bootstrap, con los datos generados por Jinja.
📖 Explicación conceptual
Nada cambia en Bootstrap: sigue siendo un <link> y un <script> en la plantilla. Lo nuevo es combinarlo con lo que ya sabes:
<!-- templates/index.html -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="{{ url_for('static', filename='css/styles.css') }}" rel="stylesheet">
...
<div class="container">
<div class="row">
{% for post in posts %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title">{{ post.title }}</h5>
<p class="card-text">{{ post.subtitle }}</p>
<a href="{{ url_for('show_post', index=post.id) }}" class="btn btn-primary">Leer</a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>Un ciclo de Jinja genera una tarjeta por entrada; el sistema de columnas decide cuántas caben por fila según la pantalla. Es el blog del Día 57 con aspecto profesional.
¿CDN o archivo local? La CDN es cómoda y rápida, pero exige Internet. Si tu sitio debe funcionar en una red sin Internet (por ejemplo, una feria en la sala de informática), descarga bootstrap.min.css y bootstrap.bundle.min.js de getbootstrap.com y ponlos en static/.
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: aplica el código anterior al blog del Día 57.
- 🟡 Reto 2: agrega una navbar común con enlaces generados con
url_fora la portada y a cada entrada. - 🟠 Reto 3: sirve Bootstrap desde
static/y comprueba en la pestaña Red que ya no se descarga decdn.jsdelivr.net.
5. 🚀 Proyecto del día: el sitio de la startup TinDog
(Fuente: 416 - Day 58 Project - A Startup Website for TinDog.md)
📝 Ejercicio original del curso
Una startup ficticia, TinDog ("Tinder para perros": ayuda a los perros a conocer perros nuevos cerca), te pide su página de aterrizaje. El resultado final está en appbrewery.github.io/tindog: fondo degradado animado, botones para descargar la aplicación, características, testimonios, precios y pie de página.
Archivos de inicio:
index.htmlcon comentarios y elementos<section>vacíos, uno por área del sitio (mantienen el código organizado).- Imágenes objetivo de cada sección con anotaciones (qué imagen usar, qué margen aplicar).
- Un README con los SVG que se deben usar (no los de la página de Bootstrap, porque tienen otros tamaños) y todos los textos del sitio. "Es un flujo de trabajo muy habitual: el cliente escribe el texto porque es quien mejor sabe lo que quiere; tú lo colocas y le das estilo".
style.csscon la clasegradient-background, tomada de un CodePen de Manuel Pinto (un degradado animado en CSS puro con colores propios: azul, rojo y durazno). Para usarlo, basta con agregar la clase a un elemento.
"Puede que tengas que dedicarle media hora o una hora. Date tiempo para equivocarte". La profesora insiste en intentarlo antes de ver la solución: "puedes escucharme todo el día, pero no aprenderás hasta que escribas el código tú mismo".
El recorrido de la solución:
| Sección | Pasos principales |
|---|---|
| Título | Copiar un Hero de Examples (texto, botones e imagen a la derecha). Se ve sin estilo → falta el <link> de Bootstrap. Imagen images/iphone.png con alt="app demo"; quitar el width y dejar height="200" para conservar la proporción. Título "Meet new and interesting dogs nearby." Quitar el párrafo. Dos botones "Download" con los SVG de Apple y Google Play del README. Colores: btn-light y btn-outline-light. Enlazar style.css después de Bootstrap y poner gradient-background en la section (no en el contenedor, que tiene márgenes). El exceso de espacio es relleno (el fondo se extiende; si fuera margen, se vería blanco): cambiar py-5 por pt-5 en los dos lugares. |
| Características | Copiar la fila de Features de Examples y envolverla en un container. Quitar los botones (enlaces). Reemplazar textos y los SVG (marca de verificación, birrete, corazón con flecha). Copiar el CSS propio del ejemplo (icon-square) a style.css. Agregar mt-5 al contenedor. |
| Testimonios | Copiar el Jumbotron de ancho completo. La cita de "Pebbles" (de Nueva York) va en un h2, no en h1: solo debe haber un h1 por página. Imagen dog-img con una clase propia profile-img (height: 100px; border-radius: 50%), mt-5 en la imagen y mt-2 en el texto. Debajo, los logotipos de prensa (TechCrunch, Mashable, Business Insider, TNW) en un container > row con columnas col-lg-3 col-sm-12 (3/12 en escritorio, 12/12 en celular) y height="30". |
| Precios | Copiar la fila de tarjetas de Pricing y el encabezado, dentro de un container. Cambiar los colores de primary a dark (btn-outline-dark, btn-dark, borde oscuro) uno por uno con Buscar, no con "Reemplazar todo". El título pasa de h1 a h2: el tamaño no cambia porque lo da una clase display-*, no la etiqueta. |
| Pie de página | Copiar un Footer de Examples. Quitar el enlace con el logotipo de Bootstrap; poner "© TinDog". Quitar la clase border-top. Agregar gradient-background. El espacio blanco final es un margen inferior: cambiar my-5 por mt-5. |
"En menos de media hora" se construye un sitio moderno. La lección final: Bootstrap es excelente para lanzar componentes rápido; Flexbox y Grid son mejores para diseños muy personalizados.
🛠️ Nota técnica: el video dice que la clase del pie de página es "mi-5"; es una errata de la transcripción: la clase es
my-5(verificado en el código de la demostración).
Problema y contexto
Una empresa pequeña necesita una página de aterrizaje profesional hoy, y el presupuesto no alcanza para diseñarla desde cero.
🔍 Antes de programar
- Abre la demostración y la barra de dispositivos: ¿qué cambia entre celular y escritorio en cada sección?
- Para cada sección, ¿qué bloque de Examples o qué componente se parece más?
- ¿Qué necesitará CSS propio además de Bootstrap?
Requisitos funcionales
- Cinco secciones: título, características, testimonios, precios y pie de página.
- Degradado animado en el título y en el pie de página.
- Diseño responsivo: logotipos de prensa en 4 columnas en escritorio y en una sola en celular.
- Un solo
h1en toda la página yalten todas las imágenes.
Restricciones técnicas
- Bootstrap 5 por CDN;
style.cssenlazado después. - Clases utilitarias para el espaciado en lugar de CSS propio siempre que sea posible.
- Textos y SVG del README.
Planificación
- Comprender el objetivo con las imágenes de cada sección. 2. Entradas: README, imágenes,
style.css. 3. Procesos: una sección a la vez (copiar → contener → reemplazar → ajustar). 4. Salida: la página completa. 5. Dividir por secciones. 6. Diseñar: anota, para cada sección, el bloque de Bootstrap que usarás. 7. Implementar. 8. Probar en tres tamaños. 9. Corregir. 10. Mejorar.
Construcción paso a paso
- Versión 1: plantilla base con Bootstrap,
style.cssy las cincosectionvacías con un título provisional. - Versión 2: sección de título completa con el degradado.
- Versión 3: características y testimonios.
- Versión 4: precios.
- Versión final: pie de página y revisión en celular, tableta y escritorio.
Pruebas
| Caso | Resultado esperado |
|---|---|
| Ancho 375 px (celular) | Todo en una columna; nada se sale de la pantalla (sin barra de desplazamiento horizontal) |
| Ancho 1280 px (escritorio) | Logotipos en 4 columnas; precios en 3 tarjetas |
| Consola de Chrome | Ningún error 404 |
Contar h1 (document.querySelectorAll("h1").length en la Consola) |
1 |
| Imágenes | Todas con alt |
| Degradado | Animado en título y pie de página |
🧪 Prueba y depuración
<head>
<link rel="stylesheet" href="css/style.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<section id="title">
<div class="container gradient-background">
<h1>Meet new and interesting dogs nearby.</h1>
</div>
</section>
<section id="press">
<div class="row">
<div class="col-lg-3 col-sm-12"><img src="images/techcrunch.png"></div>
</div>
</section>
<section id="testimonials">
<h1>I no longer have to sniff other dogs for love.</h1>
</section>
</body>Encuentra cinco problemas: style.css antes de Bootstrap (Bootstrap sobrescribe tus reglas), el degradado en el container y no en la section (quedan márgenes blancos), la row sin container, la imagen sin alt y un segundo h1.
⭐ Extensión del proyecto
- Servir TinDog con Flask (Día 56):
index.htmlentemplates, imágenes y CSS enstatic, rutas conurl_for. - Generar las tarjetas de precios con Jinja a partir de una lista de diccionarios en Python (Día 57).
- Un botón de modo oscuro (Reto 3 de la sección 3).
6. 🌟 Proyecto extra: la página del emprendimiento del colegio
(Proyecto creado para esta adaptación; no existe en el curso original.)
Situación
Un grupo de grado 10.° tiene un emprendimiento escolar (por ejemplo, venta de postres saludables, reparación de bicicletas o reciclaje de papel) y quiere una página para la feria empresarial del colegio.
Requisitos
- Página con Bootstrap servida por Flask, con al menos: navbar, sección principal con llamado a la acción, catálogo de productos, testimonios, preguntas frecuentes y pie de página.
- El catálogo se genera con Jinja desde
productos.json(nombre, precio en pesos, descripción, imagen, disponible); los productos no disponibles se muestran atenuados (claseopacity-50) con la etiqueta "Agotado". - Las preguntas frecuentes usan el componente Accordion (búscalo tú en la documentación; no se vio en el curso).
- Diseño responsivo: 1 producto por fila en celular, 2 en tableta, 3 en escritorio.
- Precios con formato colombiano (
$ 3.500) calculado en Python.
Decisiones que debes tomar (y justificar)
- ¿Qué bloques de Examples usas y cuáles diseñas tú?
- ¿Qué dato de contacto publicas sin exponer a los integrantes (menores de edad)?
- ¿Qué pasa con tu página si el día de la feria no hay Internet?
Casos de prueba
- Un producto con
"disponible": falsesale atenuado y con "Agotado". productos.jsonvacío → mensaje "Pronto tendremos productos".- A 375 px de ancho no aparece barra de desplazamiento horizontal.
7. 🏆 Proyecto integrador final del bloque Flask (Días 54 a 58)
(Proyecto creado para esta adaptación. Se construyó por etapas desde el Día 54; aquí está su descripción completa y la etapa final.)
Situación problema
El grupo del colegio (club, semillero, equipo deportivo o curso) tiene un sitio hecho en los Días 41 a 44 que ya fue analizado y automatizado en los Días 45 a 53. Pero sigue siendo un conjunto de archivos HTML fijos: para agregar un integrante o una actividad hay que editar varias páginas, copiar y pegar, y siempre queda algo desactualizado.
Contexto
Con Flask, Jinja y Bootstrap, un sitio puede generarse a partir de datos: basta con editar un archivo JSON y todas las páginas se actualizan. Así funcionan los blogs, las tiendas y las plataformas escolares.
Pregunta orientadora
¿Cómo puede un pequeño servidor escrito en Python convertir los datos de un grupo en un sitio web actualizado, seguro, accesible y agradable en cualquier pantalla?
Objetivo
Construir el Portal del Grupo: una aplicación Flask que sirva el sitio del grupo a partir de un archivo de datos, con plantillas Jinja y diseño responsivo con Bootstrap.
Requerimientos
Funcionales
- Servidor (Día 54): aplicación Flask que se ejecuta con
flask --app server runy conpython server.py; un decorador propio@registrar_visita(confunctools.wraps) que registre envisitas.logla hora y la ruta de cada visita. - Rutas dinámicas (Día 55):
/integrante/<int:id>,/actividad/<int:id>; un 404 amable para identificadores inexistentes; nada de HTML armado con f-strings sin escapar. - Plantillas y estáticos (Día 56): todo el HTML en
templates, todo el CSS e imágenes enstatic, rutas conurl_for. - Datos y Jinja (Día 57):
datos.jsoncon integrantes, actividades y anuncios; páginas generadas con{% for %}y{% if %}; actividades futuras y pasadas separadas en Python; año actual en el pie de página. Opcional: una sección que consuma una API pública (por ejemplo, el clima de la ciudad para las actividades al aire libre), con manejo de errores si no responde. - Diseño (Día 58): Bootstrap 5 con navbar, tarjetas de integrantes generadas por Jinja en columnas responsivas, al menos un componente que no se vio en clase (Accordion, Modal, Toast, Badge…) y CSS propio enlazado después de Bootstrap.
No funcionales
- Accesibilidad: un
h1por página,alten todas las imágenes, contraste suficiente (Día 44). - Privacidad: solo datos ficticios o autorizados por escrito; nada de teléfonos, direcciones ni documentos.
- Código legible: nombres descriptivos, funciones cortas, comentarios donde haga falta, un
README.mdcon instrucciones de instalación y ejecución.
Restricciones
- Sin
debug=Trueen la versión de entrega (usa--debugsolo al desarrollar). - Plantillas con licencia libre y créditos en
CREDITOS.md. - El servidor solo se ejecuta en la red local del colegio (
127.0.0.1o la IP que autorice el docente).
Etapas de desarrollo
| Etapa | Día | Producto |
|---|---|---|
| 1. Primer servidor | 54 | server.py con rutas básicas, decorador de visitas, README.md |
| 2. Rutas dinámicas | 55 | /integrante/<nombre>, /actividad/<int:numero>, escape, functools.wraps |
| 3. Plantillas y estáticos | 56 | El sitio de los Días 41 a 44 dentro de templates y static, con url_for |
| 4. Datos con Jinja | 57 | datos.json, ciclos y condiciones, enlaces con url_for, pie con el año |
| 5. Diseño responsivo | 58 | Bootstrap, navbar, tarjetas en columnas, componente nuevo, revisión en tres tamaños |
Etapa 5 (hoy)
- Agrega Bootstrap a todas las plantillas (por ahora, copiando el
<head>en cada una; el Día 59 aprenderás a no repetirlo con herencia de plantillas). - Convierte
/integrantesen una cuadrícula de tarjetas (1-2-3 columnas según la pantalla). - Una navbar común con los enlaces del sitio generados con
url_for. - Un componente nuevo investigado por tu cuenta en la documentación.
- Revisa el sitio completo con la tabla de casos de prueba.
Entregables
- La carpeta
portal_grupocompleta:server.py,datos.json,templates/,static/,README.md,CREDITOS.mdycuaderno_errores.md. - Capturas del sitio en celular (375 px) y en escritorio (1280 px).
- Un informe de pruebas con la tabla de casos y sus resultados.
- Una demostración de 5 minutos: agregar un integrante editando solo
datos.json, mostrar que aparece en todas las páginas y explicar una decisión de diseño (por qué<int:id>, por quéurl_for, por qué escapar).
Casos de prueba
| # | Caso | Resultado esperado |
|---|---|---|
| 1 | Agregar un integrante en datos.json y recargar |
Aparece en /integrantes y tiene su página /integrante/<id> |
| 2 | /integrante/999 y /integrante/abc |
Página 404 amable, no el depurador |
| 3 | Un integrante con nombre <b>Prueba</b> en los datos |
Se muestra como texto, sin negrita |
| 4 | Visitar tres páginas | Tres líneas nuevas en visitas.log |
| 5 | Actividad con fecha de ayer | Aparece en "Pasadas" |
| 6 | 375 px de ancho | Una tarjeta por fila, menú hamburguesa funcional, sin desplazamiento horizontal |
| 7 | Consola de Chrome en todas las páginas | Ningún error 404 |
| 8 | Si se usa la API opcional: sin conexión | Mensaje "Información no disponible", la página carga igual |
Criterios técnicos de funcionamiento
| Criterio | Nivel básico | Nivel alto |
|---|---|---|
| Servidor y rutas | Las rutas responden | Convertidores adecuados, 404 personalizados, sin debug en la entrega |
| Plantillas | Páginas renderizadas con render_template |
Una plantilla por tipo de página, lógica en Python, datos en JSON |
| Seguridad | No hay HTML armado a mano con datos del usuario | Escape comprobado con el caso 3; ningún secreto en el código |
| Diseño | Usa Bootstrap | Responsivo en tres tamaños, componente nuevo integrado, CSS propio mínimo y bien ubicado |
| Accesibilidad y privacidad | alt en las imágenes |
Un h1 por página, contraste revisado, solo datos ficticios o autorizados |
| Documentación | Hay README.md |
Un compañero instala y ejecuta el proyecto solo con el README |
| Proceso | Entrega el código | Cuaderno de errores con al menos 8 entradas de los Días 54 a 58 |
Posibles extensiones
- Herencia de plantillas con
{% extends %}y{% block %}(Día 59 del curso). - Un formulario de inscripción a actividades que envíe datos al servidor (Días 60 a 62 del curso).
- Guardar los datos en una base de datos SQLite en lugar de JSON (Día 63 del curso).
8. 🧩 Comprueba lo aprendido
Conceptuales
- ¿Qué es un framework de CSS? Da dos ventajas y dos desventajas de Bootstrap.
- ¿Por qué el
<script>de Bootstrap va al final del<body>? ¿Qué deja de funcionar si falta? - ¿Qué significa exactamente
col-md-6? ¿Qué ancho tiene ese elemento en una pantalla de 500 px? - ¿Qué diferencia hay entre
containerycontainer-fluid? - ¿Por qué tu hoja de estilos debe enlazarse después de la de Bootstrap?
Análisis de código
<div class="container">
<div class="row">
<div class="col-lg-3 col-md-6">A</div>
<div class="col-lg-3 col-md-6">B</div>
<div class="col-lg-6">C</div>
</div>
</div>Describe cómo se ven A, B y C en 400 px, 800 px y 1100 px.
Predicción
¿Qué hace cada clase: mt-0, px-3, my-auto, pb-5, ms-2?
Depuración
<div class="row">
<div class="col-8">Contenido</div>
<div class="col-6">Barra lateral</div>
</div>
<button class="btn-primary">Enviar</button>Encuentra los tres problemas.
Modificación
Cambia la sección de precios de TinDog para que en tableta (md) muestre 2 tarjetas por fila en lugar de 3.
Creación
Con Flask, Jinja y Bootstrap, crea una página /equipo que reciba una lista de 6 diccionarios (nombre, rol, emoji) y muestre una tarjeta por persona: 2 por fila en celular y 3 en escritorio.
9. 🤖 Programar con apoyo de IA
Ciclo de trabajo: formula el problema → inténtalo tú → consulta a la IA → lee y entiende → prueba → compara con la documentación oficial → modifica → explica con tus palabras.
Actividad 1 — ¿Qué versión? Pide a una IA el código de una navbar de Bootstrap. Revisa: ¿qué versión carga? ¿Usa clases de Bootstrap 4 (ml-auto, data-toggle) o de Bootstrap 5 (ms-auto, data-bs-toggle)? Compara con la página de Navbar de la documentación 5.3.
Actividad 2 — Verificar los puntos de corte. Pregunta a una IA desde qué ancho se aplica col-lg-*. Compruébalo con la barra de dispositivos de Chrome y con la tabla de "Breakpoints" de la documentación.
Actividad 3 — Accesibilidad. Pide a una IA una sección "hero" con Bootstrap. Revisa si las imágenes tienen alt, si hay más de un h1 y si el contraste de los botones es suficiente (usa la herramienta de contraste de las herramientas de desarrollo). Corrige lo necesario.
10. 🛠️ Correcciones técnicas al material original
| Archivo | Afirmación o comportamiento del curso | Observación | Tratamiento |
|---|---|---|---|
415 |
"Para arriba y abajo se usa el eje x; para izquierda y derecha, el eje y" | Está invertido: y = arriba y abajo, x = izquierda y derecha (documentación de Bootstrap; el propio curso lo usa bien en my-3 y py-5) |
Nota técnica de la sección 3 |
415 |
Clases de espaciado con lados t, b… |
En Bootstrap 5, izquierda y derecha son s y e; ml-* y mr-* ya no existen |
Nota técnica de la sección 3 |
416 |
Cambiar "mi-5" por "mt-5" en el pie de página | Errata de la transcripción: la clase es my-5 (verificado en la demostración) |
Nota técnica de la sección 5 |
414 |
En el ejercicio 1, "al reducir el ancho alcanzamos el punto de corte sm" | El código de la demostración usa col-xl-6 (verificado): el cambio ocurre en 1200 px, como dice la solución del mismo video |
Tabla de ejercicios de la sección 2 |
414 |
Anchos del contenedor "540 en móvil, 720 o 960 en iPad, unos 1000 en escritorio" | Valores de la documentación: 100 % (< 576), 540, 720, 960, 1140 y 1320 px | Tabla de la sección 2 |
413 |
Incluir Bootstrap por CDN | La versión actual es la 5.3.8 (verificado); falta mencionar la etiqueta viewport, indispensable para el diseño responsivo |
Plantilla base de la sección 1 |
11. 📋 Matriz de trazabilidad
| Contenido original | Archivo de origen | Concepto desarrollado | Ejercicio original | Reto adicional | Proyecto relacionado |
|---|---|---|---|---|---|
| Presentación de Bootstrap, sección tomada del curso de desarrollo web, repetición | 412 |
Sección 0 | — | Por qué importa en Python | Sección 7 |
Historia (2010, Otto y Thornton), CSS prehecho, 12 columnas con Flexbox, mobile first, otros frameworks, uso en la web, ventajas y desventajas, cuándo usarlo, CDN, .min, ejercicio 11.0 con 4 TODO, centrado con Flexbox, sobrescribir estilos |
413 |
Sección 1 | Tarjeta del girasol centrada | Retos 1–4 de la sección 1; viewport |
Secciones 5 y 6 |
container, row, col, contenedores responsivos, container-fluid, columnas de tamaño, puntos de corte, varios infijos, mezcla con col, barra de dispositivos, 3 ejercicios de bootstrap-layout |
414 |
Sección 2 | Tres ejercicios de diseño | Retos 1–4 de la sección 2 | Secciones 5, 6 y 7 |
Botones y colores, tarjetas, navbar y JavaScript, Move It, disabled, navbar-brand, Bootstrap Icons, Hero y Features de Examples, CSS propio de los ejemplos, carrusel en contenedor, footer, espaciado, modo oscuro, temas |
415 |
Sección 3 | Botón verde "Ok"; sitio Move It; reto del carrusel | Retos 1–4 de la sección 3 | Secciones 5 y 6 |
| (No existe en el curso original) | — | Sección 4 | — | Bootstrap con Flask y Jinja | Secciones 6 y 7 |
Proyecto TinDog: secciones, README con SVG y textos, gradient-background, solución de título, características, testimonios, prensa, precios y pie de página |
416 |
Sección 5 | Proyecto del día | Extensiones con Flask y Jinja | Sección 5 |
| (No existe en el curso original) | — | — | — | Página del emprendimiento del colegio | Sección 6 |
| (No existe en el curso original) | — | — | — | Portal del Grupo: proyecto integrador final (etapas de los Días 54 a 58) | Sección 7 |
12. 📦 Evidencias de aprendizaje del Día 58
- La tarjeta centrada del ejercicio
11.0y las soluciones de los tres ejercicios de diseño (capturas en los tamaños clave). - El sitio TinDog completo con capturas en 375 px y 1280 px y la tabla de pruebas.
- El blog del Día 57 con tarjetas de Bootstrap (Reto 1 de la sección 4).
- La página del emprendimiento (proyecto extra).
- El Portal del Grupo con todos sus entregables.
- Cuaderno de errores: falta el
<link>o el<script>, CSS propio antes de Bootstrap,rowsincontainer, columnas que suman más de 12, punto de corte mal entendido, bloque de Examples sin su CSS, clases de Bootstrap 4, falta deviewport, más de unh1.