Communitygithub.com

karero/website-design-system

Gerencia a camada visual de um site: gráficos mobile, modo escuro e tokens de tema.

O que é website-design-system?

Este skill, `karero/website-design-system`, é responsável por toda a camada visual e de desempenho de um site, incluindo gráficos para dispositivos móveis, modo escuro e os tokens de tema. Ele é útil para desenvolvedores que desejam garantir consistência visual, acessibilidade e desempenho (como evitar layout shift e otimizar imagens) em seus projetos Astro. O skill é compatível com plataformas como Astro e Claude Code, fornecendo diretrizes e componentes específicos (como `EmailLink.astro`) para implementar modo escuro sem FOUC, imagens responsivas em formatos modernos (WebP/AVIF) com atributos obrigatórios de largura e altura, e um sistema de tabelas responsivas do tipo `stack` ou `figures`. Ele também aborda a responsividade de texto para múltiplos idiomas, com recomendações como usar larguras flexíveis e `hyphens: auto` para evitar overflow com traduções mais longas. O funcionamento se baseia em manter um arquivo `BRAND.md` sincronizado com tokens CSS, aplicar testes automatizados (a11y, tabelas, imagens) e usar componentes como `EmailLink.astro` para ofuscar endereços de email contra crawlers.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/karero/croftweaver/tree/HEAD/skills/website-design-system

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Sistema de design de site web

