Apostila completa · Bootstrap 5.3

Bootstrap 5, do zero ao nível profissional

Um guia único e navegável para quem já conhece HTML e CSS básicos e quer dominar o framework front-end mais pedido em vagas júnior no Brasil — com exercícios, projetos completos e preparação para entrevistas.

17 módulos 50+ exemplos ao vivo 3 projetos completos Perguntas de entrevista respondidas

☆ Como usar esta apostila

Esta página foi construída com o próprio Bootstrap 5.3. Isso significa que cada componente que você vai estudar está funcionando de verdade aqui dentro: o menu lateral usa Scrollspy, o menu do celular usa Offcanvas, os exemplos usam Cards, Accordions e tudo o mais. A apostila é, ela mesma, um projeto de referência.

🖥️
Exemplos ao vivo

Blocos com borda tracejada roxa mostram o resultado renderizado. Clique em </> Ver código para revelar o HTML exato que gerou aquele resultado.

✍️
Exercícios com solução

Todo módulo termina com exercícios. Tente resolver antes de abrir a solução escondida no bloco "Ver solução".

💼
Foco em mercado

Blocos verdes "Visão de mercado" conectam a teoria com o que empresas realmente pedem em vagas e entrevistas.

Trilha sugerida de estudo
  • Semana 1: módulos 1 a 4 (fundamentos e grid) — a base de tudo.
  • Semana 2: módulos 5 a 8 (utilitários, componentes, navbar).
  • Semana 3: módulos 9 e 10 (formulários e componentes JS) + projeto 1.
  • Semana 4: módulos 11 a 14 (nível avançado) + projetos 2 e 3.
  • Semana 5: desafios finais, revisão e módulo 17 (entrevistas).

Para praticar, use o CodePen ou o VS Code com a extensão Live Server. O importante é digitar o código, não copiar e colar.

Módulo 01 · Fundamentos

O que é o Bootstrap (e por que o mercado ainda o usa tanto)

O Bootstrap é um framework front-end: uma coleção pronta de CSS e JavaScript que resolve os problemas mais repetitivos da construção de interfaces — grade de layout responsivo, botões, formulários, menus, janelas modais — para que você não precise escrever tudo do zero em cada projeto.

Ele nasceu em 2011 dentro do Twitter (por isso o nome antigo, Twitter Blitz/Bootstrap), criado por Mark Otto e Jacob Thornton para padronizar as ferramentas internas da empresa. Foi liberado como código aberto e virou, por anos, o repositório mais estrelado do GitHub.

Linha do tempo das versões

VersãoAnoO que mudou de importante
2.x2012Primeira versão com layout responsivo opcional.
3.x2013Mobile first por padrão. Ainda aparece em sistemas legados de empresas.
4.x2018Grid reescrito com Flexbox; Sass no lugar de Less; muitos sistemas corporativos usam até hoje.
5.x2021+Removeu a dependência de jQuery, adicionou utilitários novos, RTL, Offcanvas e, na 5.3, dark mode nativo. É a versão desta apostila.
💼 Visão de mercado

