🚀 Trilha Web
Roadmap de 2 semanas para aprender HTML, CSS e JavaScript — do zero, com exemplos comentados e exercícios práticos.
📄 Versões para download (Google Drive):
💡 Dica: marque os exercícios conforme concluir — o progresso fica salvo neste navegador. Use F12 (Console) para testar o JavaScript.
Guia completo e explicado para iniciantes absolutos (ADS — 3ª semana)
Como usar este guia: leia a teoria do dia, digite os exemplos (não copie/cole — digitar fixa o aprendizado), faça os exercícios e só então avance. Ritmo sugerido: 1h30–2h por dia. Se um dia ficar pesado, divida em dois — o importante é entender, não correr.
PARTE PARTE 0 — ANTES DE COMEÇAR
0.1 O que são HTML, CSS e JavaScript? (A analogia da casa)
Imagine que você vai construir uma casa:
| Tecnologia | Papel | Analogia |
|---|---|---|
| HTML | Estrutura | Os tijolos, paredes, cômodos e a planta da casa. Define O QUE existe na página (títulos, textos, imagens, botões, formulários). |
| CSS | Visual | A pintura, o piso, a decoração. Define COMO a página se parece (cores, tamanhos, espaçamentos, posições). |
| JavaScript | Comportamento | A elétrica, o encanamento, as portas automáticas. Define O QUE ACONTECE quando o usuário interage (clique, digitação, envio de formulário). |
Resumo: HTML = conteúdo. CSS = aparência. JS = comportamento. Os três juntos formam qualquer site moderno.
0.2 Ferramentas que você vai usar
- Editor de código — VS Code (gratuito): https://code.visualstudio.com
- Instale a extensão Live Server (ícone de extensões na barra lateral → pesquise "Live Server" → Install). Ela recarrega a página automaticamente quando você salva o arquivo.
- Navegador — Chrome ou Edge (você já tem). Use o DevTools (tecla F12): é o "raio-X" da página. Nele você vê o HTML, testa CSS na hora e vê erros de JS no Console.
- Uma pasta de estudos: crie
C:\estudos-web\(ou onde preferir). Um arquivo HTML por dia, com nome claro:dia1.html,dia2.html...
0.3 Como funciona um site?
- Você escreve arquivos no seu computador:
index.html,style.css,script.js. - O navegador lê o HTML de cima para baixo e monta a página na tela.
- O HTML "chama" o CSS e o JS através de tags específicas (você vai aprender agora).
- Um site publicado na internet é só uma pasta de arquivos servida por um computador remoto (servidor). No seu começo, basta abrir o arquivo
.htmlno navegador ou usar o Live Server.
PARTE PARTE 1 — SEMANA 1: HTML & CSS
📅 DIA 1 — Primeiro HTML: estrutura, textos, listas, links e imagens
1.1 A estrutura obrigatória de todo documento HTML
Todo arquivo HTML tem este "esqueleto". Vou explicar linha por linha:
<!DOCTYPE html> <!-- Diz ao navegador: "isto é um documento HTML5" (a versão atual) -->
<html lang="pt-BR"> <!-- A tag raiz. Envolve TUDO. lang="pt-BR" diz que o idioma é português -->
<head> <!-- Cabeça: informações invisíveis sobre a página (metadados) -->
<meta charset="UTF-8"> <!-- Define a codificação de caracteres. Sem isso, acentos (ã, ç) aparecem quebrados! -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Faz o site funcionar bem no celular (obrigatório em sites modernos) -->
<title>Minha Primeira Página</title>
<!-- O texto que aparece na aba do navegador -->
</head>
<body> <!-- Corpo: TUDO que aparece visível na página fica aqui -->
<h1>Olá, mundo!</h1> <!-- Título principal da página -->
<p>Meu primeiro parágrafo.</p>
</body>
</html>Anatomia de uma tag: a maioria das tags vem em par: <tag> (abertura) ... </tag> (fechamento, com a barra). Algumas são "auto-fecháveis", como <img> e <br>.
Atributos: informações extras dentro da tag de abertura: <tag atributo="valor">. Ex.: <a href="https://google.com">.
Comentários: <!-- texto --> — o navegador ignora. Use para se organizar!
1.2 Tags de texto
<h1>Título principal</h1> <!-- IMPORTANTE: só UM h1 por página (usado pelo Google para entender o assunto) -->
<h2>Subtítulo</h2> <!-- h1 > h2 > h3 > h4 > h5 > h6: hierarquia de importância -->
<h3>Seção menor ainda</h3>
<p>Parágrafo normal. Texto corrido vai aqui.</p>
<p>Outro parágrafo. O navegador já coloca espaçamento entre parágrafos sozinho.</p>
<strong>Texto em negrito (ênfase forte)</strong>
<em>Texto em itálico (ênfase)</em>
<mark>Texto marcado (grifado)</mark>
<small>Texto pequeno (notas, avisos legais)</small>
<del>Texto riscado</del> <!-- mostra: <del>Texto riscado</del> -->
<ins>Texto sublinhado</ins>
<br> <!-- Quebra de linha ("break") — use com moderação, prefira <p> -->
<hr> <!-- Linha horizontal divisória -->
<blockquote>Citação longa — aparece recuada.</blockquote>
<code>console.log("código")</code> <!-- Trecho de código em fonte monoespaçada -->Dica de ouro: o navegador ignora espaços e quebras de linha extras no seu código. Se você digitar 10 espaços seguidos, ele mostra 1. Para espaçar, use CSS (aprenderemos amanhã).
1.3 Listas
<!-- Lista não ordenada (com marcadores "bolinha") -->
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
<!-- Lista ordenada (numerada) -->
<ol>
<li>Estudar estrutura</li>
<li>Fazer exercícios</li>
<li>Revisar</li>
</ol>
<!-- Lista de definição (termo + descrição) -->
<dl>
<dt>HTML</dt> <!-- termo -->
<dd>Linguagem de marcação para estruturar páginas.</dd> <!-- descrição -->
</dl>1.4 Links — a alma da web
<a href="https://www.google.com">Ir para o Google</a>
<!-- Abrir em nova aba: atributo target="_blank" (SEMPRE use com rel="noopener" por segurança) -->
<a href="https://www.google.com" target="_blank" rel="noopener">Google em nova aba</a>
<!-- Link para uma página sua (arquivo na mesma pasta) -->
<a href="contato.html">Página de contato</a>
<!-- Link para uma parte da MESMA página (âncora): o destino precisa ter um id -->
<a href="#secao-projetos">Ir para meus projetos</a>
...
<h2 id="secao-projetos">Projetos</h2>
<!-- Link que abre o app de email -->
<a href="mailto:seuemail@gmail.com">Me mande um email</a>1.5 Imagens
<!-- src = fonte (caminho do arquivo ou URL). alt = texto alternativo (acessibilidade + SEO). OBRIGATÓRIO -->
<img src="foto.jpg" alt="Foto do meu gato dormindo">
<!-- Do tamanho certo: width e height em pixels -->
<img src="foto.jpg" alt="Foto do meu gato" width="300" height="200">
<!-- Imagem vinda da internet (URL completa) -->
<img src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" alt="Logo do Google">
<!-- width="300" apenas distorce a exibição; o arquivo continua o mesmo tamanho no disco -->Pegadinha comum: se a imagem não aparecer, o caminho em src está errado (nome com erro de digitação, maiúsculas/minúsculas, ou pasta errada). Verifique!
✅ Exercícios do Dia 1
📅 DIA 2 — Semântica, tabelas e formulários
2.1 Tags semânticas: dar significado às partes da página
Antigamente usava-se <div> (divisão genérica) para tudo. Hoje usamos tags que dizem o que cada parte é — isso ajuda o Google, leitores de tela (acessibilidade) e você mesmo a se achar no código:
<body>
<header> <!-- Cabeçalho da página (logo, menu, título) -->
<nav> <!-- Navegação: o menu de links -->
<a href="#inicio">Início</a>
<a href="#sobre">Sobre</a>
<a href="#contato">Contato</a>
</nav>
</header>
<main> <!-- Conteúdo PRINCIPAL. Deve haver só um por página -->
<section id="sobre"> <!-- Seção: bloco temático da página -->
<h2>Sobre mim</h2>
<p>Texto sobre mim...</p>
</section>
<article> <!-- Artigo: conteúdo independente (post de blog, notícia) -->
<h2>Meu primeiro projeto</h2>
<p>Como eu fiz...</p>
<time datetime="2026-08-09">9 de agosto de 2026</time> <!-- data legível para máquinas -->
</article>
</main>
<aside> <!-- Conteúdo lateral/complementar (barra lateral, propaganda, links relacionados) -->
<p>Publicidade ou links úteis.</p>
</aside>
<footer> <!-- Rodapé: copyright, contatos, links legais -->
<p>© 2026 Meu Site. Todos os direitos reservados.</p>
</footer>
</body><div> vs <span>: são os "contêineres genéricos" (sem significado). <div> é em bloco (ocupa a linha toda); <span> é inline (fica no meio do texto). Use-os quando nenhuma tag semântica servir:
<div class="card">Bloco genérico</div>
<p>Texto com um <span class="destaque">trecho destacado</span> no meio.</p>2.2 Tabelas
<table> <!-- a tabela -->
<caption>Notas dos alunos</caption> <!-- legenda da tabela -->
<thead> <!-- cabeçalho da tabela -->
<tr> <!-- linha (table row) -->
<th>Aluno</th> <!-- célula de cabeçalho (fica em negrito automaticamente) -->
<th>Nota</th>
</tr>
</thead>
<tbody> <!-- corpo da tabela -->
<tr>
<td>Ana</td> <!-- célula de dados -->
<td>9,5</td>
</tr>
<tr>
<td>Bruno</td>
<td>7,0</td>
</tr>
</tbody>
<tfoot> <!-- rodapé da tabela (opcional) -->
<tr>
<td>Média</td>
<td>8,25</td>
</tr>
</tfoot>
</table>
<!-- Mesclar células: colspan (colunas) e rowspan (linhas) -->
<tr>
<td colspan="2">Esta célula ocupa 2 colunas</td>
</tr>Dica: tabelas são para dados (notas, horários, preços). NUNCA use tabela para fazer layout da página — isso é coisa dos anos 2000, use CSS (Flexbox/Grid, dias 4–5).
2.3 Formulários — como a página recebe dados do usuário
<!-- action = para onde os dados vão (no começo, pode ser "#"). method = como (GET/POST) -->
<form action="#" method="post">
<!-- CADA campo precisa de um <label> com "for" apontando para o "id" do input.
Clique no label = foca o campo. Acessibilidade + usabilidade. -->
<label for="nome">Nome completo:</label>
<input type="text" id="nome" name="nome" placeholder="Digite seu nome" required>
<label for="email">Email:</label>
<input type="email" id="email" name="email" placeholder="voce@email.com" required>
<!-- type="email" valida automaticamente se tem @ e . -->
<label for="senha">Senha:</label>
<input type="password" id="senha" name="senha" required>
<!-- type="password" esconde os caracteres digitados -->
<label for="idade">Idade:</label>
<input type="number" id="idade" name="idade" min="0" max="120">
<label for="nascimento">Data de nascimento:</label>
<input type="date" id="nascimento" name="nascimento">
<label for="cor">Cor favorita:</label>
<input type="color" id="cor" name="cor">
<!-- Checkbox: marcações independentes. name igual = grupo -->
<p>Interesses:</p>
<input type="checkbox" id="front" name="interesse" value="frontend">
<label for="front">Front-end</label>
<input type="checkbox" id="back" name="interesse" value="backend">
<label for="back">Back-end</label>
<!-- Radio: escolhe APENAS UMA opção (name igual obrigatório para agrupar) -->
<p>Nível:</p>
<input type="radio" id="iniciante" name="nivel" value="iniciante" checked>
<label for="iniciante">Iniciante</label>
<input type="radio" id="medio" name="nivel" value="medio">
<label for="medio">Intermediário</label>
<!-- Select: lista suspensa -->
<label for="cidade">Cidade:</label>
<select id="cidade" name="cidade">
<option value="">Selecione...</option>
<option value="sp">São Paulo</option>
<option value="rj">Rio de Janeiro</option>
<option value="bh">Belo Horizonte</option>
</select>
<!-- Textarea: texto longo -->
<label for="mensagem">Mensagem:</label>
<textarea id="mensagem" name="mensagem" rows="4" cols="40">Texto inicial</textarea>
<!-- Botões -->
<button type="submit">Enviar</button> <!-- envia o formulário -->
<button type="reset">Limpar</button> <!-- limpa os campos -->
<button type="button">Sem ação</button> <!-- não faz nada (útil com JS) -->
</form>Atributos importantes de inputs:
name→ nome do campo (é assim que os dados são identificados ao enviar)placeholder→ texto cinza de exemplo dentro do camporequired→ o navegador bloqueia o envio se estiver vaziovalue→ valor pré-preenchidochecked→ checkbox/radio já marcadodisabled→ campo desativado (cinza, não editável)readonly→ só leitura
✅ Exercícios do Dia 2
📅 DIA 3 — CSS: conectando, seletores, cores e o famoso Box Model
3.1 As 3 formas de usar CSS
<!-- 1) ARQUIVO EXTERNO (a forma certa — usaremos sempre esta) -->
<!-- No <head> do HTML: -->
<link rel="stylesheet" href="style.css">
<!-- 2) Tag <style> dentro do <head> (ok para testes rápidos) -->
<style>
p { color: red; }
</style>
<!-- 3) Atributo style inline (EVITE — mistura conteúdo e estilo, difícil de manter) -->
<p style="color: red;">Texto vermelho</p>Regra de prioridade (a mais específica vence): inline > id > class > tag. E !important (evite) vence tudo.
3.2 Seletores: como "apontar" para os elementos
/* Seleciona TODAS as tags <p> */
p { color: blue; }
/* Seleciona o elemento com id="titulo" (IDs são ÚNICOS na página) */
#titulo { font-size: 32px; }
/* Seleciona todos os elementos com class="card" (classes podem repetir) */
.card { background-color: lightgray; }
/* Seleciona TODOS os elementos da página */
* { margin: 0; }
/* Seleciona <a> que está DENTRO de <nav> (seletor descendente) */
nav a { text-decoration: none; }
/* Seleciona só o FILHO direto */
main > p { color: green; }
/* Seleciona <input> do tipo email (seletor de atributo) */
input[type="email"] { border: 2px solid blue; }
/* Vários seletores com a mesma regra */
h1, h2, h3 { color: navy; }Nomenclatura de classes: use inglês, minúsculas, com hífen (kebab-case): botao-primario, card-produto, menu-item.
3.3 Cores e texto
p {
color: #ff5733; /* HEX: #RRGGBB (vermelho, verde, azul) — o padrão da web */
color: rgb(255, 87, 51); /* RGB: números de 0 a 255 */
color: rgba(255, 87, 51, 0.5); /* RGBA: o 4º valor (0 a 1) é a TRANSPARÊNCIA (alpha) */
color: tomato; /* Nomes de cores também funcionam (147 nomes) */
background-color: lightyellow; /* fundo do elemento */
opacity: 0.7; /* transparência do elemento INTEIRO (texto também) */
}Pegadinha: color muda a cor do TEXTO. background-color muda o FUNDO. Os dois juntos = texto colorido sobre fundo colorido.
Propriedades de texto:
p {
font-family: Arial, Helvetica, sans-serif; /* lista de fontes: se a 1ª não existir, tenta a próxima */
font-size: 18px; /* tamanho da fonte */
font-weight: bold; /* espessura: normal | bold | 100–900 */
font-style: italic; /* normal | italic */
line-height: 1.6; /* altura da linha (1.5–1.7 = leitura confortável) */
text-align: center; /* left | center | right | justify */
text-decoration: underline; /* none | underline | line-through */
text-transform: uppercase; /* uppercase | lowercase | capitalize */
letter-spacing: 2px; /* espaçamento entre letras */
text-shadow: 2px 2px 4px gray; /* sombra: x y blur cor */
}3.4 ⭐ O BOX MODEL — o conceito mais importante do CSS
Todo elemento HTML é uma caixa com 4 camadas, de dentro para fora:
┌─────────────────────────────────────────────┐
│ MARGIN (espaço EXTERNO — afasta das outras caixas) │
│ ┌───────────────────────────────────────┐ │
│ │ BORDER (a borda visível) │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ PADDING (espaço INTERNO — │ │ │
│ │ │ entre o conteúdo e a borda) │ │ │
│ │ │ ┌───────────────────────────┐ │ │ │
│ │ │ │ CONTENT (o conteúdo: │ │ │ │
│ │ │ │ texto, imagem...) │ │ │ │
│ │ │ └───────────────────────────┘ │ │ │
│ │ └─────────────────────────────────┘ │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────┘.card {
width: 300px; /* largura do CONTEÚDO (por padrão) */
height: 150px;
padding: 20px; /* 20px nos 4 lados. Formas: padding: 10px 20px; (vertical horizontal) / padding-top, padding-right... */
border: 2px solid black; /* espessura estilo cor (solid | dashed | dotted) */
border-radius: 10px; /* cantos arredondados! (50% = círculo) */
margin: 15px; /* espaço externo. margin: 0 auto; centraliza HORIZONTALMENTE a caixa */
}A pegadinha número 1 do CSS (decore isso!): por padrão, width: 300px conta SÓ o conteúdo. Se você adicionar padding: 20px e border: 2px, a caixa visual fica com 344px (300 + 40 + 4). Isso quebra layouts o tempo todo.
A solução universal — box-sizing:
/* Coloque isto no topo do seu CSS (reset básico) e a vida fica mais fácil: */
* {
box-sizing: border-box; /* agora width/height INCLUEM padding e border */
margin: 0; /* remove margens padrão do navegador */
padding: 0;
}3.5 Unidades de medida
| Unidade | O que é | Quando usar |
|---|---|---|
px | Pixel (fixo) | Bordas, ícones, coisas pequenas |
% | Porcentagem do elemento PAI | Larguras de layout (ex.: 50% = metade do pai) |
rem | Relativo à fonte raiz (<html>, padrão 16px → 1rem = 16px) | Tamanhos de fonte (acessibilidade: respeita o zoom do usuário) |
em | Relativo à fonte do elemento atual | Espaçamentos proporcionais |
vh / vw | % da altura/largura da JANELA | Seções de tela cheia (height: 100vh) |
body { font-size: 16px; }
h1 { font-size: 2rem; } /* = 32px */
.container { width: 80%; } /* 80% da largura do pai */
.hero { height: 100vh; } /* altura total da tela */✅ Exercícios do Dia 3
📅 DIA 4 — Flexbox: alinhamento sem sofrimento
4.1 O problema
Antigamente, centralizar um elemento verticalmente era um pesadelo. O Flexbox (2015+) resolveu isso: é um sistema de layout em uma dimensão (linha OU coluna) com regras simples.
4.2 Como funciona
Você transforma um elemento em container flex com display: flex;. Os filhos diretos dele viram "itens flex" e passam a obedecer alinhamento automático:
<div class="container"> <!-- VIRA O CONTAINER -->
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>.container {
display: flex; /* liga o flexbox */
flex-direction: row; /* direção: row (linha, padrão) | column (coluna) | row-reverse | column-reverse */
justify-content: center; /* alinha no EIXO PRINCIPAL (horizontal se row) */
align-items: center; /* alinha no EIXO TRANSVERSAL (vertical se row) */
gap: 20px; /* espaçamento ENTRE os itens (use isso, não margin!) */
}Os valores mais usados de justify-content (eixo principal):
flex-start [1][2][3] (padrão: esquerda)
center ....[1][2][3].... (centro)
flex-end ............[1][2][3] (direita)
space-between [1]......[2]......[3] (primeiro e último nas pontas)
space-around ..[1].....[2].....[3].. (espaço igual ao redor)
space-evenly ...[1]...[2]...[3]... (espaços iguais)align-items (eixo transversal): flex-start (topo) | center (meio) | flex-end (baixo) | stretch (estica, padrão).
Propriedades nos ITENS:
.item {
flex-grow: 1; /* quanto o item "cresce" para ocupar espaço extra (0 = não cresce). 1 em todos = larguras iguais */
flex-shrink: 1; /* quanto encolhe quando falta espaço */
flex-basis: 200px; /* tamanho inicial antes de crescer/encolher */
align-self: center; /* alinhamento individual (sobrescreve align-items) */
order: 2; /* ordem visual (sem mudar o HTML) */
}flex-wrap: por padrão os itens tentam caber numa linha (e espremem). Com flex-wrap: wrap, quando não couberem, quebram para a linha de baixo:
.container {
display: flex;
flex-wrap: wrap; /* agora itens viram grade quando necessário */
}Como centralizar qualquer coisa na tela (o clássico):
.pai {
display: flex;
justify-content: center;
align-items: center;
}4.3 Exemplo completo: navbar (barra de navegação)
<nav class="navbar">
<a href="#" class="logo">MeuSite</a>
<div class="links">
<a href="#">Início</a>
<a href="#">Sobre</a>
<a href="#">Contato</a>
</div>
</nav>.navbar {
display: flex;
justify-content: space-between; /* logo na esquerda, links na direita */
align-items: center;
padding: 15px 30px;
background-color: #222;
}
.navbar a { color: white; text-decoration: none; }
.links { display: flex; gap: 20px; }Regra mental: Flexbox = alinhar itens numa linha/coluna (navbar, cards lado a lado, centralizar). Grid (amanhã) = layout completo da página em 2 dimensões.
✅ Exercícios do Dia 4
📅 DIA 5 — Grid e responsividade (sites que funcionam no celular)
5.1 Grid: layout em 2 dimensões (linhas E colunas ao mesmo tempo)
O Grid cria uma "tabela invisível" onde você posiciona os elementos:
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr; /* 3 colunas de largura igual (1fr = 1 fração do espaço) */
grid-template-columns: repeat(3, 1fr); /* mesmo resultado, mais legível */
grid-template-columns: 200px 1fr; /* coluna fixa de 200px + o resto */
gap: 20px; /* espaço entre colunas E linhas */
}<div class="galeria">
<div class="foto">1</div>
<div class="foto">2</div>
<div class="foto">3</div>
<div class="foto">4</div>
<div class="foto">5</div>
<div class="foto">6</div>
</div>Com 3 colunas e 6 itens: 2 linhas de 3 — automático, sem cálculo nenhum.
Fazer um item ocupar mais espaço:
.foto-grande { grid-column: span 2; } /* ocupa 2 colunas */
.foto-alta { grid-row: span 2; } /* ocupa 2 linhas */Áreas nomeadas (layout clássico de página):
.layout {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-columns: 250px 1fr;
gap: 15px;
}
header { grid-area: header; }
aside { grid-area: sidebar; }
main { grid-area: main; }
footer { grid-area: footer; }Flexbox ou Grid? Flexbox = alinhar uma sequência (navbar, cards). Grid = estrutura geral da página (colunas + linhas juntas). Ambos se combinam: Grid no layout, Flexbox dentro de cada bloco.
5.2 Responsividade: Media Queries
A mesma página precisa ficar boa no monitor de 24" e no celular. A ferramenta: media queries — regras CSS que só valem em certas condições (ex.: telas menores que X px).
/* Estilos padrão (desktop) vêm primeiro — ou mobile-first, como preferir */
@media (max-width: 768px) { /* telas de até 768px de largura (tablet/celular) */
.galeria {
grid-template-columns: repeat(2, 1fr); /* 2 colunas em vez de 3 */
}
.navbar {
flex-direction: column; /* menu empilhado */
gap: 10px;
}
}
@media (max-width: 480px) { /* celulares pequenos */
.galeria {
grid-template-columns: 1fr; /* 1 coluna só */
}
}Teste no DevTools: F12 → ícone de celular/tablet no topo (ou Ctrl+Shift+M) → escolha um tamanho de tela e veja o site se adaptar.
Pegadinhas comuns de responsividade:
- Esqueceu o
<meta name="viewport">no<head>→ o celular mostra o site "encolhido" (é o famoso "zoom de formiga"). SEMPRE tenha essa meta tag. - Imagem estourando a tela →
img { max-width: 100%; }resolve. - Texto minúsculo no celular → use
remem vez depxpara fontes.
✅ Exercícios do Dia 5
📅 DIA 6 — Posicionamento, pseudo-classes e animações suaves
6.1 position: controlar onde a caixa fica
/* static (padrão): flui normalmente com a página. Nada acontece. */
.relative {
position: relative; /* âncora para filhos absolutos + permite top/left/right/bottom para DESLOCAR da posição original */
top: 10px; /* move 10px para baixo do lugar original */
left: 20px;
}
.absolute {
position: absolute; /* sai do fluxo! Posiciona em relação ao ancestral mais próximo com position (senão, à página) */
top: 0; right: 0; /* gruda no canto superior direito do ancestral */
}
.fixed {
position: fixed; /* gruda na JANELA. Não rola com a página — navbar fixa, botão "voltar ao topo" */
top: 0; left: 0;
width: 100%;
}
.sticky {
position: sticky; /* comporta-se como static, mas "gruda" no topo quando você rola até ele */
top: 0;
}Padrão clássico: pai com position: relative + filho com position: absolute → o filho se posiciona em relação ao pai. Ex.: selo "PROMOÇÃO" no canto do card.
z-index: controla quem fica por cima quando elementos se sobrepõem. z-index: 10 fica acima de z-index: 1. Só funciona em elementos posicionados (relative/absolute/fixed/sticky).
6.2 Pseudo-classes: estados dos elementos (:)
a:hover { color: orange; } /* quando o mouse está POR CIMA */
a:active { color: red; } /* no instante do clique */
input:focus { border-color: blue; } /* quando o campo está selecionado/focado */
button:disabled { opacity: 0.5; } /* botão desativado */
li:first-child { font-weight: bold; } /* o primeiro filho */
li:last-child { border-bottom: none; }
li:nth-child(2n) { background: #f5f5f5; } /* linhas pares (efeito zebra) — 2n = pares, 3n = a cada 3 */
p:not(.destaque) { color: gray; } /* tudo que NÃO tem a classe */6.3 Pseudo-elementos (::): criar conteúdo decorativo
.card::before {
content: "★ "; /* insere conteúdo ANTES do elemento (só funciona com content) */
color: gold;
}
.card::after {
content: ""; /* vazio + display block + dimensões = desenho (ex.: linha decorativa) */
display: block;
width: 50px;
height: 3px;
background: orange;
margin-top: 10px;
}6.4 Transitions: animação suave de hover
.botao {
background-color: blue;
color: white;
padding: 12px 24px;
border: none;
border-radius: 6px;
cursor: pointer; /* mãozinha ao passar o mouse (sempre em botões!) */
transition: background-color 0.3s ease, transform 0.3s ease;
/* propriedade duração ritmo */
}
.botao:hover {
background-color: darkblue;
transform: scale(1.05); /* cresce 5% (transform: translate/rotate/scale) */
}Regra: a transition fica no estado NORMAL (não no :hover), para a animação funcionar nos dois sentidos (entrar E sair do hover).
✅ Exercícios do Dia 6
📅 DIA 7 — 🎯 PROJETO DA SEMANA 1: Página de Portfólio Pessoal
Objetivo: uma página única de portfólio — algo que você pode mostrar para colegas, professores e futuros empregadores.
Requisitos (use TUDO da semana):
<!DOCTYPE html>+ metas (charset, viewport) +<title>correto- Estrutura semântica:
header→nav(menu fixo composition: sticky),main,sections,footer - Seção Sobre com foto sua,
<h1>com seu nome e um parágrafo - Seção Projetos: 3 cards em Grid (3 colunas → 1 no celular), cada card com imagem, título, descrição e link
- Seção Contato: formulário (nome, email, mensagem) + links de redes sociais
- CSS externo com: reset (
box-sizing: border-box), paleta de 2–3 cores,:hovernos links/botões,transitionsuave - Responsivo:
@media (max-width: 768px)e@media (max-width: 480px) - Valide no https://validator.w3.org (cole o código, veja se não há erros)
Inspiração de estrutura:
<header>
<nav>...</nav>
</header>
<main>
<section id="sobre">...</section>
<section id="projetos">
<div class="grid-projetos">
<article class="card">...</article>
<article class="card">...</article>
<article class="card">...</article>
</div>
</section>
<section id="contato">
<form>...</form>
</section>
</main>
<footer>...</footer>Desafio extra: publique no GitHub (crie uma conta em github.com, crie repositório, suba os arquivos) — é o seu cartão de visitas profissional.
PARTE PARTE 2 — SEMANA 2: JAVASCRIPT
Mudança de mentalidade: JS é uma linguagem de programação de verdade (a mesma usada no servidor, no Node.js). Você não está mais "marcando texto" — está dando instruções ao computador. O computador faz exatamente o que você manda, na ordem que você manda. Nem mais, nem menos.
📅 DIA 8 — Primeiros passos: variáveis, tipos e operadores
8.1 Como colocar JS na página
<!-- No final do <body> (antes de </body>): o HTML já carregou, e o JS roda em cima dele -->
<script src="script.js"></script>
<!-- Ou direto no HTML (só para testes): -->
<script>
console.log("Olá, mundo!");
</script>O Console do DevTools (F12 → Console) é seu melhor amigo: mostra erros em vermelho e resultados de console.log. Você também pode digitar JS ali e testar na hora.
8.2 Variáveis: caixinhas com nome
let idade = 20; // let: variável que PODE mudar de valor depois
const nome = "Ana"; // const: constante — NÃO pode mudar (use por padrão!)
// var: forma antiga, evite
idade = 21; // ✅ ok, let permite
// nome = "Bruno"; // ❌ erro! const não pode ser reatribuída
// Regras de nome: sem espaços, sem começar com número, sem caracteres especiais (só _ e $)
// Convenção: camelCase — primeira palavra minúscula, próximas com maiúscula: minhaIdade, nomeCompletoRegra prática: use const por padrão. Só use let se você PRECISA reatribuir. Se der erro "Assignment to constant variable", você sabe o motivo.
8.3 Tipos de dados
const texto = "Olá, mundo"; // string (texto) — aspas simples ' ', duplas " " ou crases ` `
const numero = 42; // number — inteiros e decimais (42.5)
const verdadeiro = true; // boolean — true ou false
const nada = null; // null: "vazio de propósito" (você define)
let indefinido; // undefined: existe mas não tem valor (a linguagem define)
// Também: objetos, arrays, funções (próximos dias)
console.log(typeof texto); // "string" — typeof diz o tipo
console.log(typeof numero); // "number"null vs undefined: undefined = "nunca recebeu valor". null = "recebi um valor que significa nada". Detalhe fino, mas cai em entrevista. 😄
8.4 Operadores
// Aritméticos
5 + 3 // 8 (soma)
5 - 3 // 2 (subtração)
5 * 3 // 15 (multiplicação)
5 / 2 // 2.5 (divisão)
5 % 2 // 1 (RESTO da divisão — ótimo para par/ímpar)
2 ** 3 // 8 (potência)
let x = 5; x++; // x vira 6 (incremento). x-- decrementa.
// Atalhos
x += 3; // x = x + 3
x -= 3; // x = x - 3
x *= 2; // x = x * 2
// Comparação — SEMPRE use === e !== (triplo!)
5 == "5" // true (== compara ignorando tipo — EVITE, causa bugs!)
5 === "5" // false (=== compara valor E tipo — USE SEMPRE)
5 !== "5" // true
10 > 5 // true | < menor | >= maior ou igual | <= menor ou igual
// Lógicos
true && false // false (E: os dois precisam ser true)
true || false // true (OU: pelo menos um true)
!true // false (NEGAÇÃO: inverte)8.5 Template literals (crases) — o jeito moderno de montar texto
const nome = "Ana";
const idade = 20;
// Jeito antigo (concatenação com +):
console.log("Meu nome é " + nome + " e tenho " + idade + " anos.");
// Jeito moderno (template literal com crases ` e ${}):
console.log(`Meu nome é ${nome} e tenho ${idade} anos.`);
// Dá para fazer contas dentro:
console.log(`Ano que vem farei ${idade + 1} anos.`);✅ Exercícios do Dia 8
📅 DIA 9 — Condicionais, loops e funções (o coração da lógica)
9.1 Condicionais: o computador decide
const nota = 7.5;
if (nota >= 7) {
console.log("Aprovado! 🎉");
} else if (nota >= 5) {
console.log("Recuperação 😬");
} else {
console.log("Reprovado 💔");
}
// Operador ternário: if/else em uma linha (para casos simples)
const resultado = nota >= 7 ? "Aprovado" : "Reprovado";
// condição valor se true valor se false
// switch: muitas comparações com o MESMO valor
const dia = "segunda";
switch (dia) {
case "sabado":
case "domingo":
console.log("Fim de semana!");
break; // SEMPRE coloque break (senão "cai" no próximo case)
default: // se nenhum case bater
console.log("Dia útil");
}9.2 Loops: repetição sem copiar e colar
// for: quando você sabe QUANTAS vezes
for (let i = 0; i < 5; i++) {
// início condição incremento
console.log(`Volta número ${i + 1}`);
}
// imprime: Volta número 1, 2, 3, 4, 5
// while: quando você não sabe quantas vezes (repete ENQUANTO a condição for true)
let tentativas = 0;
while (tentativas < 3) {
console.log("Tentando...");
tentativas++; // SEMPRE incremente algo, senão = loop infinito (trava o navegador!)
}
// for...of: percorrer itens de um array (veremos arrays amanhã)
const frutas = ["maçã", "banana", "uva"];
for (const fruta of frutas) {
console.log(fruta);
}
// break: para o loop na hora. continue: pula para a próxima volta
for (let i = 1; i <= 10; i++) {
if (i === 5) break; // para no 4
if (i % 2 === 0) continue; // pula pares
console.log(i); // imprime 1, 3
}9.3 Funções: blocos de código reutilizáveis
// Declaração tradicional
function somar(a, b) {
return a + b; // return devolve o resultado para quem chamou
}
console.log(somar(2, 3)); // 5 — passamos 2 e 3 como ARGUMENTOS
// Arrow function (jeito moderno, você verá MUITO por aí)
const multiplicar = (a, b) => a * b; // sem {} = return implícito
console.log(multiplicar(4, 2)); // 8
// Arrow com corpo maior
const saudacao = (nome) => {
const mensagem = `Olá, ${nome}!`;
return mensagem;
};
// Função SEM return devolve undefined
function semRetorno() {
console.log("faz algo");
}
console.log(semRetorno()); // undefined
// Parâmetro padrão
function dividir(a, b = 2) { // se b não for passado, vale 2
return a / b;
}
console.log(dividir(10)); // 5Escopo (resumo): variável criada dentro de {} de função existe só lá dentro. Variável no topo do arquivo (global) existe em todo lugar. Não declare variáveis globais à toa.
✅ Exercícios do Dia 9
📅 DIA 10 — Arrays e objetos: organizando dados
10.1 Arrays: listas
const frutas = ["maçã", "banana", "uva"];
// índice: 0 1 2 ← SEMPRE começa em 0!
console.log(frutas[0]); // "maçã" (acessar pelo índice entre colchetes)
console.log(frutas.length); // 3 (quantidade de itens)
console.log(frutas[frutas.length - 1]); // "uva" (sempre o último item)
frutas.push("laranja"); // adiciona no FIM → ["maçã","banana","uva","laranja"]
frutas.pop(); // remove o ÚLTIMO → ["maçã","banana","uva"]
frutas.unshift("manga"); // adiciona no INÍCIO
frutas.shift(); // remove o PRIMEIRO
frutas.indexOf("banana"); // 1 (posição) | -1 se não existir
frutas.includes("uva"); // true (existe?)
frutas.join(", "); // "maçã, banana, uva" (vira texto)
// Percurso moderno: forEach (para cada item, faça...)
frutas.forEach((fruta) => console.log(fruta));⭐ map e filter — os dois mais importantes (decore!):
// map: transforma CADA item e devolve um NOVO array do mesmo tamanho
const numeros = [1, 2, 3, 4];
const dobrados = numeros.map((n) => n * 2);
console.log(dobrados); // [2, 4, 6, 8] — o original NÃO muda
const precoEmCentavos = [100, 250, 990];
const precoEmReais = precoEmCentavos.map((c) => `R$ ${(c / 100).toFixed(2)}`);
// ["R$ 1.00", "R$ 2.50", "R$ 9.90"]
// filter: devolve um NOVO array só com os itens que passam no teste (true)
const numeros2 = [1, 2, 3, 4, 5, 6];
const pares = numeros2.filter((n) => n % 2 === 0);
console.log(pares); // [2, 4, 6]
// reduce: reduz tudo a UM valor (soma, média...)
const total = numeros2.reduce((acumulador, n) => acumulador + n, 0);
console.log(total); // 2110.2 Objetos: agrupando informações relacionadas
const aluno = {
nome: "Ana",
idade: 20,
curso: "ADS",
aprovada: true,
materias: ["Matemática", "Programação"], // objetos podem ter arrays
endereco: { // e objetos dentro de objetos!
cidade: "São Paulo",
uf: "SP"
},
apresentar() { // métodos = funções dentro do objeto
return `Sou ${this.nome}, do curso de ${this.curso}.`;
// ^^^^ this = o próprio objeto (aqui: aluno)
}
};
console.log(aluno.nome); // "Ana" (acesso com ponto)
console.log(aluno["nome"]); // "Ana" (acesso com colchetes — útil p/ nomes dinâmicos)
console.log(aluno.endereco.cidade); // "São Paulo" (caminho)
console.log(aluno.apresentar()); // "Sou Ana, do curso de ADS."
aluno.idade = 21; // alterar
aluno.email = "ana@email.com"; // adicionar propriedade nova
// O padrão mais comum do mundo real: ARRAY DE OBJETOS
const produtos = [
{ nome: "Teclado", preco: 150 },
{ nome: "Mouse", preco: 80 },
{ nome: "Monitor", preco: 900 }
];
const caros = produtos.filter((p) => p.preco > 100);
// [{ nome: "Teclado", preco: 150 }, { nome: "Monitor", preco: 900 }]
const nomes = produtos.map((p) => p.nome);
// ["Teclado", "Mouse", "Monitor"]✅ Exercícios do Dia 10
📅 DIA 11 — DOM: o JavaScript "enxergando" a página
11.1 O que é o DOM?
Quando o navegador lê seu HTML, ele monta uma árvore de objetos na memória chamada DOM (Document Object Model). Cada tag vira um "nó" da árvore. O JavaScript pode achar, ler, criar e modificar esses nós. É assim que a página "ganha vida".
document (a página inteira)
└── body
├── h1 "Minha Lista"
├── ul
│ ├── li "Estudar HTML" ← o JS pode achar este li...
│ └── li "Estudar CSS"
└── button "Adicionar" ← ...e reagir quando clicam aqui11.2 Selecionando elementos (o "radar" do JS)
// Pelo ID (retorna UM elemento ou null)
const titulo = document.getElementById("titulo");
// Pelo seletor CSS (retorna UM — o primeiro que encontrar)
const primeiroCard = document.querySelector(".card");
const botao = document.querySelector("#btn-enviar");
const link = document.querySelector("nav a");
// Por seletor CSS (retorna TODOS — uma NodeList, parecida com array)
const cards = document.querySelectorAll(".card");
console.log(cards.length); // quantidade
cards.forEach((card) => console.log(card)); // percorrer11.3 Lendo e alterando conteúdo
const titulo = document.querySelector("h1");
titulo.textContent = "Novo título!"; // muda o texto (USE SEMPRE para texto)
console.log(titulo.textContent); // "Novo título!"
// innerHTML: muda o HTML interno (cuidado: aceita HTML, mas é risco de segurança
// se o conteúdo vier do usuário — prefira textContent)
titulo.innerHTML = "<em>Título</em> com itálico";
// Atributos
const link = document.querySelector("a");
link.href = "https://google.com";
link.setAttribute("target", "_blank");
console.log(link.getAttribute("href"));
// Estilos (inline — ok para mudanças pontuais)
titulo.style.color = "red";
titulo.style.fontSize = "32px"; // camelCase! (font-size vira fontSize)
titulo.style.display = "none"; // esconde o elemento11.4 Classes: o jeito certo de estilizar via JS
const card = document.querySelector(".card");
card.classList.add("destaque"); // adiciona classe
card.classList.remove("destaque"); // remove
card.classList.toggle("destaque"); // liga/desliga (interruptor — PERFEITO p/ dark mode)
card.classList.contains("destaque"); // true/false (tem a classe?)/* No CSS: */
.card.destaque {
border: 2px solid orange;
background-color: #fff8e1;
}11.5 Criando e removendo elementos
// 1. Cria o elemento (ainda não está na página!)
const novoItem = document.createElement("li");
novoItem.textContent = "Estudar JavaScript";
// 2. Coloca dentro de um pai existente
const lista = document.querySelector("ul");
lista.appendChild(novoItem); // adiciona no fim
// lista.prepend(novoItem); // adiciona no início
// 3. Remove
novoItem.remove(); // some da página
// lista.removeChild(novoItem); // forma antiga
// Padrão completo: array → elementos na tela
const tarefas = ["Estudar HTML", "Estudar CSS", "Estudar JS"];
const listaTarefas = document.querySelector("#lista");
tarefas.forEach((tarefa) => {
const li = document.createElement("li");
li.textContent = tarefa;
listaTarefas.appendChild(li);
});✅ Exercícios do Dia 11
📅 DIA 12 — Eventos: a página reage ao usuário + localStorage
12.1 addEventListener: "fique de ouvido" para o clique
const botao = document.querySelector("#btn-clique");
botao.addEventListener("click", () => {
console.log("Você clicou no botão!");
});
// ↑ evento ↑ o que fazer quando acontecer (callback)Eventos mais comuns:
elemento.addEventListener("click", handler); // clique
elemento.addEventListener("dblclick", handler); // duplo clique
elemento.addEventListener("mouseover", handler); // mouse por cima
elemento.addEventListener("mouseout", handler); // mouse saiu
elemento.addEventListener("input", handler); // digitou em um campo (dispara a cada tecla)
elemento.addEventListener("change", handler); // campo mudou e perdeu foco (select, checkbox)
elemento.addEventListener("keydown", handler); // apertou tecla (event.key = qual tecla)
elemento.addEventListener("submit", handler); // enviou formulário (no <form>)O objeto event: o navegador passa informações sobre o evento:
document.querySelector("input").addEventListener("input", (event) => {
console.log(event.target); // o elemento que disparou
console.log(event.target.value); // o valor digitado ← MUITO usado
});
document.addEventListener("keydown", (event) => {
if (event.key === "Enter") console.log("Apertou Enter!");
});12.2 Formulários: capturando o que o usuário digitou
const formulario = document.querySelector("#meu-form");
formulario.addEventListener("submit", (event) => {
event.preventDefault(); // ⚠️ IMPEDE o recarregamento da página (comportamento padrão do form)!
// Lê os valores pelos "name" dos campos:
const nome = document.querySelector("#nome").value;
const email = document.querySelector("#email").value;
console.log(`Cadastro: ${nome} (${email})`);
// Limpa o formulário:
formulario.reset();
});12.3 Adicionando itens a uma lista (o exercício que vira seu projeto final)
const formulario = document.querySelector("#form-tarefa");
const input = document.querySelector("#nova-tarefa");
const lista = document.querySelector("#lista");
formulario.addEventListener("submit", (event) => {
event.preventDefault();
const texto = input.value.trim(); // .trim() remove espaços em branco das pontas
if (texto === "") return; // não aceita tarefa vazia
const li = document.createElement("li");
li.textContent = texto;
// Botão de remover em cada item:
const botaoRemover = document.createElement("button");
botaoRemover.textContent = "❌";
botaoRemover.addEventListener("click", () => li.remove());
li.appendChild(botaoRemover);
lista.appendChild(li);
input.value = ""; // limpa o campo
input.focus(); // devolve o foco para continuar digitando
});12.4 localStorage: dados que sobrevivem ao refresh 🧠
O localStorage guarda dados no navegador do usuário (até ~5MB, texto puro). É a memória do seu site:
// Salvar (só aceita TEXTO):
localStorage.setItem("nome", "Ana");
localStorage.setItem("idade", "20");
// Ler:
const nome = localStorage.getItem("nome"); // "Ana" (ou null se não existir)
const idade = Number(localStorage.getItem("idade")); // Number() converte texto → número
// Remover:
localStorage.removeItem("nome");
// localStorage.clear(); // limpa TUDO
// Para salvar ARRAYS/OBJETOS: JSON.stringify (vira texto) e JSON.parse (volta a ser objeto)
const tarefas = ["Estudar HTML", "Estudar CSS"];
localStorage.setItem("tarefas", JSON.stringify(tarefas)); // salva como "[...]"
const tarefasSalvas = JSON.parse(localStorage.getItem("tarefas")); // volta a ser array
console.log(tarefasSalvas[0]); // "Estudar HTML"Padrão completo para o seu app (salvar → carregar na abertura):
const lista = document.querySelector("#lista");
const input = document.querySelector("#nova-tarefa");
const formulario = document.querySelector("#form-tarefa");
// 1. Função que DESENHA a lista na tela (a partir de um array):
function renderizar(tarefas) {
lista.innerHTML = ""; // limpa a lista
tarefas.forEach((tarefa) => {
const li = document.createElement("li");
li.textContent = tarefa;
lista.appendChild(li);
});
}
// 2. Carregar do localStorage quando a página abre:
let tarefas = JSON.parse(localStorage.getItem("tarefas")) || [];
// ↑ se não existir nada, vira [] (array vazio) — o || é "fallback"
renderizar(tarefas);
// 3. Adicionar tarefa:
formulario.addEventListener("submit", (event) => {
event.preventDefault();
const texto = input.value.trim();
if (texto === "") return;
tarefas.push(texto);
localStorage.setItem("tarefas", JSON.stringify(tarefas)); // salvar
renderizar(tarefas); // redesenhar
input.value = "";
});Pegadinhas: o localStorage é por origem (domínio) — cada site tem o seu. E guardar senha/dado sensível lá = nunca. Só dados simples.
✅ Exercícios do Dia 12
📅 DIA 13 — JSON, fetch e APIs: buscando dados da internet
13.1 O que é uma API?
Uma API é um "garçom" de um sistema: você faz um pedido (requisição) e ela traz o que você pediu (resposta). Muitos serviços públicos oferecem APIs gratuitas que devolvem dados em JSON — exatamente a estrutura de array de objetos que você já aprendeu!
13.2 JSON — o formato de dados da web
[
{ "nome": "Ana", "idade": 20 },
{ "nome": "Bruno", "idade": 22 }
]É literalmente texto que parece um array de objetos. No JS:
// JSON → objeto JS: JSON.parse
const texto = '{"nome": "Ana"}';
const objeto = JSON.parse(texto);
console.log(objeto.nome); // "Ana"
// objeto JS → JSON: JSON.stringify
const deVolta = JSON.stringify(objeto);
console.log(deVolta); // '{"nome":"Ana"}'13.3 fetch + async/await: buscar dados
// async = função que pode esperar coisas. await = "espere terminar antes de continuar".
async function carregarUsuarios() {
try {
// 1. Busca (fetch) — isso leva tempo (rede), por isso o await
const resposta = await fetch("https://jsonplaceholder.typicode.com/users");
// 2. Converte a resposta em JSON (array de objetos)
const usuarios = await resposta.json();
console.log(usuarios); // veja no console!
return usuarios;
} catch (erro) {
// 3. Se QUALQUER coisa der errado (sem internet, servidor fora...):
console.error("Erro ao carregar:", erro);
}
}Ligando tudo — buscar e desenhar na tela:
<body>
<button id="btn-carregar">Carregar usuários</button>
<ul id="lista"></ul>
<script src="script.js"></script>
</body>const botao = document.querySelector("#btn-carregar");
const lista = document.querySelector("#lista");
botao.addEventListener("click", async () => {
botao.textContent = "Carregando..."; // feedback pro usuário
botao.disabled = true;
try {
const resposta = await fetch("https://jsonplaceholder.typicode.com/users");
if (!resposta.ok) throw new Error(`Erro HTTP: ${resposta.status}`); // status 200 = ok
const usuarios = await resposta.json();
lista.innerHTML = ""; // limpa
usuarios.forEach((usuario) => {
const li = document.createElement("li");
li.textContent = `${usuario.name} — ${usuario.email}`;
lista.appendChild(li);
});
} catch (erro) {
lista.innerHTML = `<li>❌ Falha ao carregar: ${erro.message}</li>`;
} finally {
botao.textContent = "Carregar usuários"; // restaura (roda sempre, certo ou errado)
botao.disabled = false;
}
});APIs gratuitas para praticar:
- https://jsonplaceholder.typicode.com/users — usuários falsos (ideal)
- https://api.exchangerate-api.com/v4/latest/USD — cotações de moedas
- https://dog.ceo/dog-api/ — fotos de cachorros (
https://dog.ceo/api/breeds/image/random) - https://api.chucknorris.io/jokes/random — piadas aleatórias
✅ Exercícios do Dia 13
📅 DIA 14 — 🎯 PROJETO FINAL: To-Do List completa
Você já tem todas as peças. Agora é juntar: HTML + CSS + JS + localStorage.
Requisitos (mínimo):
- ✅ Adicionar tarefa (formulário + Enter)
- ✅ Marcar como concluída (clique no texto → riscado)
- ✅ Remover tarefa (botão ❌)
- ✅ Persistência com localStorage (recarregou, continua lá)
- ✅ Contador de tarefas pendentes
- ✅ Layout responsivo decente
Bônus (se sobrar tempo): filtros (Todas / Ativas / Concluídas), campo de busca, editar tarefa, data de criação.
Estrutura sugerida (3 arquivos):
index.html:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minha To-Do List</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="app">
<h1>✅ Minhas Tarefas</h1>
<p id="contador"></p>
<form id="form-tarefa">
<input type="text" id="nova-tarefa" placeholder="O que precisa ser feito?" required>
<button type="submit">Adicionar</button>
</form>
<ul id="lista"></ul>
</div>
<script src="script.js"></script>
</body>
</html>style.css: (você já sabe! Flexbox centralizando, cards, hover, media query p/ celular — capriche)
script.js: (o padrão do dia 12, com uma evolução — cada tarefa vira um objeto com texto e feita)
const form = document.querySelector("#form-tarefa");
const input = document.querySelector("#nova-tarefa");
const lista = document.querySelector("#lista");
const contador = document.querySelector("#contador");
// Cada tarefa: { texto: "Estudar JS", feita: false }
let tarefas = JSON.parse(localStorage.getItem("tarefas")) || [];
function salvar() {
localStorage.setItem("tarefas", JSON.stringify(tarefas));
}
function atualizarContador() {
const pendentes = tarefas.filter((t) => !t.feita).length;
contador.textContent = `${pendentes} pendente(s)`;
}
function renderizar() {
lista.innerHTML = "";
tarefas.forEach((tarefa, indice) => {
const li = document.createElement("li");
li.textContent = tarefa.texto;
if (tarefa.feita) li.classList.add("feita"); // CSS: .feita { text-decoration: line-through; ... }
// Clique no item = marcar/desmarcar
li.addEventListener("click", () => {
tarefa.feita = !tarefa.feita;
salvar();
renderizar();
});
// Botão remover
const btnRemover = document.createElement("button");
btnRemover.textContent = "❌";
btnRemover.addEventListener("click", (event) => {
event.stopPropagation(); // impede que o clique chegue no <li> (senão marca como feita!)
tarefas.splice(indice, 1); // remove do array pela posição
salvar();
renderizar();
});
li.appendChild(btnRemover);
lista.appendChild(li);
});
atualizarContador();
}
form.addEventListener("submit", (event) => {
event.preventDefault();
const texto = input.value.trim();
if (texto === "") return;
tarefas.push({ texto: texto, feita: false });
salvar();
renderizar();
input.value = "";
input.focus();
});
renderizar(); // carrega tudo ao abrir a páginaApós terminar — PUBLIQUE!
- Crie o repositório no GitHub e suba os 3 arquivos
- Publique no Cloudflare Pages → você terá
https://seu-projeto.pages.devpara mostrar para todo mundo (peça para mim — tenho o script pronto, é rápido!) - Mandou bem? Faça uma segunda versão com filtros e busca — é assim que se vira desenvolvedor: iterando.
PARTE PARTE 3 — REFERÊNCIAS RÁPIDAS
Glossário de tags HTML (consulte sempre que esquecer)
| Tag | O que faz |
|---|---|
<html> | Raiz do documento |
<head> | Metadados invisíveis |
<body> | Conteúdo visível |
<h1>–<h6> | Títulos (1 = mais importante) |
<p> | Parágrafo |
<a> | Link (atributo href) |
<img> | Imagem (atributos src, alt) |
<ul> / <ol> / <li> | Listas: não ordenada / ordenada / item |
<div> | Bloco genérico |
<span> | Trecho inline genérico |
<header> / <footer> | Cabeçalho / rodapé da página ou de uma seção |
<nav> | Menu de navegação |
<main> | Conteúdo principal (único) |
<section> | Seção temática |
<article> | Conteúdo independente (post, notícia) |
<aside> | Conteúdo lateral |
<table> <tr> <td> <th> | Tabela / linha / célula / célula de cabeçalho |
<form> | Formulário |
<input> | Campo de entrada (type: text, email, password, number, date, checkbox, radio, color...) |
<label> | Rótulo do campo (atributo for → id) |
<select> <option> | Lista suspensa / opção |
<textarea> | Campo de texto longo |
<button> | Botão (type: submit, reset, button) |
<br> / <hr> | Quebra de linha / linha horizontal |
<strong> / <em> | Negrito / itálico (com significado) |
<code> | Trecho de código |
<blockquote> | Citação longa |
<time> | Data/hora legível |
<figure> <figcaption> | Imagem com legenda |
<!-- --> | Comentário |
Glossário de propriedades CSS
| Propriedade | O que faz |
|---|---|
color / background-color | Cor do texto / do fundo |
font-size / font-family | Tamanho / fonte |
font-weight / font-style | Espessura / itálico |
text-align / text-decoration | Alinhamento / decoração do texto |
line-height | Altura da linha |
width / height | Largura / altura |
max-width | Largura máxima (responsividade) |
margin / padding | Espaço externo / interno |
border / border-radius | Borda / cantos arredondados |
box-sizing | border-box = width inclui padding+borda |
display | block / inline / flex / grid / none |
flex-direction | row / column |
justify-content | Alinhamento no eixo principal |
align-items | Alinhamento no eixo transversal |
gap | Espaço entre itens flex/grid |
grid-template-columns | Colunas do grid |
position | static / relative / absolute / fixed / sticky |
top / right / bottom / left | Deslocamento do elemento posicionado |
z-index | Camada (quem fica por cima) |
transition | Animação suave entre estados |
transform | scale() / translate() / rotate() |
cursor | Formato do mouse (pointer = mãozinha) |
opacity | Transparência (0–1) |
overflow | Comportamento do conteúdo que transborda |
Comandos JS que você mais vai usar
console.log(x) // imprimir/debugar
const / let // declarar variáveis
if / else / switch // decisões
for / while / for...of // repetição
function / () => // funções
array.map(f) / array.filter(f) // transformar / filtrar
array.forEach(f) // percorrer
objeto.propriedade // acessar objeto
document.querySelector(css) // achar elemento
elemento.textContent // ler/mudar texto
elemento.classList.add/remove/toggle // classes
elemento.addEventListener(ev, f) // eventos
elemento.style.propriedade // estilos inline
localStorage.setItem/getItem // persistência
JSON.stringify / JSON.parse // objeto ↔ texto
async / await / fetch(url) // chamadas de rede
event.preventDefault() // parar comportamento padrãoPARTE PARTE 4 — PLANO DE ESTUDOS E RECURSOS
Rotina diária recomendada (1h30–2h)
- 10 min: revisão rápida do dia anterior (releia o código que fez)
- 30–40 min: teoria deste guia (leia, digite os exemplos)
- 50–70 min: exercícios do dia + um desafio a mais
- 5 min: anote o que aprendeu e o que ficou confuso (no fim da semana, revise as dúvidas)
Recursos gratuitos
- MDN Web Docs (developer.mozilla.org) — a documentação oficial, sua bíblia. Pesquise "MDN
" - freeCodeCamp (freecodecamp.org) — trilhas gratuitas de HTML/CSS e JS com certificado; ótimo reforço nos dias 3–5 e 9–11
- Frontend Mentor (frontendmentor.com) — desafios com layout pronto para você codar
- JS Hero (pt) — exercícios curtos de JS em português
- W3Schools (w3schools.com) — referência rápida e "Try it yourself" (use como consulta, não como curso principal)
- CS50 (edx.org, gratuito) — se quiser se aprofundar em lógica depois
O que NÃO estudar agora (armadilhas do iniciante)
- ❌ Frameworks (React, Vue, Angular) — primeiro domine JS puro
- ❌ Tailwind, Sass, build tools, bundlers
- ❌ TypeScript
- ❌ "Estudar" assistindo vídeo sem digitar — programação se aprende digitando
- ❌ Decorar tudo — use as referências acima, é normal consultar
Checklist final (depois das 2 semanas, você deve saber)
Bons estudos! Se travar, aplique a regra dos 15 minutos: tente sozinho, depois pesquise ("MDN