Skip to content

Bootstrap ​

Bootstrap es el framework de CSS más usado de la historia: millones de sitios, paneles administrativos y sistemas internos están hechos con él. Te da un grid responsive y componentes listos (navbar, tarjetas, modales, formularios) con sólo añadir clases. En esta lección aprenderás a incluirlo, a dominar su grid de 12 columnas, sus utilidades y componentes, a personalizarlo para que no "se vea a Bootstrap", y a decidir cuándo usarlo.

Concepto ​

Bootstrap es un framework de componentes: en lugar de piezas pequeñas como Tailwind, te entrega piezas armadas. Escribes class="btn btn-primary" y obtienes un botón completo con colores, estados y accesibilidad.

Analogía

Si Tailwind es un juego de LEGO, Bootstrap es una tienda de muebles armados: eliges un sillón, una mesa y un librero, y en una tarde tienes la sala lista. El costo: tu sala se parece a la de mucha gente, salvo que la personalices.

Incluye tres cosas:

  1. Grid de 12 columnas, responsive.
  2. Componentes (CSS + JavaScript): navbar, cards, modal, dropdown, carousel, acordeón, toasts...
  3. Utilidades: clases de una sola propiedad para espaciado, colores, flex, texto, etc.

Instalación con CDN (Bootstrap 5.3) ​

La forma más rápida: un link en el head y un script al final del body.

html
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Mi sitio con Bootstrap</title>
  <!-- CSS de Bootstrap -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
  <!-- Tu CSS va DESPUÉS, para poder sobrescribir -->
  <link href="css/estilos.css" rel="stylesheet">
</head>
<body>
  <div class="container py-5">
    <h1 class="display-5 fw-bold">¡Hola, Bootstrap!</h1>
    <button class="btn btn-primary">Mi primer botón</button>
  </div>

  <!-- JS de Bootstrap (incluye Popper para dropdowns y tooltips) -->
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Con npm (para personalizar con Sass): npm install bootstrap.

Buena práctica

Bootstrap 5 ya no necesita jQuery. Si ves tutoriales que lo incluyen, son de Bootstrap 4 o anteriores. Busca siempre documentación de la versión 5.3.

Contenedores ​

Todo layout empieza con un contenedor:

ClaseComportamiento
.containerAncho máximo que cambia por breakpoint (540, 720, 960, 1140, 1320px) y centrado
.container-fluidSiempre 100 % del ancho
.container-md100 % hasta md, luego se comporta como .container

Grid de 12 columnas ​

El grid de Bootstrap se basa en filas (.row) y columnas (.col-*). Cada fila se divide en 12 partes y tú decides cuántas ocupa cada columna.

txt
┌────────────────────────── .row (12 partes) ──────────────────────────┐
│  .col-12 ─────────────────────────────────────────────────────────── │
│  .col-6 ─────────────────────────  .col-6 ────────────────────────── │
│  .col-4 ────────────── .col-4 ──────────────  .col-4 ─────────────── │
│  .col-3 ──────  .col-9 ────────────────────────────────────────────  │
└──────────────────────────────────────────────────────────────────────┘

Breakpoints ​

InfijoDesdeTípico
(ninguno)0Móviles
sm576pxMóviles grandes
md768pxTablets
lg992pxLaptops
xl1200pxEscritorio
xxl1400pxPantallas grandes

Igual que en Responsive design, es mobile-first: col-md-6 significa "6 de 12 columnas desde 768px; antes, ancho completo".

html
<div class="container">
  <!-- g-4: separación (gutter) entre columnas -->
  <div class="row g-4">
    <!-- Móvil: 12/12 (una por fila). Tablet: 6/12 (dos). Escritorio: 4/12 (tres) -->
    <div class="col-12 col-md-6 col-lg-4">Diseño</div>
    <div class="col-12 col-md-6 col-lg-4">Desarrollo</div>
    <div class="col-12 col-md-6 col-lg-4">SEO</div>
  </div>
