Partilhar: WhatsApp
aulify · Sebenta
UC · Unidade de Competência · UC02833

Desenho e construção de interfaces web

Sebenta · HTML5, CSS moderno, responsivo, a11y
50h · 4.5 pontos crédito Curso: T. Desenv. Software ↗ Referencial oficial SNQ
Índice

Apresentação

UC02833 (50h · 4,5 pts) ensina a construir o frontend de aplicações web: HTML5 semântico, CSS moderno (Flexbox, Grid, variáveis), design responsivo mobile-first e acessibilidade. É a base para UC02834 (programação web) e UC02835 (apps móveis).

HTML5

Estrutura de documento

<!DOCTYPE html>
<html lang="pt">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Descrição da página">
  <title>Título — Aulify</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- conteúdo -->
  <script src="app.js"></script>
</body>
</html>

Elementos semânticos

Elemento Uso
<header> Cabeçalho da página ou secção
<nav> Navegação principal
<main> Conteúdo principal (1 por página)
<article> Conteúdo independente (post, notícia)
<section> Agrupamento temático
<aside> Conteúdo lateral relacionado
<footer> Rodapé
<figure>/<figcaption> Imagem com legenda
<time> Data/hora

Usar tag semântica antes de <div>. <div> e <span> são contentores sem significado, último recurso.

<!-- MAU -->
<div class="header">
  <div class="title">Aulify</div>
  <div class="menu">...</div>
</div>

<!-- BOM -->
<header>
  <h1>Aulify</h1>
  <nav>...</nav>
</header>

Vantagens da semântica: - Acessibilidade — leitores de ecrã navegam por landmarks. - SEO — motores valorizam estrutura clara. - Manutenção — código auto-explicativo.

Texto e listas

<h1>Título principal</h1>   <!-- 1 por página -->
<h2>Subtítulo</h2>
<h3>Sub-subtítulo</h3>      <!-- não saltar níveis -->

<p>Parágrafo com <strong>importante</strong> e <em>ênfase</em>.</p>

<ul>
  <li>Item não ordenado</li>
</ul>

<ol>
  <li>Item ordenado</li>
</ol>

<blockquote cite="https://...">Citação</blockquote>

Hiperligações e imagens

<a href="https://aulify.pt">Link externo</a>
<a href="/recursos">Link interno</a>
<a href="#seccao">Âncora na página</a>
<a href="mailto:geral@aulify.pt">Email</a>

<img src="logo.png" alt="Logótipo Aulify" width="200" height="60">

<picture>
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="...">
</picture>

alt obrigatório. Vazio (alt="") para imagens puramente decorativas.

Formulários

<form action="/registar" method="post">
  <label for="nome">Nome</label>
  <input type="text" id="nome" name="nome" required minlength="2">

  <label for="email">Email</label>
  <input type="email" id="email" name="email" required>

  <label for="pass">Palavra-passe</label>
  <input type="password" id="pass" name="pass" minlength="10">

  <label for="idade">Idade</label>
  <input type="number" id="idade" name="idade" min="13" max="120">

  <fieldset>
    <legend>Plano</legend>
    <label><input type="radio" name="plano" value="free" checked> Grátis</label>
    <label><input type="radio" name="plano" value="pro"> Pro</label>
  </fieldset>

  <label for="bio">Sobre ti</label>
  <textarea id="bio" name="bio" rows="4"></textarea>

  <label>
    <input type="checkbox" name="termos" required> Aceito os termos
  </label>

  <button type="submit">Registar</button>
</form>

Tipos de input HTML5: email, tel, url, number, date, time, color, range, search. Cada um traz validação e teclado adequado em mobile.

Acessibilidade de formulários: - Cada input tem <label for="id"> ligado. - required, min, max, pattern validam no browser (mas validar sempre também no servidor). - fieldset + legend agrupam radios/checkboxes relacionados.

CSS

Como aplicar

<!-- Externo (recomendado) -->
<link rel="stylesheet" href="style.css">

<!-- Interno -->
<style> p { color: red; } </style>

<!-- Inline (evitar) -->
<p style="color: red;">...</p>

Seletores

/* Tipo */
p { }

/* Classe */
.card { }

/* ID */
#cabecalho { }

/* Descendente */
nav a { }

/* Filho directo */
ul > li { }

/* Múltiplas classes */
.btn.btn-primario { }

/* Atributo */
input[type="email"] { }

/* Pseudo-classes */
a:hover { }
input:focus { }
li:first-child { }
li:nth-child(2n) { }   /* pares */

/* Pseudo-elementos */
p::first-line { }
.card::before { content: ""; }

Especificidade

Quando há conflito, vence a regra mais específica:

  1. Inline style (1000)
  2. ID (100)
  3. Classe, atributo, pseudo-classe (10)
  4. Elemento, pseudo-elemento (1)

Evitar !important — torna debugging um pesadelo. Preferir aumentar especificidade legítima ou reorganizar CSS.

Box model

Todo elemento é uma caixa: content → padding → border → margin.

*, *::before, *::after {
  box-sizing: border-box;
}

Com border-box, width inclui padding e border — muito mais previsível.

Cores e unidades