Por que aprender Bootstrap em vez de ir direto para outra coisa?

  • Base instalada gigante: milhões de sistemas internos, painéis administrativos, e-commerces e sites institucionais no Brasil rodam Bootstrap 3, 4 ou 5. Manutenção de legado é uma porta de entrada real para júnior.
  • Vagas: Bootstrap aparece com frequência em descrições de vagas de desenvolvedor front-end júnior, full stack (especialmente PHP/Laravel, C#/.NET e Java/Spring) e web designer.
  • Velocidade de entrega: agências e software houses cobram por projeto; entregar um site responsivo em dias, não semanas, é diferencial econômico direto.
  • Conceitos transferíveis: grid de 12 colunas, mobile first, breakpoints e utilitários existem em quase todos os frameworks. Dominar Bootstrap facilita aprender Tailwind depois (módulo 14).

O que vem "dentro da caixa"

  • Reboot: uma normalização de estilos que deixa todos os navegadores parecidos.
  • Sistema de grid: 12 colunas flexíveis e responsivas (módulo 4).
  • Componentes: mais de 20 blocos prontos — cards, navbar, modal, carousel...
  • Utilitários: centenas de classes pequenas para margem, cor, flexbox, etc. (módulo 5).
  • Plugins JavaScript: comportamento pronto para dropdown, modal, toast, sem jQuery.
  • Ícones (pacote separado): a biblioteca Bootstrap Icons, com 2.000+ ícones SVG.
⚠️ Atenção
Bootstrap não substitui saber CSS. Ele acelera. Nas entrevistas, é comum o avaliador perguntar "como você faria isso sem o Bootstrap?" justamente para separar quem entende de quem só decora classes. Ao longo da apostila, sempre explicamos o CSS por trás de cada classe.

✍️ Exercícios do módulo 1

  1. Com suas palavras, explique a diferença entre uma biblioteca de componentes e escrever CSS puro. Cite 2 vantagens e 2 desvantagens de cada abordagem.
  2. Abra 3 vagas reais de "desenvolvedor front-end júnior" (LinkedIn, Gupy, Programathor) e anote quais tecnologias aparecem junto com Bootstrap. Guarde essa lista: ela vira seu plano de estudos.
Ver comentário da solução

1. Framework: mais velocidade, consistência visual e responsividade pronta; em troca, sites podem "parecer Bootstrap" e o CSS final carrega código não usado. CSS puro: controle e leveza totais; em troca, mais tempo, mais bugs entre navegadores e necessidade de criar seu próprio sistema de grid.

2. Padrões comuns que você vai encontrar: HTML/CSS/JS + Bootstrap + jQuery (legado), PHP/Laravel + Bootstrap + Blade, C#/.NET + Bootstrap + Razor, e WordPress + Bootstrap. Isso mostra que Bootstrap raramente anda sozinho — ele acompanha um back-end.

Módulo 02 · Fundamentos

Instalação e primeiro projeto

Existem três formas principais de adicionar o Bootstrap a um projeto. Para estudar e para a maioria dos sites institucionais, a CDN resolve. Em projetos profissionais com build (Vite, Webpack, Laravel Mix), usa-se npm + Sass.

Opção 1 — CDN (a mais rápida)

Basta colar dois links. O CSS vai no <head> e o JavaScript antes de fechar o </body>:

<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <!-- Obrigatória: sem ela, o layout responsivo não funciona no celular -->
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Meu primeiro projeto Bootstrap</title>

  <!-- CSS do Bootstrap 5.3 -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

  <h1>Olá, Bootstrap!</h1>
  <button class="btn btn-primary">Meu primeiro botão</button>

  <!-- JS do Bootstrap (bundle já inclui o Popper, usado por dropdowns e tooltips) -->
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
⚠️ Erros clássicos de iniciante
  • Esquecer a <meta name="viewport"> → o site abre "encolhido" no celular.
  • Importar só o CSS e esquecer o JS → dropdown, modal e navbar mobile "não abrem".
  • Usar bootstrap.min.js em vez de bootstrap.bundle.min.js sem incluir o Popper separadamente → tooltips e dropdowns quebram.

Opção 2 — Download local

Baixe o pacote compilado em getbootstrap.com, copie as pastas css/ e js/ para o projeto e referencie localmente. Útil para intranets sem acesso à internet — cenário comum em empresas e órgãos públicos.

<link href="assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<script src="assets/bootstrap/js/bootstrap.bundle.min.js"></script>

Opção 3 — npm (projetos profissionais)

# dentro da pasta do projeto
npm install bootstrap@5.3.3

# o Sass é necessário para customizar (módulo 11)
npm install -D sass

E no seu arquivo Sass principal:

// styles.scss — importa o Bootstrap inteiro
@import "bootstrap/scss/bootstrap";

No módulo 11 você aprenderá a importar só as partes que usa e a trocar as variáveis de tema — é isso que separa o uso amador do uso profissional.

Estrutura de pastas recomendada (projeto simples)

meu-projeto/
├── index.html
├── css/
│   └── estilos.css        ← seu CSS fica SEMPRE depois do Bootstrap
├── js/
│   └── app.js
└── img/
💼 Visão de mercado
A ordem dos arquivos CSS importa: seu CSS entra depois do Bootstrap para poder sobrescrevê-lo. Saber explicar isso (cascata e especificidade) é pergunta recorrente em entrevista júnior.

Testando se funcionou

Se o botão abaixo aparecer azul e com cantos arredondados, o CSS carregou. Se o dropdown abrir ao clicar, o JavaScript carregou:

✍️ Exercícios do módulo 2

  1. Crie um arquivo index.html do zero com Bootstrap via CDN, um <h1> e três botões: um btn-primary, um btn-outline-danger e um btn-success btn-lg.
  2. Remova a linha do <script> e tente abrir um dropdown. Observe o que acontece e explique o porquê.
  3. Instale o Bootstrap via npm em uma pasta de teste e localize, dentro de node_modules/bootstrap/, as pastas dist/ e scss/. Qual a diferença entre elas?
Ver solução

2. O dropdown não abre: quem escuta o clique e adiciona a classe .show é o JavaScript do Bootstrap. Sem o bundle, só existe o estilo, não o comportamento.

3. dist/ contém os arquivos compilados e minificados, prontos para o navegador. scss/ contém o código-fonte em Sass, que você importa e customiza em projetos com build.

Módulo 03 · Fundamentos

Containers e breakpoints: a base do responsivo

Antes do grid, você precisa entender duas ideias que sustentam todo o Bootstrap: o container (a moldura do conteúdo) e os breakpoints (os pontos de largura de tela onde o layout muda).

Containers

  • .container — largura fixa por faixa de tela, centralizado, com margens automáticas. O mais usado em sites institucionais.
  • .container-fluid — ocupa 100% da largura sempre. Usado em dashboards e sistemas.
  • .container-{breakpoint} — fluido até o breakpoint indicado, fixo depois. Ex.: .container-lg é 100% em telas pequenas e fixo a partir de 992px.
.container
.container-fluid

Os 6 breakpoints do Bootstrap 5

Decore esta tabela — ela é usada em todas as classes responsivas do framework:

SufixoNomeLargura mínimaPense em…
(nenhum)extra small0celular em pé
smsmall≥ 576pxcelular deitado
mdmedium≥ 768pxtablet
lglarge≥ 992pxnotebook
xlextra large≥ 1200pxdesktop
xxlextra extra large≥ 1400pxmonitor grande

Mobile first: o conceito que reprova ou aprova em entrevista

O Bootstrap é mobile first: toda classe sem sufixo vale a partir do celular para cima, e os sufixos (sm, md…) sobrescrevem a partir daquele ponto. Ou seja, col-12 col-md-6 significa: "ocupe 12 colunas no celular e 6 colunas do tablet em diante". Você projeta primeiro a versão de celular e vai "abrindo" o layout conforme a tela cresce.

Por trás dos panos, é uma media query CSS comum:

/* o que o Bootstrap gera, simplificado */
.col-md-6 { /* nada até 767px */ }
@media (min-width: 768px) {
  .col-md-6 { width: 50%; }
}
💼 Visão de mercado
Mais da metade do tráfego web no Brasil vem do celular. "Você desenvolve mobile first?" é pergunta padrão de entrevista. A resposta esperada: "Sim — escrevo o estilo base para telas pequenas e uso media queries de min-width (ou os sufixos do Bootstrap) para ajustar telas maiores."

✍️ Exercícios do módulo 3

  1. Crie uma página com um .container e um .container-fluid, cada um com um fundo colorido (bg-primary, bg-success). Redimensione a janela e observe o comportamento.
  2. Sem olhar a tabela, escreva de memória os 6 breakpoints e suas larguras mínimas.
  3. Explique com suas palavras o que significa d-none d-lg-block (dica: módulo 5 aprofunda, mas você já consegue deduzir).
Ver solução

3. d-none esconde o elemento a partir de 0px (celular). d-lg-block sobrescreve a partir de 992px, exibindo-o como bloco. Resultado: o elemento só aparece em telas de notebook para cima — exatamente o que o menu lateral desta apostila faz.

Módulo 04 · Fundamentos

Sistema de grid: as 12 colunas que constroem tudo

O grid é o coração do Bootstrap. A regra de ouro tem três camadas, sempre nesta ordem:

  1. .container (ou fluid) — a moldura;
  2. .row — a linha, que é um flex container;
  3. .col-* — as colunas, que somam 12 por linha.

O básico: dividindo em colunas

col-4
col-4
col-4
col-8
col-4
col
col
col (divisão automática)

Repare na terceira linha: .col sem número divide o espaço igualmente — o Bootstrap usa Flexbox (flex: 1 0 0) para isso.

Grid responsivo: combinando breakpoints

O padrão profissional mais comum do mundo: 1 coluna no celular, 2 no tablet, 3 no desktop. Redimensione a janela do navegador para ver acontecer:

Card 1
Card 2
Card 3

Gutters: o espaçamento entre colunas

As classes g-0 a g-5 controlam o vão (gutter) entre colunas. gx-* só horizontal, gy-* só vertical. Em layouts de cards, quase sempre você usará g-3 ou g-4:

<div class="row g-4">          <!-- vão de 1.5rem nos dois eixos -->
<div class="row gx-5 gy-2">    <!-- 3rem horizontal, 0.5rem vertical -->
<div class="row g-0">          <!-- colunas coladas, sem vão -->

Offset: empurrando colunas

col-4 offset-4 (centralizada)
col-3
col-3 offset-6

Ordem: reordenando sem tocar no HTML

As classes order-* (0 a 5, order-first, order-last) mudam a ordem visual. Uso clássico: no celular a imagem vem antes do texto, no desktop vem depois:

🖼️ Imagem
(order-md-2: vai para a direita no desktop)
Texto do produto

No celular, este texto aparece depois da imagem (ordem natural do HTML). A partir de md, o order-md-1 o traz para a esquerda.

Alinhamento dentro da row

Como a .row é um flex container, valem os utilitários de Flexbox:

  • Vertical: align-items-start | center | end na row; align-self-* na coluna.
  • Horizontal: justify-content-start | center | end | between | around | evenly.
start
center
end

Grid aninhado (nesting)

Dentro de uma coluna, você pode abrir outra .row com novas 12 colunas:

<div class="row">
  <div class="col-8">
    Conteúdo principal
    <div class="row">          <!-- novo grid de 12 dentro da col-8 -->
      <div class="col-6">metade da col-8</div>
      <div class="col-6">metade da col-8</div>
    </div>
  </div>
  <div class="col-4">Barra lateral</div>
</div>

Row-cols: definindo colunas na linha

Em vez de repetir a classe em cada coluna, defina na row quantos itens cabem por linha — perfeito para listas de produtos vindas de um loop do back-end:

<!-- 1 por linha no celular, 2 no tablet, 4 no desktop -->
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-4 g-4">
  <div class="col"><div class="card">Produto</div></div>
  <div class="col"><div class="card">Produto</div></div>
  <!-- ...gerados pelo loop... -->
</div>
⚠️ Erros que derrubam candidatos em teste técnico
  • Colocar .col-* direto dentro de .container sem .row — quebra as margens negativas do grid.
  • Somar mais de 12 colunas achando que dá erro — não dá: a coluna excedente quebra para a linha de baixo (às vezes é até desejado).
  • Usar grid para tudo. Para alinhar 2 ou 3 itens (ícone + texto), d-flex com gap-* é mais simples (módulo 5).

✍️ Exercícios do módulo 4

  1. Layout clássico de blog: crie uma linha com conteúdo principal (col-lg-8) e sidebar (col-lg-4), que empilham no celular.
  2. Vitrine: monte 8 caixas que fiquem 1 por linha no celular, 2 no sm, 4 no lg, usando apenas row-cols-*.
  3. Hero invertido: texto à esquerda e imagem à direita no desktop; no celular, a imagem deve aparecer primeiro. Use order-*.
Ver solução
<!-- 1) Blog -->
<div class="container">
  <div class="row g-4">
    <main class="col-12 col-lg-8">Conteúdo</main>
    <aside class="col-12 col-lg-4">Sidebar</aside>
  </div>
</div>

<!-- 2) Vitrine -->
<div class="row row-cols-1 row-cols-sm-2 row-cols-lg-4 g-3">
  <div class="col"><div class="border p-3">1</div></div>
  <!-- ...repita 8x... -->
</div>

<!-- 3) Hero invertido -->
<div class="row align-items-center">
  <div class="col-md-6 order-2 order-md-1"><h1>Texto</h1></div>
  <div class="col-md-6 order-1 order-md-2"><img src="..." class="img-fluid"></div>
</div>
Módulo 05 · Construindo interfaces

Classes utilitárias: 80% do seu dia a dia

Utilitários são classes minúsculas que fazem uma coisa cada: uma margem, uma cor, um display. Na prática profissional, você passa mais tempo com utilitários do que com componentes. Dominar a nomenclatura permite "adivinhar" classes que você nunca viu.

Espaçamento: a fórmula {propriedade}{lado}-{breakpoint}-{tamanho}

ParteValoresSignificado
propriedadem / pmargin / padding
ladot b s e x y ou nadatop, bottom, start (esq.), end (dir.), eixo x, eixo y, todos
tamanho0 1 2 3 4 5 auto0, .25rem, .5rem, 1rem, 1.5rem, 3rem, automático
<div class="mt-4">        margem superior de 1.5rem
<div class="px-3">        padding horizontal de 1rem
<div class="mb-md-5">     margem inferior de 3rem só a partir do tablet
<div class="mx-auto" style="width:200px">  centraliza bloco com largura definida
⚠️ Por que "s" e "e" em vez de "l" e "r"?
Desde a v5, o Bootstrap usa start/end (propriedades lógicas) em vez de left/right, para suportar idiomas escritos da direita para a esquerda (RTL), como árabe. Em português, ms-* = margem esquerda, me-* = margem direita.