</div>

Otras herramientas del grid:

html
<!-- Columnas automáticas: se reparten el espacio por igual -->
<div class="row">
  <div class="col">1</div>
  <div class="col">2</div>
  <div class="col">3</div>
</div>

<!-- Lateral fijo de 3 columnas + contenido de 9, desde lg -->
<div class="row">
  <aside class="col-lg-3">Filtros</aside>
  <main class="col-lg-9">Productos</main>
</div>

<!-- row-cols: define cuántas columnas por fila desde la fila -->
<div class="row row-cols-1 row-cols-sm-2 row-cols-lg-4 g-3">
  <div class="col">...</div>
  <div class="col">...</div>
</div>

<!-- Desplazar y reordenar -->
<div class="row">
  <div class="col-md-6 offset-md-3">Centrado en tablet y escritorio</div>
  <div class="col-md-6 order-md-first">Va primero desde md</div>
</div>

Error común

Las columnas siempre deben ser hijas directas de un .row, y la .row debe estar dentro de un contenedor. Si pones contenido directamente en .row o anidas .col sin .row, los márgenes negativos del gutter generan scroll horizontal.

Utilidades ​

Bootstrap trae utilidades parecidas a las de Tailwind, con nombres más cortos:

html
<!-- Espaciado: m/p + lado (t, b, s=start, e=end, x, y) + tamaño 0-5 (0 a 3rem) -->
<div class="mt-4 px-3 py-5 mb-0">...</div>

<!-- Flexbox -->
<div class="d-flex justify-content-between align-items-center gap-3">...</div>

<!-- Responsive en utilidades: d-none d-md-block = oculto en móvil, visible desde md -->
<div class="d-none d-md-block">Sólo en tablet y escritorio</div>

<!-- Texto y color -->
<p class="text-center text-body-secondary fs-5 fw-semibold">...</p>
<div class="bg-primary text-white rounded-3 shadow">...</div>
<div class="bg-success-subtle text-success-emphasis border border-success-subtle">Éxito</div>

<!-- Tamaños -->
<img class="w-100 h-auto" src="..." alt="...">

Componentes ​

html
<nav class="navbar navbar-expand-lg bg-body-tertiary sticky-top">
  <div class="container">
    <a class="navbar-brand fw-bold" href="#">Estudio Nova</a>
    <!-- Botón hamburguesa: Bootstrap ya maneja aria-expanded por ti -->
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
            data-bs-target="#menu" aria-controls="menu" aria-expanded="false" aria-label="Abrir menú">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="menu">
      <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
        <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Inicio</a></li>
        <li class="nav-item"><a class="nav-link" href="#servicios">Servicios</a></li>
        <li class="nav-item"><a class="nav-link" href="#contacto">Contacto</a></li>
      </ul>
      <a class="btn btn-primary ms-lg-3" href="#contacto">Cotizar</a>
    </div>
  </div>
</nav>

navbar-expand-lg indica desde qué breakpoint el menú deja de ser colapsable. El comportamiento del botón viene de los atributos data-bs-*: no escribes ni una línea de JavaScript.

Cards ​

html
<div class="card h-100 shadow-sm">
  <img src="img/servicio.webp" class="card-img-top" alt="Diseño web">
  <div class="card-body d-flex flex-column">
    <h5 class="card-title">Diseño web</h5>
    <p class="card-text text-body-secondary">Sitios rápidos, modernos y fáciles de administrar.</p>
    <a href="#" class="btn btn-outline-primary mt-auto">Ver más</a>
  </div>
</div>

Botones ​

html
<button class="btn btn-primary">Primario</button>
<button class="btn btn-secondary">Secundario</button>
<button class="btn btn-success">Éxito</button>
<button class="btn btn-outline-danger">Peligro</button>
<button class="btn btn-primary btn-lg">Grande</button>
<button class="btn btn-link">Como enlace</button>
html
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalCotizar">
  Pedir cotización