.x {
  color: #333;                 /* hex */
  color: rgb(51, 51, 51);
  color: rgba(0, 0, 0, .5);    /* com transparência */
  color: hsl(240, 60%, 50%);   /* matiz, saturação, luz */
}
Unidade Quando usar
rem Tipografia, espaçamento (relativo à raiz)
em Espaçamento relativo ao elemento
px Bordas, detalhes precisos
% Larguras relativas ao pai
vw/vh Relativo à viewport
fr Fracções no grid
ch Largura de caracteres (texto legível)
h1 { font-size: clamp(1.5rem, 4vw, 3rem); }
/* mínimo 1.5rem, escala com viewport, máximo 3rem */

Variáveis CSS (custom properties)

:root {
  --cor-primaria: #6366f1;
  --cor-texto: #1a1a2e;
  --espaco-s: 8px;
  --espaco-m: 16px;
  --espaco-l: 32px;
  --raio: 8px;
  --fonte: "Inter", system-ui, sans-serif;
}

.botao {
  background: var(--cor-primaria);
  padding: var(--espaco-m);
  border-radius: var(--raio);
  font-family: var(--fonte);
}

/* Dark mode trivial */
@media (prefers-color-scheme: dark) {
  :root {
    --cor-texto: #eee;
    --cor-fundo: #1a1a2e;
  }
}

Centralizam o design system. Mudar 1 valor propaga a todo o site.

Layout

Flexbox (uma dimensão)

.container {
  display: flex;
  flex-direction: row;          /* ou column */
  justify-content: space-between; /* eixo principal */
  align-items: center;          /* eixo cruzado */
  gap: 16px;
  flex-wrap: wrap;
}

.item {
  flex: 1;          /* cresce igualmente */
}
.item-fixo {
  flex: 0 0 200px;  /* não cresce, 200px */
}

justify-content: flex-start, center, flex-end, space-between, space-around, space-evenly.

Ideal para: navbars, toolbars, alinhar itens numa linha/coluna, centrar conteúdo.

Grid (duas dimensões)

.galeria {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto;
  gap: 20px;
}

/* Responsivo sem media queries */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 16px;
}

/* Layout de página */
.app {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}
.app > header { grid-area: header; }
.app > nav { grid-area: sidebar; }
.app > main { grid-area: main; }
.app > footer { grid-area: footer; }

Ideal para: galerias, dashboards, layouts de página inteira, qualquer grelha 2D.

Regra prática: Flexbox para componentes (uma direcção); Grid para layout de página (duas direcções).

Posicionamento

.x { position: static; }   /* default */
.x { position: relative; } /* relativo a si mesmo; cria contexto */
.x { position: absolute; } /* relativo ao ancestral posicionado */
.x { position: fixed; }    /* relativo à viewport */
.x { position: sticky; top: 0; } /* fixa ao rolar */

Design responsivo

Mobile-first

Escrever CSS base para mobile; adicionar regras para ecrãs maiores.

/* Base — mobile */
.container {
  padding: 16px;
}
.menu {
  display: none;  /* hamburger em mobile */
}

/* Tablet */
@media (min-width: 768px) {
  .container { padding: 32px; }
  .menu { display: flex; }
}

/* Desktop */
@media (min-width: 1024px) {
  .container {
    max-width: 1100px;
    margin: 0 auto;
  }
}

Vantagens do mobile-first: força priorização de conteúdo essencial; CSS base mais simples; progressive enhancement.

Breakpoints comuns

Dispositivo Largura
Mobile < 768px (base)
Tablet ≥ 768px
Desktop ≥ 1024px
Wide ≥ 1280px

Não decorar dimensões de modelos específicos — usar breakpoints onde o layout "parte".

Imagens responsivas

<img src="foto.jpg"
     srcset="foto-480.jpg 480w, foto-960.jpg 960w"
     sizes="(max-width: 600px) 480px, 960px"
     alt="...">
img { max-width: 100%; height: auto; }

Acessibilidade (a11y)

WCAG essencial

WCAG 2.1 nível AA é o alvo prático.

ARIA

Atributos que dão semântica quando HTML não chega:

<button aria-label="Fechar menu"></button>
<div role="alert">Erro: email inválido</div>
<nav aria-label="Navegação principal">...</nav>
<input aria-describedby="ajuda-pass">
<small id="ajuda-pass">Mínimo 10 caracteres</small>

Regra de ouro: "No ARIA is better than bad ARIA." HTML semântico nativo é preferível. <button> já é acessível; <div onclick> não.

<a href="#main" class="skip-link">Saltar para o conteúdo</a>
...
<main id="main">...</main>
.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: 16px;
  top: 16px;
}

Testar

Workflow e ferramentas

Stack 2026

Performance

Validação

Apêndices

A · Snippet base

<!DOCTYPE html>
<html lang="pt">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Página</title>
  <style>
    *, *::before, *::after { box-sizing: border-box; }
    body { margin: 0; font-family: system-ui, sans-serif; line-height: 1.6; }
    .container { max-width: 1100px; margin: 0 auto; padding: 16px; }
  </style>
</head>
<body>
  <header><h1>Título</h1></header>
  <main class="container">...</main>
  <footer>...</footer>
</body>
</html>

B · Glossário

A11y. Acessibilidade (a + 11 letras + y). Box model. Modelo de caixa: content/padding/border/margin. Flexbox. Layout 1D. Grid. Layout 2D. Media query. Regra CSS condicional ao ecrã. Mobile-first. Desenhar primeiro para mobile. Semântica. HTML com significado (não só <div>). WCAG. Web Content Accessibility Guidelines.

C · Recursos