Cores: texto, fundo e as variações "subtle"

O Bootstrap tem 8 cores de tema, cada uma com um papel semântico. Isso importa: em sistemas, danger é excluir, success é confirmar.

primary secondary success danger warning info light dark

.text-primary — texto colorido

.text-muted (ou .text-body-secondary) — texto apagado, ótimo para legendas

.bg-warning
.bg-danger-subtle + .text-danger-emphasis (5.3) — o par perfeito para avisos suaves
💼 Visão de mercado
Prefira text-bg-primary (define fundo e a cor de texto com contraste correto) em vez de bg-primary text-white. E as variações -subtle/-emphasis se adaptam sozinhas ao dark mode — detalhe que impressiona em code review.

Display: mostrando e escondendo por tela

d-none          esconde
d-block / d-inline / d-inline-block / d-flex / d-grid
d-none d-md-block      ← esconde no celular, mostra do tablet pra cima
d-lg-none              ← mostra até o notebook, esconde depois
d-print-none           ← some na impressão (útil para botões)

Flexbox: o canivete suíço

Provavelmente o grupo de utilitários mais valioso. Padrões que você usará todo dia:

Ícone + texto alinhados, com espaço entre eles (gap):

🔔
Notificação
d-flex align-items-center gap-2

Título à esquerda, botão à direita (padrão de header de card):

Pedidos recentes

Centralização total (o famoso "centralizar div"):

centralizado com d-flex justify-content-center align-items-center
<!-- direção e quebra -->
flex-row  flex-column  flex-md-row      ← coluna no celular, linha no desktop
flex-wrap  flex-nowrap
<!-- crescimento -->
flex-grow-1  flex-shrink-0
<!-- espaço automático: empurra o item para a direita -->
ms-auto

Dimensão, borda, sombra e cantos

border
border-primary border-3
shadow-sm
shadow
shadow-lg
rounded-3
rounded-pill

w-50 (50% do pai)
w-100

Também existem h-25/50/75/100, vw-100, vh-100 (altura da janela — clássico em heros de tela cheia) e min-vh-100.

Posição

position-relative / absolute / fixed / sticky
top-0 top-50 top-100 · start-0 · end-0 · bottom-0
translate-middle        ← combina com top-50 start-50 para centralizar absoluto
← o badge de notificação: position-absolute + translate-middle

✍️ Exercícios do módulo 5

  1. Recrie um "item de lista de contatos": avatar redondo (use um div com rounded-circle), nome em negrito, última mensagem em text-muted, e o horário empurrado para a direita com ms-auto. Tudo com d-flex.
  2. Crie um botão "Carrinho 🛒" com um badge de contagem sobreposto no canto, como no exemplo acima.
  3. Sem testar no navegador, escreva o que faz: mt-3 mt-lg-0 px-4 d-none d-md-flex justify-content-end. Depois teste e confira.
Ver solução
<!-- 1) Item de contato -->
<div class="d-flex align-items-center gap-3 p-2 border-bottom">
  <div class="rounded-circle bg-secondary" style="width:48px;height:48px;"></div>
  <div>
    <div class="fw-bold">Ana Souza</div>
    <small class="text-muted">Combinado! Te mando amanhã.</small>
  </div>
  <small class="text-muted ms-auto">14:32</small>
</div>

3. Margem superior de 1rem só no mobile (zera no lg), padding horizontal de 1.5rem, escondido no celular, vira flex a partir do tablet com conteúdo alinhado à direita.

Módulo 06 · Construindo interfaces

Tipografia, imagens e tabelas

Títulos e classes de texto

.display-5 — título de impacto

.h3 — aparência de h3 em qualquer tag

.lead — parágrafo de destaque, usado em heros e introduções.

.text-muted + small — legendas e observações

fw-bold · fw-semibold · fw-light · fst-italic

text-uppercase

text-center (há também text-md-start, text-end...)

Outros utilitários úteis: fs-1 a fs-6 (tamanho de fonte), lh-1 / lh-sm / lh-base / lh-lg (altura de linha), text-truncate (corta com reticências — exige largura definida) e text-break (quebra palavras longas, salva layouts com URLs gigantes).

Imagens responsivas

<img src="foto.jpg" class="img-fluid" alt="Descrição da foto">
<!-- img-fluid = max-width:100%; height:auto → nunca estoura o container -->

<img src="perfil.jpg" class="rounded-circle" width="64" height="64" alt="Avatar">
<img src="print.png" class="img-thumbnail" alt="Miniatura com borda">

Para cortar imagens sem distorcer (cards de produto com fotos de tamanhos diferentes), combine altura fixa com object-fit:

<img src="produto.jpg" class="w-100 object-fit-cover" style="height:200px" alt="...">

Proporção fixa: vídeos que não quebram

O helper .ratio mantém a proporção de iframes (YouTube, mapas) em qualquer tela:

<div class="ratio ratio-16x9">
  <iframe src="https://www.youtube.com/embed/CODIGO" title="Vídeo" allowfullscreen></iframe>
</div>
<!-- também: ratio-1x1, ratio-4x3, ratio-21x9 -->

Tabelas

#ClientePlanoStatus
1Mariana LopesProAtivo
2Carlos AndradeBásicoPendente
3Loja ZenithProInadimplente

Classes principais: table (obrigatória), table-striped (zebrada), table-hover (destaque ao passar o mouse), table-bordered / table-borderless, table-sm (compacta), cores contextuais por linha ou célula (table-danger etc.) e o essencial table-dark para cabeçalhos.

⚠️ Nunca esqueça o .table-responsive
Tabela é o componente que mais quebra no celular. Envolva sempre em <div class="table-responsive">, que cria rolagem horizontal quando falta espaço. Em dashboards reais, é a diferença entre "funciona no celular" e chamado de suporte.

✍️ Exercícios do módulo 6

  1. Monte uma tabela de "produtos em estoque" com cabeçalho escuro, zebra, hover, e uma linha table-warning para produto com estoque baixo. Envolva em table-responsive.
  2. Crie um cabeçalho de artigo: título com display-4, subtítulo com lead text-muted e uma imagem img-fluid rounded shadow abaixo.
  3. Incorpore um vídeo do YouTube que se mantenha 16x9 em qualquer largura.
Módulo 07 · Construindo interfaces

Componentes essenciais

Botões

btn-link
💼 Boas práticas cobradas em code review
Use <button type="button"> para ações e <a class="btn"> apenas para navegação. Botão dentro de <form> sem type faz submit sem querer — bug clássico de júnior.

Badges e alerts

Pedidos 4
Entregue Em trânsito

O alert com alert-dismissible fade show + botão com data-bs-dismiss="alert" pode ser fechado pelo usuário — sem escrever nenhum JavaScript. Esse padrão data-bs-* se repete em quase todos os componentes interativos (módulo 10).

Cards: o componente mais usado do Bootstrap

imagem (card-img-top)
Curso de Bootstrap 5
Front-end · 40h

Estrutura clássica: card > card-body > title, subtitle, text e ações.

Matricular
card-header colorido
Card de mesma altura

O segredo dos cards alinhados: h-100 no card e, para o botão descer para o rodapé, d-flex flex-column no body + mt-auto no botão.

Botão sempre embaixo
⚠️ O truque do h-100
"Como deixar todos os cards com a mesma altura?" é uma das dúvidas mais comuns do mundo Bootstrap (e pergunta de entrevista). Resposta: a .row já estica as colunas (Flexbox align-items: stretch); falta só o card acompanhar com h-100.

List group

Feedback de carregamento: spinners e progress

Carregando…
Carregando…
65%

✍️ Exercícios do módulo 7

  1. Vitrine de planos: 3 cards de preço lado a lado (empilhados no celular), mesma altura, com o plano do meio destacado com border-primary e um badge "Mais popular". Botões alinhados no rodapé com mt-auto.
  2. Central de avisos: um alert de cada tipo (success, warning, danger, info), todos fecháveis.
  3. Botão de envio com estado: um botão normal e, ao lado, sua versão "carregando" (disabled + spinner pequeno), simulando o antes/depois de um clique.
