Curso de CSS / Criar um site responsivo com HTML e CSS

Você pode combinar HTML semântico, variáveis CSS compartilhadas, navegação com Flexbox e layout de cartões em Grid para construir um pequeno site responsivo. Comece com conteúdo legível e um layout utilizável para telas estreitas, depois adicione ajustes para telas mais largas e estados de interação visíveis.

Defina a página e os critérios de aceitação

Decida qual conteúdo e comportamento a página precisa antes de aplicar o estilo. Em telas estreitas, a navegação se ajusta quando necessário e os cards formam uma coluna. Mais espaço disponível permite duas ou três colunas. Limite a largura de leitura geral para que o texto não se torne excessivamente longo em telas largas.

Requisitos Critérios de conclusão
estrutura de conteúdo Um título principal, frase introdutória, três cards e rodapé são lidos em ordem.
tela estreita Menus e cards são legíveis sem rolagem horizontal completa
tela larga Os cartões são dispostos em várias colunas enquanto mantêm a largura máxima do corpo
navegação por teclado Uma marca de foco aparece nos atalhos para o texto e links de menu/movimento.
Mudanças de conteúdo Mesmo se você inserir descrições longas e strings sem espaços, o layout cresce para acomodá-las, sem altura fixa que corte o conteúdo.
movimento reduzido Permite que você se mova conforme necessário sem rolagem suave e transições decorativas.

Este exemplo é uma tela estática e não há links no próprio cartão. O menu de introdução/curso e os grandes links de navegação levam a seções do mesmo documento. Para expandir sua lista de cursos reais, coloque o URL do post verificado no título do cartão. Não é necessário adicionar formulários não utilizados ou animações infinitas para completar este exercício.

Prepare arquivos e HTML semântico

Crie index.html e style.css no mesmo local, em uma pasta vazia. Ao criar o arquivo, certifique-se de que não seja index.html.txt devido à extensão oculta e salve como UTF-8. A tag link em index.html aponta para style.css na mesma pasta. Nenhuma instalação ou build separado é necessário.

learning-site/
  index.html
  style.css

Primeiro, salve todo o HTML abaixo como index.html. Mesmo que o CSS esteja vazio, o título, o link e o conteúdo do cartão devem ser lidos em ordem. header é a área do cabeçalho do site, nav é a navegação, main é o conteúdo principal e footer é o rodapé. Use h2 para a seção de tópicos e h3 para os títulos dos cartões, abaixo do h1 do arquivo independente. Este HTML é um exemplo de um arquivo independente, portanto, ele está separado da estrutura da página que está diretamente anexada ao corpo do WordPress.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>A Small Learning Site</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <a class="skip-link" href="#main">Skip to main content</a>
  <header class="site-header">
    <div class="container header-inner">
      <p class="site-name">Learning Notes</p>
      <nav aria-label="Main navigation">
        <a href="#intro">About</a><a href="#lessons">Lessons</a>
      </nav>
    </div>
  </header>
  <main id="main" tabindex="-1">
    <section id="intro" class="hero" aria-labelledby="intro-title">
      <div class="container">
        <h1 id="intro-title">Learn to Build Webpages Step by Step</h1>
        <p>Structure content with HTML and adapt its appearance with CSS.</p>
        <a class="button" href="#lessons">Explore the lessons</a>
      </div>
    </section>
    <section id="lessons" class="lessons container" aria-labelledby="lessons-title">
      <h2 id="lessons-title">Learning topics</h2>
      <ul class="card-grid" role="list">
        <li><article class="card"><h3>HTML structure</h3><p>Organize content with headings and paragraphs.</p></article></li>
        <li><article class="card"><h3>CSS styles</h3><p>Adjust colors, fonts, and spacing.</p></article></li>
        <li><article class="card"><h3>Responsive layout</h3><p>Arrange cards to fit the available width.</p></article></li>
      </ul>
    </section>
  </main>
  <footer class="site-footer"><div class="container"><p>Small learning site exercise</p></div></footer>
</body>
</html>

O atalho para o texto principal está conectado ao ID de main. tabindex="-1" permite que main receba foco sem adicioná-lo à ordem normal de tabulação. Toque em um menu ou atalho para navegar até essa seção e garanta que a navegação pelo teclado continue a partir do conteúdo principal. Para o propósito e composição do atalho, consulte a técnica de atalho de texto W3C.

Defina valores compartilhados e largura do conteúdo

Comece o style.css com a seguinte seção. Nomear as variáveis de cor de acordo com suas funções facilita a alteração da cor de destaque compartilhada. border-box inclui padding e bordas na largura declarada, simplificando a definição de tamanho. Estabeleça um layout base que possa acomodar o crescimento do conteúdo em vez de atribuir dimensões fixas em todos os lugares. Antes de alterar os valores compartilhados, distinga Variáveis: var(), escopo, herança e fallback.

