Files
cybercore-signer/docs/ui-troubleshooting.md
T
Claudecio Martins 4010a9bba5
CI Pipeline / Build & Verify (Linux x86_64) (push) Canceled after 0s
CI Pipeline / Build & Verify (Windows) (push) Canceled after 0s
fix(ui): resolve dark theme text contrast bug and eliminate inline color styles
2026-10-20 20:52:08 -03:00

5.0 KiB

UI Troubleshooting & Resolução de Estilos (JavaFX CSS)

Este documento registra a investigação da causa raiz de problemas visuais na interface gráfica do CyberCore Signer, em especial a falha de renderização de textos escuros sobre fundo escuro no tema escuro.


1. O Problema: Texto Preto sobre Fundo Escuro (Contraste ~1.1:1)

Sintoma

No tema escuro (ThemeManager.AppTheme.DARK / .theme-dark), determinados textos nos diálogos ExitConfirmationDialog (texto explicativo da ação), PdfSignDialog (nome e metadados do documento PDF selecionado, dica de arraste do selo visual) e PdfCertificateSignDialog (opção de memorização segura de PIN) eram renderizados com a cor preta (#000000) sobre um fundo escuro (#090d16 ou #111827).

O contraste medido entre o texto e o fundo situava-se em aproximadamente 1.1:1 a 1.2:1, violando completamente as diretrizes de acessibilidade WCAG AA (mínimo de 4.5:1 para texto normal) e tornando o texto praticamente invisível.


2. Investigação Técnica e Causa Raiz

2.1 Lookups Inexistentes no CSS

Ao inspecionar o código-fonte Java dessas telas, verificou-se o uso de estilos inline via setStyle(...):

subtitle.setStyle("-fx-text-fill: -fx-text-secondary; -fx-font-size: 12px;");
lblDocName.setStyle("-fx-font-weight: bold; -fx-font-size: 12.5px; -fx-text-fill: -fx-text-primary;");
lblDocMeta.setStyle("-fx-font-size: 11px; -fx-text-fill: -fx-text-secondary;");
previewBox.setStyle("-fx-background-color: -fx-bg-primary; -fx-border-color: -fx-border-light; ...");
chkRememberPin.setStyle("-fx-font-size: 11.5px; -fx-text-fill: -fx-text-primary;");

Os tokens -fx-text-primary, -fx-text-secondary, -fx-bg-primary, -fx-border-light e -fx-accent não estavam declarados no arquivo de folha de estilos theme.css.

2.2 Por que o JavaFX rebaixa para preto (#000000)?

No motor de estilização do JavaFX (com.sun.javafx.css / Modena):

  1. Quando uma declaração inline em setStyle(...) utiliza uma cor de lookup (-fx-text-fill: <variavel>), o analisador CSS do JavaFX tenta resolver essa variável percorrendo os ancestrais do nó até o .root da cena.
  2. Caso a variável não seja encontrada, o StyleConverter do JavaFX não lança exceção em tempo de execução. Em vez disso, seu mecanismo de tolerância a falhas adota o valor fallback padrão da especificação base de controles: Color.BLACK (rgba(0, 0, 0, 1.0)).
  3. Em um tema claro, o fundo é branco ou cinza claro (#ffffff / #f1f5f9), de modo que o texto preto parece ter funcionado por pura coincidência de luminância.
  4. No tema escuro, no entanto, o fundo da aplicação é escuro (#090d16 a #111827), fazendo com que o fallback para #000000 destrua o contraste da interface.

2.3 Problemas Adicionais com setStyle(...)

  • Prioridade Forçada: setStyle(...) tem especificidade de estilo inline (prioridade máxima), sobrescrevendo quaisquer regras de temas .theme-light e .theme-dark que tentem ajustar o elemento.
  • Acoplamento: Espalha lógica visual e regras de cor pelo código Java, dificultando testes de regressão automatizados e auditorias de contraste.

3. Diretrizes e Solução Adotada

3.1 Definição Completa de Tokens e Aliases no theme.css

Todos os tokens semânticos e seus aliases de compatibilidade são declarados formalmente nos blocos canônicos de tokens:

.theme-light {
    -fx-text-primary: -fx-color-text;
    -fx-text-secondary: -fx-color-text-muted;
    -fx-bg-primary: -fx-color-surface;
    -fx-border-light: -fx-color-border-subtle;
    -fx-accent: -fx-color-primary;
}

.theme-dark {
    -fx-text-primary: -fx-color-text;
    -fx-text-secondary: -fx-color-text-muted;
    -fx-bg-primary: -fx-color-surface;
    -fx-border-light: -fx-color-border;
    -fx-accent: -fx-color-primary;
}

3.2 Eliminação de Cores Inline

É terminantemente proibido utilizar setStyle(...) com propriedades que afetem cores:

  • Proibidos em setStyle: -fx-text-fill, -fx-background-color, -fx-border-color, -fx-fill, -fx-stroke ou códigos #hex.
  • Permitidos em setStyle exclusivamente quando estritamente necessário: geometria e layout (-fx-min-width, -fx-pref-width, -fx-padding).

Toda estilização cromática deve ser feita atribuindo classes semânticas:

  • .text-primary: Texto principal com alta luminância no escuro e baixa no claro.
  • .text-secondary, .text-muted: Texto secundário / auxiliar com contraste garantido >= 4.5:1.
  • .text-accent: Destaque com a cor primária da marca.
  • .surface-box, .toolbar-box: Caixas de superfície neutra e barras de ferramentas.

3.3 Testes Automatizados de Guarda-Corpo

O projeto mantém testes unitários automatizados em DesignTokenGuardrailTest e CssColorAndContrastGuardrailTest que:

  1. Fazem varredura estática de todo o código Java da UI para reprovar qualquer setStyle que declare cor ou hexadecimal.
  2. Validam matematicamente a fórmula de luminância relativa WCAG 2.1 para cada par texto/fundo nos dois temas, garantindo conformidade rigorosa.