Ver solução (exercício 1, estrutura)
<div class="row row-cols-1 row-cols-md-3 g-4">
  <div class="col">
    <div class="card h-100 text-center">
      <div class="card-body d-flex flex-column">
        <h5 class="card-title">Básico</h5>
        <p class="display-6">R$ 29<small class="fs-6">/mês</small></p>
        <ul class="list-unstyled"><li>1 usuário</li></ul>
        <button class="btn btn-outline-primary mt-auto">Assinar</button>
      </div>
    </div>
  </div>
  <div class="col">
    <div class="card h-100 text-center border-primary border-2 shadow">
      <div class="card-header text-bg-primary">Mais popular</div>
      <div class="card-body d-flex flex-column">
        <h5 class="card-title">Pro</h5>
        <p class="display-6">R$ 59<small class="fs-6">/mês</small></p>
        <button class="btn btn-primary mt-auto">Assinar</button>
      </div>
    </div>
  </div>
  <!-- terceiro card análogo -->
</div>
Módulo 08 · Construindo interfaces

Navegação: navbar, tabs, breadcrumb e paginação

Navbar responsiva — anatomia completa

A navbar é o componente com mais "peças". Entenda cada uma e você nunca mais copiará navbar da documentação sem saber o que está fazendo:

↑ Estreite a janela para menos de 992px e o menu vira o botão "hambúrguer".

Peças-chave:

  • navbar-expand-lg — define em qual breakpoint o menu deixa de ser hambúrguer e expande. Troque lg por md ou sm conforme o design.
  • navbar-toggler + data-bs-toggle="collapse" + data-bs-target="#id" — o botão hambúrguer que abre o bloco .collapse.navbar-collapse com aquele id. O id precisa bater! (erro nº 1 de navbar "que não abre").
  • me-auto na ul — empurra o que vem depois (a busca) para a direita.
  • data-bs-theme="dark" — na v5.3, deixa a navbar escura (substitui o antigo navbar-dark).
  • Para fixar no topo: fixed-top (lembre de dar padding-top no body) ou sticky-top.

Tabs e pills (com troca de conteúdo)

Conteúdo da aba Descrição. Cada aba aponta para um .tab-pane via data-bs-target.
Conteúdo de Especificações — padrão clássico de página de produto.
⭐⭐⭐⭐⭐ Conteúdo de Avaliações.

Troque nav-tabs por nav-pills para o visual de "pílulas". Só o pane com show active aparece inicialmente.

Breadcrumb e paginação

✍️ Exercícios do módulo 8

  1. Monte uma navbar clara (bg-light) com logo, 4 links, um dropdown "Minha conta" (Perfil, Configurações, divisor, Sair) e um botão "Entrar" à direita. Ela deve virar hambúrguer abaixo de md.
  2. Crie uma seção de FAQ com nav-pills verticais à esquerda (flex-column) trocando o conteúdo à direita — grid col-md-3 / col-md-9.
  3. Quebre de propósito: mude o data-bs-target do toggler para um id errado e descreva o sintoma. Saber diagnosticar isso economiza horas no trabalho.
Ver solução (comentários)

3. Sintoma: o botão hambúrguer aparece, mas clicar não faz nada (ou abre o bloco errado). Diagnóstico profissional: abrir o DevTools, conferir se o data-bs-target corresponde exatamente ao id do .navbar-collapse, e se o bundle JS foi carregado (aba Network/Console).

Módulo 09 · Construindo interfaces

Formulários e validação

Formulário é onde sistemas reais vivem: login, cadastro, checkout, filtros. É também onde empresas mais avaliam capricho — rótulos, estados de erro e acessibilidade.

Controles básicos

Nunca compartilharemos seu e-mail.

Regras de ouro: form-control em inputs e textareas, form-select em selects (não form-control!), form-check-input em checkboxes/radios, e todo campo com <label for> ligado ao id — acessibilidade básica que recrutadores técnicos verificam.

Input groups e floating labels

R$ ,00

Validação: o jeito Bootstrap

O Bootstrap estiliza os estados is-valid / is-invalid e mostra as mensagens valid-feedback / invalid-feedback. O fluxo profissional usa a validação nativa do HTML5 + a classe was-validated:

Informe seu nome.
Perfeito!
Informe um e-mail válido.
← envie vazio para ver os erros
<form class="needs-validation" novalidate>
  <input type="email" class="form-control" required>
  <div class="invalid-feedback">Informe um e-mail válido.</div>
  ...
</form>
// JS padrão da documentação — memorize a lógica, não o código
document.querySelectorAll('.needs-validation').forEach(form => {
  form.addEventListener('submit', event => {
    if (!form.checkValidity()) {      // API nativa do navegador
      event.preventDefault();          // impede o envio
      event.stopPropagation();
    }
    form.classList.add('was-validated'); // liga os estilos de erro/sucesso
  });
});
⚠️ novalidate não desliga a validação
Ele desliga apenas os balões nativos do navegador, para que as mensagens estilizadas do Bootstrap assumam. A validação continua sendo feita por checkValidity(). E lembre-se da regra de ouro de mercado: validação de front-end é conveniência; a validação que protege o sistema é sempre a do back-end. Diga isso em entrevista e ganhe pontos.

✍️ Exercícios do módulo 9

  1. Tela de login: card centralizado (min-vh-100 + flex center), floating labels para e-mail e senha, switch "manter conectado", botão de largura total.
  2. Checkout: formulário em grid — nome (6), sobrenome (6), CPF (4), telefone (4), CEP (4) com botão "Buscar" em input-group, endereço (8), número (4).
  3. Adicione validação Bootstrap completa ao formulário de login, com mensagens de erro em português.
Ver solução (exercício 1)
<div class="min-vh-100 d-flex align-items-center justify-content-center bg-light">
  <div class="card shadow p-4" style="max-width:400px; width:100%;">
    <h4 class="text-center mb-4">Entrar</h4>
    <form class="needs-validation" novalidate>
      <div class="form-floating mb-3">
        <input type="email" class="form-control" id="email" placeholder="a@a.com" required>
        <label for="email">E-mail</label>
        <div class="invalid-feedback">Informe um e-mail válido.</div>
      </div>
      <div class="form-floating mb-3">
        <input type="password" class="form-control" id="senha" placeholder="senha" required minlength="6">
        <label for="senha">Senha</label>
        <div class="invalid-feedback">Mínimo de 6 caracteres.</div>
      </div>
      <div class="form-check form-switch mb-3">
        <input class="form-check-input" type="checkbox" role="switch" id="lembrar">
        <label class="form-check-label" for="lembrar">Manter conectado</label>
      </div>
      <div class="d-grid"><button class="btn btn-primary">Entrar</button></div>
    </form>
  </div>
</div>
Módulo 10 · Construindo interfaces

Componentes interativos (JavaScript)

Todos seguem o mesmo padrão mental: um gatilho com data-bs-toggle="tipo" apontando (via data-bs-target ou href) para um alvo com id. Entendeu um, entendeu todos.

Modal

Variações que caem em prova prática: modal-dialog-centered (vertical), modal-lg / modal-xl / modal-sm, modal-dialog-scrollable e data-bs-backdrop="static" (não fecha clicando fora — bom para formulários).

Accordion (collapse)

Um grupo de painéis colapsáveis. O data-bs-parent faz um fechar quando outro abre.

FAQs, filtros de e-commerce, menus de sistemas. Um dos componentes mais pedidos em testes práticos.

Carousel

Toast, Offcanvas, Tooltip e Popover

🛒 Carrinho
O offcanvas é o painel deslizante usado em carrinhos de e-commerce, filtros e menus mobile. Direções: offcanvas-start / end / top / bottom.
⚠️ Tooltip e popover NÃO funcionam sozinhos
Por desempenho, são os únicos componentes que exigem inicialização explícita:
document.querySelectorAll('[data-bs-toggle="tooltip"]')
  .forEach(el => new bootstrap.Tooltip(el));
document.querySelectorAll('[data-bs-toggle="popover"]')
  .forEach(el => new bootstrap.Popover(el));

✍️ Exercícios do módulo 10

  1. CRUD visual: uma tabela de usuários com botão "Excluir" em cada linha abrindo um modal de confirmação centralizado com backdrop estático.
  2. FAQ completo: accordion com 5 perguntas, apenas uma aberta por vez, primeira aberta por padrão.
  3. Carrinho lateral: botão "🛒 Carrinho (2)" na navbar abrindo um offcanvas pela direita com dois itens (list-group) e total.
  4. Feedback de ação: um botão "Salvar" que dispara um toast de sucesso (você vai precisar de 3 linhas de JS — espie o módulo 12 se travar).
Módulo 11 · Nível profissional

Customização: Sass, variáveis CSS e dark mode

É aqui que o "site com cara de Bootstrap" vira o site da sua empresa. Existem três níveis de customização, do mais simples ao mais poderoso:

Nível 1 — Sobrescrever com seu próprio CSS

Funciona para ajustes pontuais. Seu arquivo vem depois do Bootstrap:

