Pular para conteúdo

0017 — CSS do app no kit de UI: link fixo para app.css

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-07-17 · Decidido em: 2026-07-17

Contexto

A 0015 removeu o headComExtras do kit — com razão: dois <head> no mesmo documento quebravam toda view, e naquele momento nenhuma view usava o slot. A saída prescrita foi "escreva o <head> à mão nessa tela e traga o caso ao central". A 0015 fechou o slot, mas o head(title) linka só o Bootstrap e o custom-theme.css — e o custom-theme.css é identidade da casa, rastreado, que não se edita por app. Um app com componentes próprios (timeline, tiles, stepper, badges de domínio) não tinha onde pôr o CSS deles.

A resposta "escreva o <head> à mão" não escala: num app de 16 telas, escrever o <head> em todas descarta justamente o fragment que o kit existe para dar.

Não era hipótese — já tinha acontecido em dois apps, com dois contornos diferentes:

  • int-pied (17 views no kit): fragment local componentes :: appCss emitindo o <link> dentro do <body>. HTML5 permite e todo navegador aplica, mas é contorno local de lacuna de template.
  • bi-comercial-xls (7 views): forkou o layout.html e documentou a divergência num bloco "DIVERGÊNCIAS LOCAIS" no cabeçalho.

O fork é o dado que decide. O layout.html forkado ainda carregava o <th:block th:fragment="styles"> morto que a 0.21.0 removera do central: fork sai do radar do /xadm-docs e congela o app numa versão velha do kit — deixa de receber as correções, inclusive as de bug. E os dois apps escolheram, independentemente, o mesmo caminho: /css/app.css. A convenção certa foi descoberta duas vezes porque o kit não a prescrevia — o mesmo padrão da 0016, onde o integrador inventou a hospedeira sozinho.

Decisão

O head(title) do kit sempre linka /css/app.css, depois do custom-theme.css. Todo app que usa o kit tem public/css/app.css, nem que vazio; a /xadm-docs o scaffolda de templates/app.css na criação do app.

Dois CSS, dois donos (§1.9):

custom-theme.css app.css
O que é identidade da casa componentes deste app
Dono o central o app
Rastreado sim, verbatim não — scaffold, copiado uma vez

Descartadas:

  • Model attr ${appCss} (th:if="${appCss != null}") — segue o padrão de model attrs que o kit já usa e evita o 404, mas obriga todo controller a setar o attr (ou o app a montar um ViewsModelDecorator): complexidade permanente no app para um <link> estático.
  • Fragment irmão em 2º arquivo (layout-head.html :: headComCss) — a 0015 verificou que essa cura renderiza; o custo é um 2º rastreado, dois donos do markup do <head> (§1.9) e duas convenções para a mesma coisa.
  • Normatizar o contorno do int-pied (<link> no <body>) — funciona, mas deixa cada app reinventando o fragment e o kit sem dono do assunto: é o que produziu os dois contornos divergentes.

Consequências

  • Nenhum app quebra. As 37 views reais seguem chamando head('Título') com um parâmetro — o fragment não mudou de assinatura, e não há segundo <head> (a 0015 continua valendo: slot de markup arbitrário no <head> segue não existindo).
  • Custo aceito: app sem CSS de componente precisa do app.css vazio, senão o <link> fixo dá 404 em toda página. O scaffold (só comentário) resolve; é uma cópia, não uma obrigação recorrente.
  • O scaffold mora em templates/app.css, achatado, fora de templates/public/ — o que está lá dentro a /xadm-docs copia verbatim, e um scaffold ali seria sobrescrito a cada re-derivação, apagando o CSS do app. Glob não leva exceção; move-se a origem (mesma decisão de 0.23.1, quando o custom-theme.css saiu de views/).
  • app.css vem por último na cascata, então sobrescrever a identidade "funciona". Isso é convenção, não gate: identidade divergente por app é o problema que o kit existe para resolver, e quem precisa de algo da casa traz o caso ao central (§6).
  • Migração oportunista: os dois contornos continuam funcionando; ninguém precisa correr. O bi-comercial-xls ganha mais em des-forkar (volta a receber correção do kit) do que o int-pied em trocar o fragment local pelo <link> do kit.