Gerencia a camada visual e de desempenho: gráficos mobile, modo escuro e os tokens de tema. Produz/mantém o arquivo BRAND.md (modelo: o skill new-website's templates/brand.md) e o bloco de tokens no templates/astro/src/styles/global.css desse skill. As regras de imagem estão abaixo (WebP/AVIF via astro:assets do Astro); o teste images.spec.ts as impõe. Para gerar imagens, use o skill image.

Modo escuro (primeira classe)

  • Tokens, não cores fixas. Toda cor passa por propriedades CSS customizadas; o modo claro é o padrão :root, as sobreposições do escuro ficam em :root[data-theme="dark"], mais um bloco @media (prefers-color-scheme: dark) para visitantes sem JavaScript. O starter já vem com essa estrutura exata.
  • Script No-FOUC no <head> define data-theme a partir de localStorage.theme ou da preferência do sistema antes da primeira pintura (já configurado em Base.astro). O toggle escreve localStorage.theme (o starter não envia nenhum; se você adicionar um, mencione isso na seção 3 da página de privacidade).
  • Contraste em ambos os temas: cada par texto/fundo passa WCAG AA (4.5:1 corpo, 3:1 grande/UI). Uma cor que funciona no claro muitas vezes falha no escuro — o teste de a11y executa a matriz completa claro+escuro, portanto verifique ambos.

Gráficos mobile e responsivos

  • Mobile first: projete a partir de 360px para cima; alvos de toque ≥ 44px; sem scroll horizontal. Verifique em 360 / 768 / 1280 (preview_resize).
  • Formatos modernos: WebP (ou AVIF) em vez de JPEG/PNG para fotos.
  • Tamanho conforme a exibição, não a origem. Nunca envie uma imagem de 2000px em um slot de 80px; gere variantes de largura e use srcset/sizes (ou <picture>).
  • Sem layout shift: defina atributos explícitos de width/height para que a caixa seja reservada antes do carregamento da imagem (protege CLS / LCP). O <Image> do Astro define eles automaticamente; images.spec.ts exige os atributos (um aspect-ratio apenas via CSS não satisfaz o teste).
  • Lazy vs eager: loading="lazy" abaixo da dobra; a imagem LCP/hero carrega com eager com fetchpriority="high" (NÃO coloque lazy nela).
  • Texto alternativo em cada imagem (alt="" apenas se for puramente decorativa).
  • Fontes: auto-hospede woff2 com font-display: swap; pré-carregue apenas as 1–2 usadas acima da dobra. Evite layout shift devido a trocas tardias de fonte.

Responsividade de texto (cópia traduzida)

  • Texto traduzido ocupa mais espaço. O alemão (e muitas outras línguas) comumente ocupa 20–35% a mais que o equivalente em inglês. Um botão, link de navegação ou cartão dimensionado para caber um placeholder em inglês vai silenciosamente transbordar, quebrar feio ou truncar no momento em que a cópia traduzida real substituir.
  • Prefira larguras flexíveis. Use min-width / flex / grid auto/fr para qualquer elemento que contenha texto traduzido, não uma width fixa dimensionada para a string em inglês.
  • Transbordamento ≠ largura: dimensionamento flexível não impede que um ÚNICO substantivo composto longo (Datenschutzerklärung) estoure uma coluna estreita — isso exige hyphens: auto (correto por idioma via atributo lang que Base.astro já define) mais overflow-wrap: break-word como fallback; o global.css do starter já envia ambos no body. Células de tabela desativam a hifenização (veja Tabelas).
  • Não confie apenas em white-space: nowrap + text-overflow: ellipsis como tratamento para links de navegação ou labels de botões — truncar um link de navegação geralmente não é uma UX aceitável (o visitante não consegue mais saber para onde vai). Tudo bem para conteúdo onde truncamento é uma troca aceita (por exemplo, uma célula de tabela), não para navegação.
  • Verifique com labels traduzidas reais, não placeholders em inglês. Quando um site envia astro-i18n-setup's LanguageSwitcher.astro ou qualquer navegação bilíngue/multilíngue, verifique o layout em 360/768/1280 (preview_resize) usando a cópia real enviada em cada idioma — não apenas o placeholder em inglês.

Tabelas

Um estilo para cada tabela; uma página não carrega CSS de layout para uma tabela. Ele vive em src/styles/tables.css do starter (importado após global.css por Base.astro) e tests/tables.spec.ts o verifica. Um site feito antes desta seção copia tables.css, adiciona a linha de importação ao seu layout e primeiro remove o CSS de tabela próprio de cada página.

Dois tipos, diferenciados pelo que as células contêm:

  • stack (frases): uma tabela acima de 40rem; abaixo disso cada linha empilha, o cabeçalho da linha como título e cada célula sob o nome da coluna. Quatro colunas de prosa não podem dividir 320px.
  • figures (números curtos, class="num" em uma célula numérica): permanece como tabela no celular e deve caber em 320px. Se não couber mais, torne-a stack; uma barra de rolagem não é a solução. stack figures juntos é a aparência de figuras com o layout empilhado.

Marcação, toda tabela:

<div class="table-wrap stack" role="region" aria-label="O que a tabela mostra" tabindex="0">
  <table role="table">
    <thead role="rowgroup"><tr role="row">
      <th scope="col" role="columnheader">{cols[0]}</th><th scope="col" role="columnheader">{cols[1]}</th>
    </tr></thead>
    <tbody role="rowgroup">{rows.map((r) => (
      <tr role="row"><th scope="row" role="rowheader">{r.item}</th><td role="cell" data-label={cols[1]}>{r.text}</td></tr>
    ))}</tbody>
  </table>
</div>
  • Escreva os nomes das colunas uma vez, em uma lista, e use-a para o cabeçalho e para cada data-label: o label de uma célula empilhada deve ser igual ao cabeçalho da coluna, e o teste compara os dois. Uma tabela figures não precisa de funções por célula nem de data-label.
  • Uma tabela empilhada não é mais display: table. As funções são um fallback para um navegador que descarta a tabela quando o layout muda; que funcionem lá não é verificado. No Chromium, medido uma vez em uma tabela real, a árvore de acessibilidade manteve a tabela sem elas.
  • class="tap" em um link que está sozinho em uma célula o torna um alvo de toque de 44px no celular. nowrap mantém um valor curto (1, 3, 6) em uma linha. long-head (com stack) alarga a primeira coluna quando os cabeçalhos das linhas são frases.
  • Palavras não são hifenizadas em células. O hyphens: auto do corpo comprime uma primeira coluna estreita em fragmentos ("An-thropic"), então o bloco define hyphens: manual ali.
  • Uma página cujas tabelas vêm de fora e não podem carregar a marcação vai para TABLE_EXEMPT no spec, com a razão. PAGES permanece intacto: o sitemap e as verificações de llms.txt precisam de cada rota ativa nele.

O que tables.spec.ts verifica: cada tabela está em um .table-wrap de um tipo com sua região, label e tabindex, scope="col" em cada célula de cabeçalho e um <th scope="row"> como a primeira célula de cada linha, com <td> para o restante; uma tabela empilhada tem suas funções e um label igual ao cabeçalho em cada célula; em 360 e 320px nenhuma página e nenhuma tabela rola lateralmente; em 641px e acima uma tabela empilhada é novamente uma tabela com sua linha de cabeçalho aparecendo e nenhuma palavra quebrada (isso pega regras como overflow-wrap: anywhere que permitem que uma coluna comprima uma palavra); nenhuma célula tem hyphens: auto. Também testa o CSS em um fixture que adiciona à home page, com axe em ambos os temas, para que um site sem tabela ainda prove o bloco. O Chromium headless não hifeniza, então a guarda de hifenização lê o estilo computado, não o layout. Safari e VoiceOver não são verificados.

Ofuscação de email (ocultar endereços de crawlers)

Nunca coloque um email em texto simples ou mailto:seu@endereco no HTML fonte — raspadores o coletam para spam em horas. Renderize cada endereço através do componente EmailLink.astro (src/components/EmailLink.astro no skill new-website's templates/astro/, + seu helper lib/obfuscate.ts): o endereço é invertido + codificado em base64 no momento da construção e remontado no navegador, então o HTML servido não contém endereço legível. Visitantes sem JavaScript veem uma dica ainda utilizável "nome [at] dominio [dot] com".

<EmailLink address="[email protected]" subject="Consulta sobre projeto" text="Envie-nos um email" />

Regra: zero links mailto: crus e zero endereços @ literais no HTML construído — website-qa verifica isso. Mesma ideia para qualquer número de telefone que você não queira ser coletado.

Tokens de marca

Espelhe a paleta de BRAND.md no bloco de tokens e mantenha-os sincronizados. Defina: marca (fixa), e por tema heading/ink/muted/accent/link/line/bg/bg-soft/surface. A cor de destaque e a cor do link devem passar AA no fundo em ambos os temas, e é por isso que cada tema tem as suas próprias. O opcional website-brand-kit faz o espelhamento com uma verificação: sua leitura lê as tabelas de BRAND.md, segura cada cor de texto contra 4.5:1 em cada fundo em ambos os temas, e escreve os valores nos três blocos de cores de global.css (claro, escuro e o bloco escuro para visitantes sem JavaScript). Manualmente, altere todos os três blocos juntos.

Feito significa

BRAND.md preenchido e consistente com o bloco de tokens; imagens são WebP, dimensionadas, lazy/eager corretas, com alt; o teste de a11y (claro+escuro) está verde; o layout se mantém em 360/768/1280 sem deslocamento; toda tabela é stack ou figures e tables.spec.ts está verde. Os números de desempenho (FCP/LCP) são verificados em website-qa. O layout também se mantém em 360/768/1280 com cópia real (não placeholder) em cada idioma enviado, não apenas no locale padrão.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Habilidades Relacionadas