/* estilos.css — carregado após bootstrap.min.css */
.btn-primary {
  --bs-btn-bg: #e91e63;          /* melhor: mexer nas variáveis CSS do componente */
  --bs-btn-border-color: #e91e63;
  --bs-btn-hover-bg: #c2185b;
}

Desde a v5.2, cada componente expõe variáveis CSS (--bs-btn-bg, --bs-card-border-radius…). Sobrescrevê-las é mais limpo do que brigar com especificidade.

Nível 2 — Variáveis CSS globais

:root {
  --bs-body-font-family: 'Inter', system-ui, sans-serif;
  --bs-body-bg: #fafafa;
  --bs-border-radius: .75rem;
}

Rápido e sem build — mas não recompila tudo que depende das cores (hovers, subtle, gradientes).

Nível 3 — Sass: o jeito profissional

Com npm + Sass você redefine as variáveis antes de importar o Bootstrap, e ele recalcula todo o framework a partir delas — hovers, variações subtle, contrastes:

// styles.scss

// 1) Sobrescreva variáveis ANTES do import (todas têm !default no fonte)
$primary:        #e91e63;                 // sua cor de marca
$secondary:      #495057;
$font-family-sans-serif: 'Inter', system-ui, sans-serif;
$border-radius:  .75rem;
$enable-shadows: true;                    // "feature flags" do framework

// 2) Adicione cores novas ao theme map (vira btn-marca, bg-marca, text-marca...)
$custom-colors: (
  "marca": #6f42c1,
  "whatsapp": #25d366
);

// 3) Importe as partes necessárias
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";

$theme-colors: map-merge($theme-colors, $custom-colors);

@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/card";
// ...importe SÓ o que o projeto usa = CSS final muito menor
@import "bootstrap/scss/helpers";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/utilities/api";   // gera as classes utilitárias
# compilar
npx sass styles.scss dist/styles.css --style=compressed

A API de utilitários: criando suas próprias classes

Recurso muito avançado e valorizado: o mapa $utilities gera as classes utilitárias. Você pode estender:

@import "bootstrap/scss/utilities";

// cria .cursor-pointer, .cursor-grab + versões responsivas (.cursor-md-pointer)
$utilities: map-merge($utilities, (
  "cursor": (
    property: cursor,
    class: cursor,
    responsive: true,
    values: auto pointer grab
  )
));

@import "bootstrap/scss/utilities/api";

Dark mode (v5.3): nativo e simples

O tema é controlado pelo atributo data-bs-theme — no <html> para a página toda, ou em qualquer elemento para "ilhas" de tema:

<html data-bs-theme="dark">   <!-- página inteira escura -->

<div class="card" data-bs-theme="dark">só este card é escuro</div>
Tema claro

Card normal, herdando o tema da página.

Tema escuro

Mesmo HTML, só com data-bs-theme="dark" no pai.

Botão de alternância (o famoso "toggle de dark mode" de portfólio):

const html = document.documentElement;
document.querySelector('#btnTema').addEventListener('click', () => {
  const novo = html.getAttribute('data-bs-theme') === 'dark' ? 'light' : 'dark';
  html.setAttribute('data-bs-theme', novo);
});
💼 Visão de mercado
Em teste técnico, customização via Sass com $primary da marca + import parcial demonstra senioridade. Cite também que cores em Sass são recalculadas com funções de contraste (color-contrast()) — o Bootstrap decide sozinho se o texto do botão fica preto ou branco.

✍️ Exercícios do módulo 11

  1. Sem build: usando só variáveis CSS, mude a cor primária dos botões e o raio de borda global de uma página.
  2. Com npm + Sass: crie um tema com $primary: #ff6b35, fonte Poppins e uma cor extra "whatsapp" no theme map. Gere um botão btn-whatsapp.
  3. Implemente o botão de dark mode com o JS acima e salve a preferência (pesquise prefers-color-scheme para respeitar o sistema do usuário).
Módulo 12 · Nível profissional

JavaScript avançado: controlando componentes por código

Os atributos data-bs-* resolvem 80% dos casos. Os outros 20% — abrir um modal após uma resposta do servidor, disparar um toast ao salvar, fechar um offcanvas programaticamente — exigem a API JavaScript do Bootstrap.

Criando e controlando instâncias

// cada componente é uma classe no objeto global `bootstrap`
const meuModal = new bootstrap.Modal('#modalPedido', {
  backdrop: 'static',   // opções: as mesmas dos data-attributes
  keyboard: false
});

meuModal.show();
meuModal.hide();

// pegar uma instância já criada (por data-attributes, por exemplo)
const t = bootstrap.Toast.getOrCreateInstance('#meuToast');
t.show();

O padrão getInstance() / getOrCreateInstance() evita o erro de criar duas instâncias sobre o mesmo elemento (comportamento duplicado, animações "piscando").

Eventos: reagindo ao ciclo de vida

Todos os componentes emitem eventos no formato {ação}.bs.{componente}. Os quatro de modal se repetem em quase todos: show (antes de abrir), shown (depois de abrir), hide, hidden.

const el = document.getElementById('modalPedido');

el.addEventListener('shown.bs.modal', () => {
  el.querySelector('input')?.focus();          // foca o 1º campo ao abrir (UX!)
});

el.addEventListener('hidden.bs.modal', () => {
  el.querySelector('form')?.reset();           // limpa o form ao fechar
});

// cancelar a abertura condicionalmente
el.addEventListener('show.bs.modal', (e) => {
  if (!usuarioLogado) e.preventDefault();
});

Caso real: toast de sucesso após salvar via fetch

async function salvar(dados) {
  const btn = document.querySelector('#btnSalvar');
  btn.disabled = true;
  btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span> Salvando…';

  try {
    const resp = await fetch('/api/clientes', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(dados)
    });
    if (!resp.ok) throw new Error('Falha ao salvar');

    bootstrap.Toast.getOrCreateInstance('#toastOk').show();
    bootstrap.Modal.getInstance('#modalCliente')?.hide();
  } catch (err) {
    bootstrap.Toast.getOrCreateInstance('#toastErro').show();
  } finally {
    btn.disabled = false;
    btn.textContent = 'Salvar';
  }
}

Esse trecho reúne meia dúzia de padrões que aparecem em qualquer sistema: estado de carregamento no botão, feedback com toast, fechamento programático de modal e tratamento de erro. Vale digitar e entender linha a linha.

Bootstrap com frameworks JS (React, Vue, Angular)

⚠️ Ponto importante para entrevistas

O JS do Bootstrap manipula o DOM diretamente — e React/Vue/Angular também querem ser donos do DOM. Misturar os dois causa bugs sutis. As soluções de mercado:

  • React: usar React-Bootstrap ou reactstrap — componentes React que reimplementam o comportamento, usando só o CSS do Bootstrap.
  • Angular: ng-bootstrap.
  • Vue: BootstrapVueNext.
  • Usar só o CSS do Bootstrap (grid + utilitários) é sempre seguro em qualquer framework.

✍️ Exercícios do módulo 12

  1. Crie um modal que, ao abrir, foca automaticamente o primeiro input (shown.bs.modal).
  2. Faça um botão "Salvar" que mostra spinner por 1,5s (use setTimeout simulando o servidor) e depois dispara um toast de sucesso.
  3. Desafio: um carousel controlado por código — dois botões externos chamando .prev() e .next() na instância bootstrap.Carousel.
Módulo 13 · Nível profissional

Performance, acessibilidade e boas práticas

Performance: entregando menos bytes

  • Use sempre os arquivos .min em produção.
  • Import parcial via Sass (módulo 11): projetos que usam só grid + utilitários + botões podem cortar o CSS pela metade ou mais.
  • PurgeCSS: em builds modernos, remove automaticamente classes não usadas no HTML — o CSS do Bootstrap costuma cair de ~230 KB para 20–40 KB.
  • CDN com cache: jsDelivr serve com cache agressivo; usuários que visitaram outros sites com o mesmo arquivo podem já tê-lo.
  • Carregue o JS no fim do body (ou com defer) para não bloquear a renderização.
  • Imagens são quase sempre o gargalo real: use loading="lazy", formatos modernos (WebP/AVIF) e dimensões definidas para evitar layout shift.
💼 Meça como profissional
Aprenda a rodar o Lighthouse (aba do DevTools do Chrome) e cite as métricas Core Web Vitals (LCP, CLS, INP) em entrevistas. "Entreguei a landing com Lighthouse 95+" é uma frase que vende bem no portfólio.

Acessibilidade (a11y): o que o Bootstrap dá e o que é seu dever

O Bootstrap já traz muita coisa: contraste calculado, foco visível, atributos ARIA nos exemplos. Mas o framework não pode adivinhar seu conteúdo. Checklist mínimo profissional:

  • alt descritivo em toda imagem informativa (alt="" nas decorativas);
  • <label> ligado a todo campo de formulário (ou aria-label);
  • Botões só com ícone precisam de texto para leitores de tela: <span class="visually-hidden">Fechar</span>;
  • Não transmitir informação só por cor — acompanhe com texto/ícone;
  • HTML semântico: <nav>, <main>, <header>, hierarquia correta de headings;
  • Testar navegação completa só com Tab e Enter.