</button>

<div class="modal fade" id="modalCotizar" tabindex="-1" aria-labelledby="modalCotizarTitulo" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header">
        <h2 class="modal-title fs-5" id="modalCotizarTitulo">Pedir cotización</h2>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
      </div>
      <div class="modal-body">Te respondemos en menos de 24 horas.</div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
        <a href="#contacto" class="btn btn-primary">Ir al formulario</a>
      </div>
    </div>
  </div>
</div>

Formularios ​

html
<form class="row g-3 needs-validation" novalidate>
  <div class="col-md-6">
    <label for="nombre" class="form-label">Nombre</label>
    <input type="text" class="form-control" id="nombre" required>
    <div class="invalid-feedback">Escribe tu nombre.</div>
  </div>
  <div class="col-md-6">
    <label for="correo" class="form-label">Correo</label>
    <input type="email" class="form-control" id="correo" required>
    <div class="invalid-feedback">Escribe un correo válido.</div>
  </div>
  <div class="col-12">
    <label for="servicio" class="form-label">Servicio</label>
    <select id="servicio" class="form-select">
      <option>Diseño web</option>
      <option>Tienda en línea</option>
    </select>
  </div>
  <div class="col-12 form-check ms-2">
    <input class="form-check-input" type="checkbox" id="acepto" required>
    <label class="form-check-label" for="acepto">Acepto el aviso de privacidad</label>
  </div>
  <div class="col-12">
    <button class="btn btn-primary" type="submit">Enviar</button>
  </div>
</form>
js
// Validación visual de Bootstrap: añade .was-validated al intentar enviar
document.querySelectorAll('.needs-validation').forEach((form) => {
  form.addEventListener('submit', (e) => {
    if (!form.checkValidity()) {
      e.preventDefault()
      e.stopPropagation()
    }
    form.classList.add('was-validated')
  })
})

Así se ve todo junto:

Navbar, grid y cards con Bootstrap

Personalización ​

El mayor reproche a Bootstrap es que "todos los sitios se ven iguales". Tienes dos niveles para evitarlo.

Nivel 1: variables CSS (sin compilar nada) ​

Bootstrap 5.3 expone sus valores como variables CSS con prefijo --bs-. Sobrescríbelas en tu propio archivo, cargado después de Bootstrap:

css
:root {
  --bs-primary: #7c3aed;
  --bs-primary-rgb: 124, 58, 237;
  --bs-body-font-family: "Inter", system-ui, sans-serif;
  --bs-border-radius: 0.75rem;
  --bs-link-color-rgb: 124, 58, 237;
}

/* Los botones tienen sus propias variables locales */
.btn-primary {
  --bs-btn-bg: #7c3aed;
  --bs-btn-border-color: #7c3aed;
  --bs-btn-hover-bg: #6d28d9;
  --bs-btn-hover-border-color: #6d28d9;
  --bs-btn-active-bg: #5b21b6;
}

Bootstrap 5.3 también trae modo oscuro: añade data-bs-theme="dark" a html o a cualquier contenedor.

Nivel 2: Sass (la forma completa) ​

Con npm install bootstrap sass puedes cambiar las variables antes de compilar, y todo (botones, alertas, utilidades bg-primary, bordes) se regenera con tus valores. También puedes importar sólo los componentes que usas para reducir el peso:

scss
// scss/main.scss
// 1. Tus variables primero (Bootstrap usa !default, así que respeta las tuyas)
$primary: #7c3aed;
$font-family-base: "Inter", system-ui, sans-serif;
$border-radius: 0.75rem;
$enable-shadows: true;

// 2. Después, Bootstrap completo
@import "bootstrap/scss/bootstrap";

// 3. Tus estilos propios
.hero { padding-block: 6rem; }

Sobre @import aquí