/* Shared values and base styles */
:root {
  --ink: #183044;
  --accent: #166b92;
  --surface: #eef6fa;
  --line: #c9dbe4;
  --focus: #164f73;
}
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { margin: 0; color: var(--ink); font-family: sans-serif; line-height: 1.6; }
a { color: var(--accent); text-underline-offset: .15em; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.container { width: min(100% - 2rem, 68rem); margin-inline: auto; }
.container, .card { overflow-wrap: anywhere; }

A largura do contêiner é a menor entre “a largura disponível menos 2rem no total, reservando normalmente 1rem de cada lado” e 68rem. Fornece margens à esquerda e à direita para telas estreitas e largura máxima para telas largas. auto para margin-inline centraliza a área. overflow-wrap: anywhere permite que endereços ou identificadores longos e sem espaços sejam quebrados em uma linha, se necessário. Deve-se fazer uma distinção entre a prática que apenas aumenta o comprimento de uma frase geral e a prática que adiciona uma palavra longa.

Se você atualizar neste estágio, as cores, a fonte padrão e a largura do conteúdo serão aplicadas, mas os cabeçalhos e cartões ainda não serão detalhadamente organizados. Se não houver nenhuma mudança, verifique o caminho do arquivo antes de adicionar a seção de volta. Os conceitos de tamanho fluido e largura máxima estão vinculados aos Layout fluido com min() e clamp().

Construa navegação Flexbox e caminhos de foco

Adicione a seguinte seção sob Regras Comuns em style.css: O posicionamento entre o nome do site e o menu é gerenciado pelo header-inner, e o espaçamento dentro do menu é gerenciado pelo nav. Ao separar o intervalo entre as duas posições, você pode reduzir a possibilidade de alterações não intencionais no espaçamento entre os links do menu ao alterar o espaçamento de todo o cabeçalho. Os princípios básicos da direção do eixo e do posicionamento dos itens podem ser encontrados em Flexbox básico: contêineres, itens e eixos.

/* Navigation and header */
.skip-link { position: absolute; left: 1rem; top: -6rem; padding: .5rem; background: white; }
.skip-link:focus { top: 1rem; z-index: 10; }
.site-header { border-bottom: 1px solid var(--line); }
.header-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .5rem 1.5rem; padding-block: 1rem; }
.site-name { margin: 0; font-weight: 700; }
nav { display: flex; flex-wrap: wrap; gap: 1rem; }

flex-wrap coloca o item na linha seguinte se não houver espaço suficiente. Ter um menu de duas linhas em uma tela estreita não é uma falha. Os critérios para julgamento são se há sobreposição, truncamento ou links não clicáveis. Para manter uma ordem de navegação significativa, não use order apenas para inverter a apresentação visual sem avaliar a ordem de leitura e do teclado.

O atalho de texto geralmente é colocado fora da tela superior e é tornado visível quando recebe foco. Ocultá-lo com display:none não cumpre o mesmo propósito porque ele nem mesmo recebe foco do teclado. Ao pressionar Tab pela primeira vez, o link para saltar ao conteúdo aparece. Pressione Enter e depois Tab novamente: o foco deve seguir para o grande link da introdução. O contorno escuro de foco foi escolhido para se destacar tanto do fundo branco quanto do fundo da introdução.

Estilize a introdução fluida e os estados de link

Adicionar as seguintes seções completa o contexto introdutório, o título e os grandes links de navegação. O limite do tamanho do título vincula os valores mínimo, flutuante e máximo. A fonte não se torna infinitamente maior à medida que a largura aumenta, e a configuração do tamanho da fonte, incluindo o termo rem, também é levada em consideração. É necessária uma verificação de tela separada para ver se é realmente fácil de ler quando o usuário aumenta o zoom.

/* Introduction and navigation link */
.hero { padding-block: clamp(3rem, 8vw, 6rem); background: var(--surface); }
.hero h1 { max-width: 18ch; margin-block: 0 1rem;
  font-size: clamp(1.8rem, 1.2rem + 2vw, 3rem); line-height: 1.25; }
.hero p { max-width: 50ch; }
.button { display: inline-block; margin-top: .5rem; padding: .7rem 1rem;
  border-radius: .4rem; background: var(--accent); color: white; text-decoration: none;
  transition: background-color 180ms ease; }