A classe visually-hidden é a ferramenta-chave: esconde visualmente, mas leitores de tela leem. Você a viu em vários exemplos desta apostila (spinners, carousel).

Boas práticas de organização

  • Não repita blocos gigantes: se o back-end é PHP/Laravel, use partials/components; se é estático, considere um gerador ou includes.
  • Crie classes de componente próprias para padrões repetidos, em vez de 15 utilitários colados em 40 lugares:
    .card-produto { /* seu padrão */ }
    /* melhor ainda, com Sass, reutilizando os mixins do Bootstrap */
  • Nunca edite o arquivo do Bootstrap. Sobrescreva por fora ou recompile via Sass. Editar o fonte quebra qualquer atualização futura (e sua reputação no time).
  • Versione escolhas no README: versão do Bootstrap, como compilar, onde ficam as variáveis do tema.

✍️ Exercícios do módulo 13

  1. Rode o Lighthouse em um projeto seu e anote as 3 principais recomendações. Corrija pelo menos uma.
  2. Navegue por um formulário seu usando apenas o teclado. Consegue chegar, preencher e enviar tudo? Onde o foco "some"?
  3. Pegue um card que você repetiu 6 vezes e extraia os utilitários repetidos para uma classe própria em seu CSS.
Módulo 14 · Nível profissional

Bootstrap vs Tailwind vs os outros

Você vai ouvir essa comparação em entrevista. A resposta madura não é torcida de futebol: é saber quando cada um brilha.

Bootstrap 5Tailwind CSSBulmaMaterial UI (React)
Filosofia Componentes prontos + utilitários Utility-first: só utilitários, você monta os componentes Componentes prontos, só CSS (sem JS) Componentes React seguindo o Material Design do Google
Curva de aprendizado Suave — resultados no 1º dia Média — exige saber bem CSS Suave Média/alta — exige React
JavaScript incluso Sim (modal, dropdown…) Não (usa-se Alpine.js, Headless UI…) Não Sim (componentes React)
Visual padrão Reconhecível ("cara de Bootstrap") — customizável via Sass Nenhum: cada projeto nasce único Limpo e moderno Cara de app Google
Onde domina no mercado Sistemas corporativos, painéis admin, PHP/.NET/Java, WordPress, legado Startups, produtos SaaS, projetos React/Next.js novos Projetos menores, MVPs Aplicações React corporativas
Tamanho final ~230 KB cheio; 20–60 KB com purge/Sass parcial Muito pequeno (gera só o que usa) ~200 KB Depende do bundle JS

O mesmo botão, três dialetos

<!-- Bootstrap: classe de componente -->
<button class="btn btn-primary btn-lg">Comprar</button>

<!-- Tailwind: utilitários puros -->
<button class="bg-blue-600 hover:bg-blue-700 text-white font-semibold
               text-lg px-6 py-3 rounded-lg">Comprar</button>

<!-- CSS puro: você escreve a classe -->
<button class="botao-comprar">Comprar</button>

Repare: quem domina os utilitários do Bootstrap (módulo 5) já pensa "meio Tailwind". A transição entre os dois é questão de dias, não meses.

Como responder "Bootstrap ou Tailwind?" em entrevista

"Depende do contexto. Para painéis internos, sistemas com back-end tradicional e times com prazos curtos, Bootstrap entrega mais rápido com componentes e JS prontos. Para produtos com design system próprio e stack React/Next, Tailwind dá mais liberdade sem sobrescrever estilos. Eu me sinto confortável nos dois modelos porque a base — box model, Flexbox, responsividade — é a mesma."

✍️ Exercícios do módulo 14

  1. Recrie o card de plano do módulo 7 no Tailwind Play. Anote o que foi mais fácil e mais difícil em cada framework.
  2. Escreva (de verdade, em texto) sua própria resposta para "Bootstrap ou Tailwind?" com um exemplo de projeto para cada.
Módulo 15 · Prática e carreira

Projetos completos para o portfólio

Três projetos em ordem de dificuldade. Cada um cobre um tipo de trabalho que empresas realmente contratam. Monte cada um do zero seguindo o roteiro; o código completo de referência fica escondido para consulta.

🛠️ Projeto 1 — Landing page "TechFix Assistência Técnica"

Nível: iniciante+ · Tempo estimado: 3–5h · Simula: freela para comércio local

Requisitos do "cliente":

  1. Navbar escura fixa no topo, com links âncora para as seções e botão "Orçamento" destacado;
  2. Hero em tela cheia (min-vh-100) com título, subtítulo e dois botões;
  3. Seção "Serviços" com 3 cards de mesma altura (celular: empilhados);
  4. Seção "Depoimentos" com carousel;
  5. Formulário de contato validado (nome, e-mail, telefone, mensagem);
  6. Rodapé com 3 colunas (sobre, links, contato) que empilham no celular.
Ver código completo de referência (projeto 1)
<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>TechFix — Assistência Técnica</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body style="padding-top:56px"><!-- compensa a navbar fixed-top -->

<nav class="navbar navbar-expand-lg fixed-top bg-dark" data-bs-theme="dark">
  <div class="container">
    <a class="navbar-brand fw-bold" href="#">🔧 TechFix</a>
    <button class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#menu">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="menu">
      <ul class="navbar-nav ms-auto align-items-lg-center">
        <li class="nav-item"><a class="nav-link" href="#servicos">Serviços</a></li>
        <li class="nav-item"><a class="nav-link" href="#depoimentos">Depoimentos</a></li>
        <li class="nav-item ms-lg-2"><a class="btn btn-warning" href="#contato">Orçamento</a></li>
      </ul>
    </div>
  </div>
</nav>

<header class="min-vh-100 d-flex align-items-center text-white"
        style="background:linear-gradient(135deg,#0d1b2a,#1b4965)">
  <div class="container text-center">
    <h1 class="display-3 fw-bold">Seu computador novo de novo</h1>
    <p class="lead col-lg-8 mx-auto">Manutenção de notebooks e PCs com diagnóstico
    gratuito e garantia de 90 dias.</p>
    <div class="d-flex gap-3 justify-content-center flex-wrap mt-4">
      <a href="#contato" class="btn btn-warning btn-lg">Pedir orçamento</a>
      <a href="#servicos" class="btn btn-outline-light btn-lg">Ver serviços</a>
    </div>
  </div>
</header>

<section id="servicos" class="py-5">
  <div class="container">
    <h2 class="text-center mb-5">Serviços</h2>
    <div class="row row-cols-1 row-cols-md-3 g-4">
      <div class="col">
        <div class="card h-100 text-center shadow-sm">
          <div class="card-body d-flex flex-column">
            <div class="fs-1">💻</div>
            <h5 class="card-title">Formatação</h5>
            <p class="card-text">Sistema limpo, drivers atualizados e backup dos seus arquivos.</p>
            <a href="#contato" class="btn btn-outline-primary mt-auto">A partir de R$ 120</a>
          </div>
        </div>
      </div>
      <div class="col">
        <div class="card h-100 text-center shadow-sm">
          <div class="card-body d-flex flex-column">
            <div class="fs-1">⚡</div>
            <h5 class="card-title">Upgrade SSD</h5>
            <p class="card-text">Seu notebook até 10x mais rápido com SSD e mais memória.</p>
            <a href="#contato" class="btn btn-outline-primary mt-auto">A partir de R$ 250</a>
          </div>
        </div>
      </div>
      <div class="col">
        <div class="card h-100 text-center shadow-sm">
          <div class="card-body d-flex flex-column">
            <div class="fs-1">🧹</div>
            <h5 class="card-title">Limpeza interna</h5>
            <p class="card-text">Troca de pasta térmica e limpeza contra superaquecimento.</p>
            <a href="#contato" class="btn btn-outline-primary mt-auto">A partir de R$ 90</a>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>

<section id="depoimentos" class="py-5 bg-light">
  <div class="container" style="max-width:720px">
    <h2 class="text-center mb-4">Quem já usou, recomenda</h2>
    <div id="carDepo" class="carousel slide" data-bs-ride="carousel">
      <div class="carousel-inner text-center px-5">
        <div class="carousel-item active">
          <p class="lead">"Notebook voltou voando. Atendimento nota 10!"</p>
          <strong>— Juliana M.</strong>
        </div>
        <div class="carousel-item">
          <p class="lead">"Diagnóstico honesto, preço justo. Virei cliente."</p>
          <strong>— Roberto S.</strong>
        </div>
      </div>
      <button class="carousel-control-prev" data-bs-target="#carDepo" data-bs-slide="prev">
        <span class="carousel-control-prev-icon" style="filter:invert(1)"></span>
      </button>
      <button class="carousel-control-next" data-bs-target="#carDepo" data-bs-slide="next">
        <span class="carousel-control-next-icon" style="filter:invert(1)"></span>
      </button>
    </div>
  </div>
