Ir ao conteúdo
SEED engenharia

Componentes

95. Barra de abas de aplicativo

estávelseed-componentes.md v2.00 · §95seção 181 de 18495-barra-de-abas-de-aplicativo-estavel-decidida-em.md · MD5 460ec71b

Título completo no canon: Barra de abas de aplicativo — estável (decidida em 2026-10-10, quatro respostas dele; marcador da sessão, exposto a veto, MANIFESTO §301; AB11 acrescentada em §302; AB8 emendada e AB12 acrescentada em §309) · AB1–AB12 · LC-17 · pedido PC-2026-0008 · botão flutuante em §1.14 (FB1–FB8, LC-18) · tela de referência tela-shell-abas.html e guarda guarda-barra-abas.mjs no rito desde a leva 36 (ver 95.3)

Contexto para leitor novo. Em tela estreita (celular) o shell esconde o rail numa gaveta (SH12). O SEED Chat pediu, no pedido de cobertura PC-2026-0008 (2026-09-13), uma barra de abas na base da tela e um botão flutuante, "o mais parecido com o WhatsApp original". O decisor aprovou a frente na triagem (MANIFESTO §235.1, verbatim: "PC-2026-0008 (LC-17/LC-18, barra de abas + FAB): aprovo-lc — o meu pedido é que o layout fica o mais parecido com o do whatsapp original porque é mais intuitivo para qualquer usuário utilizar. (…)"). O estudo G9-12 (2026-09-24, base 767babd) está em 09-pesquisa/2026-09-24-grupo-9/lc-abas-fab/ (proposta PROPOSTA-CANON.md, prancha.html, medidas.json, placar-declarado.md, relatorios/G9-12-RELATORIO.md). Prefixos AB (barra) e FB (botão flutuante) — medido em 2026-10-10: 0 ocorrências de **AB<n>** e **FB<n>** como decisão no seed-componentes.md. Siglas: SH decisões do §46 · CP do seed-composicao.md · MA do §93 · NM/IC do §45 · FAB botão flutuante de ação (floating action button) · AX árvore de acessibilidade do navegador.

Veredito dele, verbatim (colado no chat em 2026-10-10 ~01:47Z): "V-AB1 a, V-AB2 b, V-FB1 c, V-FB2 b, veto/observação: nenhum". Significado de cada letra (da prancha.tpl.html do estudo):

pergunta opção dele o que ela diz
V-AB1 a barra só quando o produto tem até 5 áreas (e o nome de cada uma cabe na aba) e não tem a coluna de seções; nos outros casos, como o ERP (6 áreas e seções), continua a gaveta
V-AB2 b peça de vidro clara, com calha e cantos arredondados, e o traço no topo da aba ativa (segue a lei CP1 e o vidro da navegação)
V-FB1 c estendido, com ícone e o nome da ação escrito, 56 de altura; ao rolar, encolhe
V-FB2 b ao descer, esconde o nome e fica só o "+"; ao subir ou voltar ao topo, o nome volta; o botão nunca some

95.1 Decisões AB1–AB11#