.button:hover { background: #104d6a; }

O max-width: 18ch do cabeçalho usa a largura do glifo “0” da fonte; isso não garante 18 letras por linha. Seu line-height controla as linhas de cabeçalho quebradas, enquanto o parágrafo introdutório é limitado a 50ch. Este exemplo usa fontes sans-serif do sistema e não baixa nenhuma fonte externa.

O grande link usa o elemento a porque navega até a seção de lições no mesmo documento. Uma ação que muda o estado, sem navegar, normalmente deve usar button. Apenas transições de cor de fundo são usadas ao passar o mouse, e nenhum movimento decorativo ou aumento é necessário. O status de foco pode ser confirmado por um contorno comum.

Construa cartões em grade que acomodem o conteúdo

Adicione as seguintes seções para completar seu cartão de curso e rodapé. Remova as margens e marcadores padrão da lista, mas mantenha as estruturas ul e li no HTML. Se uma lista com list-style: none estiver fora de nav, ela pode não ser reconhecida como uma lista na árvore de acessibilidade do Safari. No exemplo, ul especifica role="list" para definir o papel da lista. Esta condição também pode ser encontrada na listagem MDN descrição de acessibilidade. A ordem de leitura do HTML não muda para a disposição de linhas e colunas no Grid.

/* Cards and footer */
.lessons { padding-block: 3rem; }
.lessons h2 { margin-block: 0 1.5rem; }
.card-grid { display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 1rem; margin: 0; padding: 0; list-style: none; }
.card-grid > li { min-width: 0; }
.card { height: 100%; padding: 1.5rem; border: 1px solid var(--line); border-radius: .5rem; }
.card h3 { margin-block: 0 .75rem; }
.card p { margin-block: 0; }
.site-footer { padding-block: 2rem; border-top: 1px solid var(--line); }
.site-footer p { margin: 0; }

Grid: repeat(), auto-fit, auto-fill e áreas explica a repetição automática de colunas que cabem no contêiner, e minmax() determina o tamanho mínimo e o tamanho expansível de cada coluna. O valor mínimo de min(100%, 16rem) faz com que o cartão encolha até essa largura quando seu elemento pai for mais estreito que 16rem. O espaço livre é dividido por 1fr, e como existem três cartões reais, a largura adicional não cria um quarto cartão. auto-fit pode gerar faixas extras vazias e depois recolhê-las, distribuindo o espaço entre as ocupadas. Veja função repeat do MDN e função minmax.

Sob a condição de que o tamanho do texto de nível superior seja 16px e a largura da página disponível seja a mesma que a da janela de visualização, a largura mínima do cartão é 256px, o espaçamento é de 16px e as margens totais esquerda e direita são 32px. Você precisa de pelo menos 560px de espaço para duas colunas e 832px para três colunas. À medida que a barra de rolagem, a largura do elemento pai e o tamanho da fonte mudam, a largura de transição real também muda, então não a memorize com base no nome do dispositivo.

A altura de um cartão de 100% é o valor que preenche a altura dos itens da lista na mesma linha. Não é uma altura fixa em pixels, então as linhas podem crescer à medida que a descrição cresce. Para evitar que palavras longas ocupem o espaço do item do Grid, defina o min-width do li para 0 e use as regras de quebra de linha do cartão.

Adicione condições de tela ampla e movimento reduzido

Adicione esta seção ao final do style.css. A partir de 64rem, inclusive, o fundo da introdução muda para um gradiente. O grid continua determinando o número de colunas de cartão de forma independente; esta media query não define essa contagem.

/* Conditional adjustments */
@media (min-width: 64rem) {
  .hero { background: linear-gradient(100deg, var(--surface), #fff); }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .button { transition: none; }
}

Na condição de movimento reduzido, mudamos a rolagem para movimento instantâneo e também eliminamos as transições de cor de fundo. O propósito e o foco do link e seu conteúdo são mantidos. A aplicação das regras condicionais está conectada ao Media queries e pontos de quebra baseados no conteúdo, e a verificação de movimento e acessibilidade está conectada ao Verificar layout responsivo: largura, zoom e teclado.

Execute a folha de estilo completa

Este é um arquivo que combina todas as regras adicionadas passo a passo. Use este arquivo inteiro para verificar a ordem do seu código ou para recomeçar. Após salvá-lo na mesma pasta que o index.html, abra o index.html em um navegador e atualize.

/* Shared values and base styles */
:root {
  --ink: #183044;
  --accent: #166b92;
  --surface: #eef6fa;
  --line: #c9dbe4;
  --focus: #164f73;
}
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { margin: 0; color: var(--ink); font-family: sans-serif; line-height: 1.6; }
a { color: var(--accent); text-underline-offset: .15em; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.container { width: min(100% - 2rem, 68rem); margin-inline: auto; }
.container, .card { overflow-wrap: anywhere; }

/* Navigation and header */
.skip-link { position: absolute; left: 1rem; top: -6rem; padding: .5rem; background: white; }
.skip-link:focus { top: 1rem; z-index: 10; }
.site-header { border-bottom: 1px solid var(--line); }
.header-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .5rem 1.5rem; padding-block: 1rem; }
.site-name { margin: 0; font-weight: 700; }
nav { display: flex; flex-wrap: wrap; gap: 1rem; }

/* Introduction and navigation link */
.hero { padding-block: clamp(3rem, 8vw, 6rem); background: var(--surface); }
.hero h1 { max-width: 18ch; margin-block: 0 1rem;
  font-size: clamp(1.8rem, 1.2rem + 2vw, 3rem); line-height: 1.25; }
.hero p { max-width: 50ch; }
.button { display: inline-block; margin-top: .5rem; padding: .7rem 1rem;
  border-radius: .4rem; background: var(--accent); color: white; text-decoration: none;
  transition: background-color 180ms ease; }
.button:hover { background: #104d6a; }

/* Cards and footer */
.lessons { padding-block: 3rem; }
.lessons h2 { margin-block: 0 1.5rem; }
.card-grid { display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 1rem; margin: 0; padding: 0; list-style: none; }
.card-grid > li { min-width: 0; }
.card { height: 100%; padding: 1.5rem; border: 1px solid var(--line); border-radius: .5rem; }
.card h3 { margin-block: 0 .75rem; }
.card p { margin-block: 0; }
.site-footer { padding-block: 2rem; border-top: 1px solid var(--line); }
.site-footer p { margin: 0; }

/* Conditional adjustments */
@media (min-width: 64rem) {
  .hero { background: linear-gradient(100deg, var(--surface), #fff); }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .button { transition: none; }
}

Altere os valores e diagnostique problemas

  1. Reduza a largura da tela para cerca de 390px e depois a aumente, mantendo o valor original. Para larguras pequenas deve haver uma coluna, para larguras grandes deve haver duas ou três colunas. Se as condições descritas acima forem as mesmas, as diferenças entre 559px e 560px e 831px e 832px também são comparadas.
  2. Altere apenas 16rem do card-grid para 20rem. Adicionar mais colunas na mesma tela requer mais espaço. Após a confirmação, restaure para 16rem.
  3. Altere apenas 68rem do container para 50rem. Mesmo em telas maiores, a largura geral do conteúdo fica mais estreita. Após a confirmação, restaure para 68rem.
  4. Altere apenas --accent para outra cor suficientemente escura. Veja se o fundo dos links e botões muda junto e restaure suas cores originais. O texto branco do botão e o indicador de foco também devem ser legíveis no novo fundo.
  5. Estenda a descrição de um cartão em várias frases. Certifique-se de que o conteúdo não seja truncado conforme a altura aumenta e que a altura dos cartões na mesma linha esteja organizada. Após a prática, restaure a frase original.
  6. Insira uma string em inglês sem espaços no cartão. overflow-wrap: anywhere permite quebrar a string dentro do cartão sem mudar seu valor. Apenas remover temporariamente essa regra de quebra de linha pode causar estouro. Após a comparação, tanto as regras quanto as frases são restauradas.
  7. Mova-se com Tab e Shift+Tab e pressione Enter para cada link. Você deve ser capaz de navegar para a introdução e os tópicos de estudo sem precisar de um mouse.
  8. Reproduza as condições de redução de movimento. A navegação pelos links deve continuar funcionando e a rolagem/transições suaves devem desaparecer. Após a confirmação, restaure as configurações de reprodução para o padrão.

Verifique se a navegação, os cards, os indicadores de foco e os parágrafos permanecem legíveis quando o navegador é ampliado ou quando as configurações de fonte mudam. Aumentar temporariamente o tamanho da fonte do html no DevTools testa o dimensionamento baseado em rem, mas é diferente do zoom do navegador. Uma configuração bem-sucedida não estabelece a usabilidade em todas as condições de zoom e tamanho de texto.

problema Verifique primeiro
Nenhum estilo Extensão do arquivo, status de salvamento, caminho relativo do link
Ocorre rolagem horizontal Palavras longas, tamanho mínimo da coluna, largura real do elemento pai, border-box ausente
Altura do cartão irregular Definindo a altura da mesma linha e cartão; Linhas diferentes não precisam ser iguais
Nenhum indicador de foco visível Regras que sobrescrevem o contorno, seja o contorno cortado devido ao overflow
Efeito de movimento indesejado Condições reais de mídia e valores aplicados de scroll-behavior·transition

Selecione o elemento problemático nas Ferramentas de Desenvolvedor para ver a largura calculada real, o seletor e as colunas do Grid. Em vez de mascarar o problema forçando todas as quebras de linha ou adicionando overflow:hidden ao corpo, primeiro corrija o tamanho e o conteúdo do elemento com overflow. Ao verificar o estado base, o estado modificado e o estado de restauração para cada requisito, você pode ir um passo além de copiar o código completo e aplicá-lo também a outros conteúdos.