</section>

<section id="contato" class="py-5">
  <div class="container" style="max-width:640px">
    <h2 class="text-center mb-4">Peça seu orçamento</h2>
    <form class="row g-3 needs-validation" novalidate>
      <div class="col-md-6">
        <label class="form-label" for="nome">Nome</label>
        <input class="form-control" id="nome" required>
        <div class="invalid-feedback">Informe seu nome.</div>
      </div>
      <div class="col-md-6">
        <label class="form-label" for="tel">Telefone/WhatsApp</label>
        <input class="form-control" id="tel" type="tel" required>
        <div class="invalid-feedback">Informe um telefone.</div>
      </div>
      <div class="col-12">
        <label class="form-label" for="email">E-mail</label>
        <input class="form-control" id="email" type="email" required>
        <div class="invalid-feedback">Informe um e-mail válido.</div>
      </div>
      <div class="col-12">
        <label class="form-label" for="msg">Descreva o problema</label>
        <textarea class="form-control" id="msg" rows="4" required></textarea>
        <div class="invalid-feedback">Conte o que está acontecendo.</div>
      </div>
      <div class="col-12 d-grid">
        <button class="btn btn-primary btn-lg">Enviar</button>
      </div>
    </form>
  </div>
</section>

<footer class="bg-dark text-light py-5" data-bs-theme="dark">
  <div class="container">
    <div class="row g-4">
      <div class="col-md-4">
        <h5>🔧 TechFix</h5>
        <p class="text-body-secondary">Assistência técnica de confiança desde 2015.</p>
      </div>
      <div class="col-md-4">
        <h6>Links</h6>
        <ul class="list-unstyled">
          <li><a class="link-light link-underline-opacity-0" href="#servicos">Serviços</a></li>
          <li><a class="link-light link-underline-opacity-0" href="#contato">Contato</a></li>
        </ul>
      </div>
      <div class="col-md-4">
        <h6>Contato</h6>
        <p class="text-body-secondary mb-0">📞 (11) 99999-0000<br>📍 Rua Exemplo, 123 — SP</p>
      </div>
    </div>
    <hr>
    <p class="text-center text-body-secondary small mb-0">© 2026 TechFix</p>
  </div>
</footer>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
  document.querySelectorAll('.needs-validation').forEach(form => {
    form.addEventListener('submit', e => {
      if (!form.checkValidity()) { e.preventDefault(); e.stopPropagation(); }
      form.classList.add('was-validated');
    });
  });
</script>
</body>
</html>

📊 Projeto 2 — Painel administrativo "VendaMais"

Nível: intermediário · Tempo estimado: 5–8h · Simula: sistema interno de empresa (o trabalho mais comum de Bootstrap no mercado)

Requisitos:

  1. Layout com sidebar fixa no desktop que vira offcanvas no mobile;
  2. Topbar com busca e dropdown de usuário;
  3. 4 cards de métricas (row-cols-1 row-cols-sm-2 row-cols-xl-4) com número grande, rótulo e badge de variação;
  4. Tabela responsiva de pedidos com badges de status e botões de ação abrindo modal;
  5. Barra de progresso de meta mensal;
  6. Toast de confirmação ao "excluir" um pedido.
Ver esqueleto de referência (projeto 2 — estrutura principal)
<body>
<div class="d-flex">

  <!-- SIDEBAR: visível só no desktop -->
  <aside class="bg-dark text-white p-3 d-none d-lg-block vh-100 position-sticky top-0"
         style="width:250px" data-bs-theme="dark">
    <h5 class="mb-4">📈 VendaMais</h5>
    <ul class="nav nav-pills flex-column gap-1">
      <li><a class="nav-link active" href="#">Dashboard</a></li>
      <li><a class="nav-link text-white" href="#">Pedidos</a></li>
      <li><a class="nav-link text-white" href="#">Clientes</a></li>
      <li><a class="nav-link text-white" href="#">Relatórios</a></li>
    </ul>
  </aside>

  <!-- mesma sidebar, versão offcanvas para mobile -->
  <div class="offcanvas offcanvas-start text-bg-dark" id="menuLateral">
    <div class="offcanvas-header">
      <h5 class="offcanvas-title">📈 VendaMais</h5>
      <button class="btn-close btn-close-white" data-bs-dismiss="offcanvas"></button>
    </div>
    <div class="offcanvas-body"><!-- mesmos links --></div>
  </div>

  <!-- ÁREA PRINCIPAL -->
  <main class="flex-grow-1 bg-light min-vh-100">
    <nav class="navbar bg-white border-bottom px-3">
      <button class="btn btn-outline-secondary d-lg-none"
              data-bs-toggle="offcanvas" data-bs-target="#menuLateral">☰</button>
      <form class="d-none d-md-flex ms-3 flex-grow-1" style="max-width:360px">
        <input class="form-control" type="search" placeholder="Buscar pedido…">
      </form>
      <div class="dropdown ms-auto">
        <button class="btn btn-light dropdown-toggle" data-bs-toggle="dropdown">👤 Ana</button>
        <ul class="dropdown-menu dropdown-menu-end">
          <li><a class="dropdown-item" href="#">Perfil</a></li>
          <li><hr class="dropdown-divider"></li>
          <li><a class="dropdown-item text-danger" href="#">Sair</a></li>
        </ul>
      </div>
    </nav>

    <div class="container-fluid p-4">
      <h4 class="mb-4">Dashboard</h4>

      <!-- MÉTRICAS -->
      <div class="row row-cols-1 row-cols-sm-2 row-cols-xl-4 g-3 mb-4">
        <div class="col"><div class="card shadow-sm"><div class="card-body">
          <div class="text-muted small">Vendas hoje</div>
          <div class="fs-3 fw-bold">R$ 4.280</div>
          <span class="badge text-bg-success">▲ 12%</span>
        </div></div></div>
        <!-- +3 cards: Pedidos, Novos clientes, Ticket médio -->
      </div>

      <!-- META -->
      <div class="card shadow-sm mb-4"><div class="card-body">
        <div class="d-flex justify-content-between">
          <strong>Meta do mês</strong><span>R$ 68 mil / R$ 100 mil</span>
        </div>
        <div class="progress mt-2" style="height:10px">
          <div class="progress-bar bg-success" style="width:68%"></div>
        </div>
      </div></div>

      <!-- TABELA -->
      <div class="card shadow-sm">
        <div class="card-header bg-white d-flex justify-content-between align-items-center">
          <strong>Pedidos recentes</strong>
          <button class="btn btn-sm btn-primary">+ Novo pedido</button>
        </div>
        <div class="table-responsive">
          <table class="table table-hover align-middle mb-0">
            <thead class="table-light">
              <tr><th>#</th><th>Cliente</th><th>Valor</th><th>Status</th><th></th></tr>
            </thead>
            <tbody>
              <tr>
                <td>#1042</td><td>Marina P.</td><td>R$ 350,00</td>
                <td><span class="badge text-bg-success">Pago</span></td>
                <td class="text-end">
                  <button class="btn btn-sm btn-outline-danger"
                          data-bs-toggle="modal" data-bs-target="#modalDel">Excluir</button>
                </td>
              </tr>
              <!-- mais linhas: Pendente (warning), Cancelado (danger)… -->
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </main>
</div>

<!-- modal de exclusão + toast de sucesso: mesmos padrões dos módulos 10 e 12 -->
</body>

📝 Projeto 3 — Cadastro em etapas com tema próprio

Nível: avançado · Tempo estimado: 6–10h · Simula: teste técnico de vaga júnior/pleno

Requisitos:

  1. Formulário de cadastro dividido em 3 etapas (Dados pessoais → Endereço → Confirmação) usando panes de tab sem os botões de tab visíveis — a navegação é por botões "Avançar/Voltar" controlados via bootstrap.Tab (API JS);
  2. Barra de progresso indicando a etapa (33% / 66% / 100%);
  3. Validação Bootstrap por etapa: só avança se os campos da etapa atual forem válidos;
  4. Busca de CEP real na API viacep.com.br preenchendo os campos de endereço (fetch);
  5. Tema customizado via Sass: cor primária própria, fonte do Google Fonts, $border-radius maior;
  6. Dark mode com botão de alternância;
  7. Modal de sucesso ao finalizar + código publicado no GitHub com README.
Ver as partes-chave (projeto 3 — navegação por etapas e CEP)
// ETAPAS: panes escondidos controlados por código
const etapas = ['#etapa1', '#etapa2', '#etapa3'];
let atual = 0;
const barra = document.querySelector('#barraProgresso');