En la lección de Sass aprendiste que @import está obsoleto. Bootstrap 5.3 todavía se distribuye con esa sintaxis, así que su documentación oficial lo usa (verás avisos de deprecación al compilar; puedes silenciarlos con --quiet-deps). En tus propios archivos usa siempre @use.

¿Bootstrap, Tailwind o CSS propio? ​

SituaciónMejor opción
Panel administrativo, sistema interno, prototipo rápidoBootstrap: componentes listos con JS incluido
Equipo con backend fuerte y poco diseñoBootstrap
Diseño a medida desde Figma, landing pages de marcaTailwind o CSS propio
Proyecto con componentes (Vue, React, Astro)Tailwind encaja muy bien
Sitio pequeño, máximo rendimiento, control totalCSS propio con variables y BEM
Proyecto heredado que ya usa unoEl que ya usa: no mezcles frameworks

Buena práctica

Sea cual sea tu elección, nunca cargues dos frameworks a la vez (Bootstrap y Tailwind chocan en nombres como .container o .hidden). Y si usas Bootstrap, aprovecha sus componentes: si vas a sobrescribirlo casi todo, probablemente no lo necesitabas.

Ejercicios ​

  1. Crea una fila con 4 tarjetas: 1 por fila en móvil, 2 en tablet (md) y 4 en escritorio (xl).
  2. Haz un layout de blog: contenido de 8 columnas y barra lateral de 4 desde lg; en móvil, la barra lateral debajo.
  3. Cambia el color primario de Bootstrap a verde #059669 usando sólo variables CSS para los botones primarios.
  4. Crea un botón que abra un modal con el título "Suscríbete" y un campo de correo.
Ver solución
html
<!-- 1 -->
<div class="container">
  <div class="row g-4">
    <div class="col-12 col-md-6 col-xl-3"><div class="card card-body">1</div></div>
    <div class="col-12 col-md-6 col-xl-3"><div class="card card-body">2</div></div>
    <div class="col-12 col-md-6 col-xl-3"><div class="card card-body">3</div></div>
    <div class="col-12 col-md-6 col-xl-3"><div class="card card-body">4</div></div>
  </div>
</div>

<!-- 2 -->
<div class="container">
  <div class="row g-5">
    <main class="col-lg-8">Artículo</main>
    <aside class="col-lg-4">Barra lateral</aside>
  </div>
</div>

<!-- 4 -->
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#suscribir">Suscribirme</button>
<div class="modal fade" id="suscribir" tabindex="-1" aria-labelledby="suscribirTitulo" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h2 class="modal-title fs-5" id="suscribirTitulo">Suscríbete</h2>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
      </div>
      <div class="modal-body">
        <label for="correo-sus" class="form-label">Correo</label>
        <input type="email" id="correo-sus" class="form-control" placeholder="tu@correo.com">
      </div>
      <div class="modal-footer">
        <button class="btn btn-primary">Enviar</button>
      </div>
    </div>
  </div>
</div>
css
/* 3 */
.btn-primary {
  --bs-btn-bg: #059669;
  --bs-btn-border-color: #059669;
  --bs-btn-hover-bg: #047857;
  --bs-btn-hover-border-color: #047857;
  --bs-btn-active-bg: #065f46;
  --bs-btn-active-border-color: #065f46;
}

Resumen ​

  • Bootstrap = grid + componentes con JS + utilidades. Inclúyelo con el CDN 5.3 (CSS + bootstrap.bundle.min.js).
  • Grid: .container → .row → .col-*; 12 columnas, mobile-first, breakpoints sm md lg xl xxl.
  • Utilidades: m-*, p-*, d-flex, d-none d-md-block, text-*, bg-*.
  • Componentes con data-bs-*: navbar colapsable, modal, dropdown, sin escribir JS.
  • Personaliza con variables --bs-* o con Sass para que no parezca "otro sitio Bootstrap".
  • Elige herramienta según el proyecto y nunca mezcles frameworks.

Siguiente: CSS moderno.

Academia Web — aprende, copia y construye.