# Decisão Porquê (medido ou citado) Descartado
AB1 A barra de abas É O RAIL em tela estreita, não uma região nova. Mesma lista de destinos (uma lista para os dois — achado C36 do SEED Chat), mesmo nome acessível "Áreas" (SH2), mesma marca de ativo (SH5), mesmo papel (SH14). Supersede parcial do SH12 (texto também no próprio SH12): em tela estreita, rail e sidebar colapsam no drawer — EXCETO no produto que satisfaz a régua da AB2, onde o rail vira a barra O SH1 fixa cinco regiões; uma sexta com o mesmo papel do rail quebraria o SH14 por dentro. Medido no estudo: em 21 de 21 capturas com barra, 1 landmark "Áreas" na AX — e com a gaveta aberta por cima da barra, 2 visíveis e 1 exposto (o showModal() deixa o resto inerte) barra como região própria com nome próprio ("Abas") — dois nomes para o mesmo papel
AB2 (V-AB1 a) Régua de escolha barra × drawer: o produto usa a barra quando (i) tem de 3 a 5 destinos de topo, (ii) o rótulo mais largo cabe no item a 360 px (largura do item − 4 px ≥ largura do rótulo, a conta do SH3 transposta), e (iii) não liga a sidebar (SH4) nem o painel de escopo (SH20). Fora disso, o drawer do SH12. Nunca os dois ao mesmo tempo. O ERP (6 áreas e seções) continua na gaveta; o SEED Chat usa a barra Material 3: "Navigation bars can have three to five destinations" (documentação do componente, lida em 2026-09-24). O teto real sai da medida da casa: com "COMERCIAL" (9 caracteres, 67,7 px no papel micro), a 360 px 5 destinos transbordam 1 rótulo nas duas formas (item 67,2 px encostada · 62,4 px peça) e 4 cabem (85 · 79); a 390 px, 5 cabem só na encostada (73,2). Sidebar e escopo não têm lugar na barra: sem o drawer eles ficariam inalcançáveis "Mais" como 5.ª aba abrindo o drawer (V-AB1 b) · nenhuma barra (V-AB1 c) · barra + ☰ ao mesmo tempo (duas navegações com o mesmo papel, SH14) · teto fixo "5" do Material (medido: não cabe a 360 px com os nomes do ERP)
AB3 Limiar: o MESMO degrau do SH12 — 860 px de contêiner app (@container app), nunca de janela. Acima, rail; abaixo, barra CP27: densidade responde ao contêiner; um segundo limiar criaria uma faixa com rail E barra ou com nenhum. O SEED Chat usa hoje md:hidden (768 px de JANELA): entre 768 e 884 px de janela o DS teria drawer/barra e o produto teria rail 768 px de janela (limiar próprio, media query)
AB4 A barra é a ÚLTIMA FAIXA da coluna de conteúdo, EM FLUXO — nunca position: fixed por cima do conteúdo. Respeita a área segura do sistema: padding-bottom: calc(sp-1 + env(safe-area-inset-bottom)) Medido: barra ∩ conteúdo = 0 px² em 21 de 21 capturas → o WCAG 2.4.11 (foco não encoberto, AA; "sticky footers" é o exemplo do texto, revisto em 15/06/2026) passa por construção. O provisório do SEED Chat é fixed e exporta a constante h-16 para as telas descontarem fixed + reserva por tela (cada tela esquece uma vez)
AB5 Item: divide a largura em partes iguais; alvo inteiro ≥ 48 × 48 (sp-12); ícone 24 (IC4 "navegação"); rótulo sempre visível, uma palavra, no papel micro do rail (11 px, caixa alta, tracking do papel), sem quebra; o ícone segue a árvore NM4 (set SEED → Lucide → criar pela régua IC) HIG Tab bars (revisto 08/06/2026): "Include tab labels (…) Use single words whenever possible"; o SH3 já descartou ícone sem rótulo como padrão. Alvo medido 48 px em 21 de 21 (≥ 44 do §1 e do HIG; ≥ 24 do WCAG 2.5.8). O SEED Chat usa ícone 22 px (fora da escala IC4) rótulo só no ativo · ícone 22 · rótulo em caixa de sentença 12 px
AB6 Ativo: aria-current="page" + pílula clara no ITEM inteiro + peso 700 — e, nas formas claras, um traço de 3 px no topo do item em text-brand-strong. No metal, a pílula turquesa-100 bastaria SH5 exige marca que sobrevive ao cinza. Medido: pílula surface-brand-subtle × surface-raised = 1,07 (claro) · 1,20 (escuro) — sem cor o ativo ficava só no negrito, que o SH5 descarta. O traço mede 5,89 (claro) · 6,92 (escuro) sobre a pílula (≥ 3 do 1.4.11); é o mecanismo que a sidebar já usa só a pílula clara nas formas claras (morre no cinza, medido) · pílula de 56 × 32 em volta do ícone do Material
AB7 (V-AB2 b) Forma = PEÇA DE VIDRO sobre o canvas: radius-lg, calha sp-3, vidro da receita vidro (MA1: navegação é vidro), com o traço no topo da aba ativa (AB6). Cumpre o CP1 (nada encosta em nada). A receita vidro ganha um seletor para a barra no material_bloco.py (MA8: receita nova nasce no módulo) iOS atual: "A tab bar floats above content (…) on a Liquid Glass background" (HIG 08/06/2026); MA1; custo de código igual nas três formas encostada nas bordas, surface-raised + borda superior (V-AB2 a — exigiria exceção nomeada no CP1) · peça de metal igual ao rail (V-AB2 c — nenhuma fonte de mercado lida faz assim)
AB8 Selo de contagem = §21 numérico (feedback-danger-solid, número em mono, "99+"), no canto superior do ícone, com o texto completo oculto para o leitor de tela (V4: "12 pendentes"). Só para o que pede atenção HIG: "Reserve badges for critical information"; §21 V4. Contraste por token, o par que a tela já usa: text-on-action-destructive sobre feedback-danger-solid 5,19 (claro: #FFFFFF sobre #C6393B) · 5,26 (escuro: #521112 sobre #FC6F6A), remedido em 2026-10-12 01:33Z a partir de seed-tokens.css. (Folha 6, J3 = a, gravada 2026-10-12 01:02Z, verbatim «J3: a»: a AB8 deixa de citar o literal #0B1419 — 6,75 — e passa ao par de tokens; zero literal de cor na tela.) O SEED Chat cita o TB7 (§34, abas DENTRO de uma tela) como regra do selo — a regra certa é o §21 contador inline ao lado do rótulo
AB9 A barra não some e não desabilita. Não se esconde ao rolar; só fica coberta por diálogo modal. Destino sem permissão continua OMITIDO (SH6); destino temporariamente vazio continua na barra e explica o vazio HIG: "Make sure the tab bar is visible (…)" e "Don't disable or hide tab bar buttons". Não contradiz o SH6: omitir por perfil é permissão, não indisponibilidade barra que se esconde ao descer
AB10 Troca de aba = troca de rota: SH7 (foco no conteúdo + live region) e SH8 (skip link) valem sem mudança É a mesma navegação do rail —
AB11 (folha de 2026-10-10 gravada às 11:22Z, F4c = a; decisão da sessão sobre o texto, exposta a veto) A última aba é "Mais", e a CONTA mora dentro dela. Na barra de abas do celular o destino final é "Mais" (ícone do set, NM4; rótulo de uma palavra, AB5); tocar abre uma folha com o menu de conta — Perfil · Trocar de conta · Tema · Sair, a UNIÃO do que o SH21 põe no avatar da base do rail (Perfil · Tema · Sair) com o «Trocar de conta» desta decisão (folha 6, J2 = b, gravada 2026-10-12 01:02Z, verbatim «J2: b»; antes a lista literal era Perfil · Trocar de conta · Sair e contradizia o SH21, que tem o Tema). O item Tema mostra o valor atual e, a cada toque, passa à próxima opção do SH21 (Claro · Escuro · Seguir o sistema, e volta ao Claro) acionando o MESMO controle do menu de conta — a regra do tema (guardar, aplicar, seguir o sistema) mora num lugar só. "Mais" CONTA no teto da AB2(i): 4 destinos de produto + "Mais" = 5; ou 2 + "Mais" = 3. "Mais" não abre o drawer e não esconde destinos de topo: os destinos de produto continuam nas abas (é o que o separa da opção que a AB2 descartou, "Mais" como 5.ª aba abrindo o drawer, V-AB1 b). Sem permissão de conta, "Mais" é omitido (SH6) e a régua da AB2 conta só os destinos. "Mais" abre FOLHA MODAL que sobe de baixo (folha 3, G4 = a, gravada 2026-10-10 14:45:59Z; descartado: menu curto sobre a aba, G4 b) — diálogo modal com foco preso e Esc/toque fora fechando (o Modal do §30, MD1–MD5, na forma de folha inferior), o item "Mais" com aria-expanded="true" e aria-haspopup="dialog" enquanto aberta; ao fechar, o foco volta ao item. Mesmo alvo ≥ 48 × 48 Fecha a pergunta que a 95.4 deixava aberta ("onde mora o menu de conta no celular quando o produto usa a barra"); SH21 (avatar na base do rail) não existe em tela estreita porque o rail some (AB1); o WhatsApp e o SEED Chat põem a conta fora da lista de conversas avatar de conta no topo da conversa (cada tela esquece) · conta na gaveta do rail (o drawer não existe no produto com barra, AB2) · aba de conta como destino de topo (gasta 1 dos 5)
AB12 (LC-41, folha 6, J5 = b, gravada 2026-10-12 01:02Z, verbatim «J5: b») Um destino de tipo balao (SH22) na barra abre uma FOLHA MODAL inferior IGUAL à do «Mais» (AB11), não um popover. A aba é disclosure de diálogo (aria-haspopup="dialog", aria-expanded, aria-controls para a folha, nunca role="menu"); a folha tem foco preso, véu do §30, Esc e toque no véu fechando, foco de volta à aba e fecha sozinha se a barra some (alargar além de 860 px); as opções vão em lista de itens com alvo ≥ 44 px (as mesmas opções que o rail mostra em balão ao lado — uma declaração, duas formas); a cabeça da folha leva o NOME do destino. Escolhida a opção, a aba do balão fica ATIVA (uma só aba ativa, AB6/SH5) e a folha fecha. O balão conta como UM dos lugares da AB2(i). O painel continua fora da barra (AB2 iii). A emenda ao SH22 (§46.7) vale SÓ para a barra: o rail (acima de 860 px) segue com o balão ao lado, e o drawer (SH12) com o balão do SH12 Estudo da letra f da leva 36 (FOLHA-LC41.md, prancha a 390 × 844, claro e escuro): a folha de 390 × 368 px (44 % da altura) tem o menor alvo de 44 px e reaproveita as oito medidas da folha «Mais» (M1–M8 da guarda-barra-abas, agora parametrizadas); o popover (A) mediu 328 × 192 px e cobriria o botão flutuante em 9.083 px². O abreBalao do SH22 mede rail.right e com o rail oculto (barra) o rail vale 0 popover ancorado acima da aba (A: SH22 intacto, mas cobre o botão flutuante) · opções dentro do «Mais», sem aba do balão (C: perde a aba ativa e muda a AB11) · adiar e permitir só destino direto na barra (D)

95.2 O que mudou no canon por causa desta seção#

  • SH12 (§46.1): ganhou a cláusula da exceção (AB1/AB2), no próprio texto do SH12.
  • CP1 (seed-composicao.md): NÃO muda — a forma escolhida (V-AB2 b, peça) cumpre o CP1; nenhuma exceção a escrever lá.
  • shell_bloco.py / gen-shell.py: a barra será EMITIDA pelo módulo único, ligada por atributo do contêiner app (ex.: data-nav-estreita="abas"); as 11 telas de referência NÃO ligam (todas têm sidebar ou 6 áreas); a tela-shell-sem-topbar ganharia uma cobaia derivada com 4 destinos. Nada disto foi feito nesta leva — pendência a nascer.
  • material_bloco.py: nenhuma receita nova; vidro ganha um seletor (barra) e metal_acao já serve o FAB (MA8).

95.3 Testes (nascem com a seção) e o instrumento#

  1. 1 landmark "Áreas" exposto na AX · 2. 1 aria-current · 3. alvo ≥ 48 · 4. rótulo cabe a 360 px (item − 4 ≥ rótulo) · 5. barra ∩ conteúdo = 0 · 6. a barra aparece a ≤ 860 px de contêiner app e some acima (e o rail faz o inverso) · 7. cinza: a marca do ativo mede ≥ 3 contra o fundo da barra.

O instrumento-base está no estudo: captura.mjs (pasta lc-abas-fab) mede os seis primeiros; o sétimo é conta por token (NÃO medido no pixel). Ainda não é guarda do rito — sem ela a próxima sessão desfaz a escolha sem que nada acuse (gate-e-folha-html.md, lição 16): pendência a nascer.

95.4 O que a seção NÃO cobre, e perguntas que ela abre#

Qual ação é "a principal" de cada tela (produto) · app nativo (fronteira do §46) · o painel lateral direito do ERP/CRM que ele pediu no mesmo PC-2026-0008 (é a forma da MS5, §94). Abertas, sem decisão dele (o SH21 manda o avatar para a base do rail em produto sem topbar, e com a barra o rail some em tela estreita): onde mora o menu de conta no celular quando o produto usa a barra (RESPONDIDA em 2026-10-10, F4c = a: a AB11 — a última aba é "Mais", com a conta dentro); e como um destino de tipo balao ou painel (SH22) se comporta na barra — a AB2(iii) deixa de fora o produto com sidebar, o que cobre o painel; o balao foi RESPONDIDO em 2026-10-12 (folha 6, J5 = b: a AB12 — folha modal inferior igual à do «Mais»).

Esc