function irPara(i) {
  atual = i;
  bootstrap.Tab.getOrCreateInstance(
    document.querySelector(`[data-bs-target="${etapas[i]}"]`)
  ).show();
  barra.style.width = ((i + 1) / etapas.length * 100) + '%';
}

document.querySelectorAll('.btn-avancar').forEach(btn => {
  btn.addEventListener('click', () => {
    const pane = document.querySelector(etapas[atual]);
    // valida SÓ os campos da etapa atual
    const invalido = [...pane.querySelectorAll('input,select')].some(c => !c.checkValidity());
    pane.classList.add('was-validated');
    if (!invalido) irPara(atual + 1);
  });
});

// CEP: preenchimento automático com a API pública ViaCEP
document.querySelector('#cep').addEventListener('blur', async (e) => {
  const cep = e.target.value.replace(/\D/g, '');
  if (cep.length !== 8) return;
  const resp = await fetch(`https://viacep.com.br/ws/${cep}/json/`);
  const d = await resp.json();
  if (d.erro) return;
  document.querySelector('#rua').value = d.logradouro;
  document.querySelector('#bairro').value = d.bairro;
  document.querySelector('#cidade').value = d.localidade;
  document.querySelector('#uf').value = d.uf;
});

Os panes usam a mesma estrutura de tab-pane fade do módulo 8, mas com a ul.nav escondida (d-none) — os "tabs" existem só para a API controlar. Esse projeto junta tudo: grid, formulários, validação, API JS do Bootstrap, fetch e Sass. Com ele no GitHub (com README e prints), você tem um portfólio que responde sozinho à pergunta "você sabe Bootstrap?".

💼 Como apresentar esses projetos
  • Publique no GitHub Pages, Netlify ou Vercel — link ao vivo vale mais que print.
  • README com: o que é, tecnologias, como rodar, prints (desktop e celular) e o que você aprendeu.
  • No LinkedIn, publique o antes/depois ou um vídeo curto navegando no projeto.
Módulo 16 · Prática e carreira

Desafios finais (sem roteiro)

Agora sem passo a passo — como no trabalho. Receba o "pedido do cliente" e resolva:

Escolha a home de um site conhecido (Nubank, iFood, Airbnb) e reproduza apenas o hero e a seção seguinte usando Bootstrap. Objetivo: treinar o olho para transformar design em grid + utilitários. Compare lado a lado e liste as diferenças.

Um restaurante quer um cardápio para QR Code: navbar com pills de categorias (Lanches, Pizzas, Bebidas) filtrando por tabs, cards de itens com foto/preço, offcanvas de "sacola" e botão flutuante do WhatsApp (position-fixed bottom-0 end-0 m-3). 100% mobile first.

Pegue qualquer template gratuito antigo em Bootstrap 4 e migre para 5: troque ml-*/mr-* por ms-*/me-*, data-toggle por data-bs-toggle, remova o jQuery, form-group por utilitários de margem, badge-* por text-bg-*. Esse exercício simula manutenção de sistema legado — trabalho real de júnior.

Sua "software house" vende o mesmo sistema para 2 clientes. A partir do painel do Projeto 2, gere dois builds Sass com marcas diferentes (cores, fonte, raio de borda) sem duplicar HTML. É exatamente assim que agências reaproveitam produto.
Módulo 17 · Prática e carreira

Mercado de trabalho e entrevistas

Onde o Bootstrap te emprega

  • Software houses e agências: sites institucionais, landing pages, painéis — volume alto, prazos curtos, Bootstrap em peso.
  • Empresas com stack tradicional (PHP/Laravel, C#/.NET, Java/Spring, Python/Django): o front dos sistemas internos costuma ser Bootstrap renderizado pelo servidor.
  • WordPress: muitos temas são construídos sobre Bootstrap; freelas abundam.
  • Freelancer direto: comércio local, profissionais liberais, cardápios, páginas de captura para tráfego pago.
  • Manutenção de legado: migrações BS3→BS5 e correções de responsividade são porta de entrada real.

Palavras para buscar vagas: desenvolvedor front-end júnior, desenvolvedor web, full stack júnior, web designer + filtro "Bootstrap". Combine sempre com HTML, CSS, JavaScript e Git — o Bootstrap nunca é exigido sozinho.

Checklist de empregabilidade

Técnico
  • HTML semântico e CSS (box model, Flexbox) sólidos
  • Grid e utilitários do Bootstrap de cabeça
  • Validação de formulários + API JS básica
  • Customização via Sass (diferencial)
  • Git/GitHub no fluxo diário
  • JavaScript: DOM, eventos, fetch
Portfólio
  • 3+ projetos no ar com link e README caprichado
  • Pelo menos 1 projeto "de sistema" (painel), não só landing
  • Prints mobile + desktop provando responsividade
  • Lighthouse alto citado no README
  • LinkedIn com os projetos publicados

Perguntas de entrevista — com respostas modelo

"É projetar primeiro para telas pequenas e melhorar progressivamente. O Bootstrap implementa com media queries de min-width: classes sem sufixo valem desde 0px e os sufixos sm/md/lg/xl/xxl sobrescrevem a partir de cada breakpoint. Por isso col-12 col-md-6 é largura total no celular e metade do tablet em diante."

"Container → row → colunas que somam 12. A row é um flex container com margens negativas que compensam o padding (gutter) das colunas. Colunas aceitam tamanho por breakpoint, offset, ordem, e podem aninhar novas rows. .col sem número divide o espaço igualmente via flex: 1 0 0."

"As maiores: remoção do jQuery (JS vanilla), data-toggle virou data-bs-toggle, left/right viraram start/end (ml-*ms-*) para suporte RTL, breakpoint xxl novo, Offcanvas como componente, form-group removido em favor de utilitários, ícones em pacote próprio e, na 5.3, dark mode nativo com data-bs-theme."

"Depende da escala. Ajuste pontual: sobrescrever variáveis CSS (--bs-primary, --bs-btn-bg) num CSS carregado depois. Projeto sério: npm + Sass, redefinindo $primary, $font-family-base etc. antes do import — o framework recompila hovers e variações a partir delas — e importando só os módulos usados para reduzir o bundle. Nunca editar o arquivo do Bootstrap diretamente."

"Checklist: (1) o bundle JS foi carregado? (Console/Network); (2) data-bs-target bate com o id do alvo?; (3) é data-bs-toggle ou o antigo data-toggle de BS4?; (4) para tooltip/popover, houve inicialização manual?; (5) há duas versões de Bootstrap conflitando na página? Esse roteiro resolve 95% dos casos."

Use a resposta do módulo 14: contexto decide. Bootstrap para sistemas com back-end tradicional, prazos curtos e componentes prontos; Tailwind para design system próprio em stacks React/Next. Feche dizendo que domina os fundamentos (Flexbox, responsividade) que valem nos dois.

"A row já estica as colunas (Flexbox stretch); basta h-100 no card. Para alinhar os botões no rodapé: d-flex flex-column no card-body e mt-auto no botão."

"Não. A do front (HTML5 + estilos do Bootstrap) melhora a experiência e reduz requisições inválidas, mas é contornável pelo usuário. Toda regra crítica precisa ser revalidada no back-end. Trato a do front como UX, a do back como segurança."

"HTML semântico, labels em todos os campos, alt em imagens, visually-hidden em botões só de ícone, não depender só de cor para transmitir estado e testar a navegação por teclado. O Bootstrap dá a base (contraste, foco, ARIA nos padrões), mas o conteúdo é responsabilidade minha."

Formatos comuns: reproduzir um layout do Figma/print em X horas; montar um CRUD visual (tabela + modal + validação); ou corrigir uma página quebrada no mobile. Avaliam: fidelidade responsiva, organização do código, commits no Git e se você leu os requisitos até o fim. Os projetos 1–3 desta apostila cobrem exatamente esses formatos.

Plano de 30 dias pós-apostila

  1. Dias 1–10: finalize os 3 projetos, publique com README e link ao vivo.
  2. Dias 11–15: desafios do módulo 16 + revisão dos módulos que travou.
  3. Dias 16–20: JavaScript focado (DOM, eventos, fetch) — é o que mais reprova júnior, não o CSS.
  4. Dias 21–25: LinkedIn e GitHub arrumados; publique cada projeto como post; peça feedback em comunidades (Discord/Reddit br-dev).
  5. Dias 26–30: aplique para 5+ vagas/dia; trate cada teste técnico recusado como aula grátis — peça feedback sempre.
💼 Última dica
Bootstrap te dá velocidade; o que te contrata é a combinação: HTML/CSS sólidos + Bootstrap + JavaScript + Git + um portfólio no ar que prove tudo isso. Esta apostila cobriu o pilar Bootstrap de ponta a ponta — os projetos são a ponte para os outros.