flutter-overflow-guard — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited flutter-overflow-guard (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Overflow nao e um bug aleatorio — e o resultado previsivel de um filho querendo mais espaco do que o pai permite, num pai que nem rola nem corta. Quando voce domina o modelo de constraints do Flutter, da pra prevenir quase todo overflow na hora de escrever o widget, diagnosticar o que sobra em segundos, e provar com teste automatizado que a tela nao estoura em nenhum tamanho de device, densidade de texto ou orientacao.
Esta skill cobre esses quatro momentos — prevenir, diagnosticar, corrigir, verificar — com rigor sub-atomico. Use o que a situacao pedir: o modelo mental resolve 80% sozinho; as fases, o checklist e o formato de saida garantem que os outros 20% (e os casos de borda) nao escapem.
Esta skill tem arquivos de apoio que JA EXISTEM na pasta. Continue apontando para eles: -references/patterns.md— catalogo de prevencao com antes/depois por cenario. -references/diagnosis.md— procedimento completo de diagnostico + familia de erros de unbounded. -references/testing.md— harness de teste, scanner, golden, lints, debug e CI. -scripts/scan_overflow_risks.py— scanner heuristico (Python 3, nao precisa do Flutter SDK). -assets/overflow_guard.dart— helper de teste pra colar emtest/; expoeexpectNoOverflow(...).
Ao ativar esta skill, voce assume simultaneamente:
Expanded resolve e quando esconde o problema, e nunca crava height: 812 esperando que sobreviva ao proximo device.textScaler grande (usuario com fonte aumentada), contraste, RTL, leitores de tela. Overflow que so aparece com fonte 200% e bug de acessibilidade real, nao "edge case".Tom: tecnico, direto, fundamentado em evidencia do codigo e do runtime real. Voce NUNCA da conselho generico ("use boas praticas de layout") sem o como concreto — widget, propriedade, exemplo antes/depois e como verificar.
Ative esta skill quando QUALQUER um destes for verdade:
Row, Column, Flex, ListView/GridView, Form/TextField, Dialog/AlertDialog, BottomSheet, ou layout responsivo.A RenderFlex overflowed by N pixels), uma excecao de unbounded, ou a barra listrada amarelo/preto.Se nenhum gatilho se aplica (ex.: pergunta sobre estado, navegacao, animacao sem componente de layout), esta skill provavelmente nao e a ferramenta certa — diga isso em vez de forcar.
Layout no Flutter e uma frase de tres partes: constraints descem, tamanhos sobem, o pai posiciona. O pai passa restricoes (min/max de largura e altura) pro filho; o filho escolhe seu tamanho dentro delas; o pai decide onde colocar.
Overflow acontece quando essa negociacao falha de um jeito especifico:
maxWidth/maxHeight que o pai deu, o RenderFlex pinta a barra listrada e avisa no console: A RenderFlex overflowed by N pixels on the right/bottom. Ninguem rola, ninguem corta — entao transborda.Expanded obriga a preencher (FlexFit.tight); Flexible permite ficar menor (FlexFit.loose). E por isso que colocar Expanded num filho que estava estourando some com o overflow: ele para de pedir o tamanho do conteudo e passa a aceitar o que sobrou.SingleChildScrollView, ListView e um Row sem Expanded dao ao filho espaco infinito no eixo de rolagem. Ai um Expanded la dentro nao consegue calcular "a fracao do infinito" e voce toma um erro diferente (unbounded height, non-zero flex but incoming constraints are unbounded) — mesma familia, causa irma.Regra de bolso: antes de escrever um `Row` ou `Column`, pergunte "e se o conteudo for grande demais pra caber?" A resposta determina o widget:
SingleChildScrollView (uma tela) ou ListView (lista).Expanded / Flexible.Wrap no lugar de Row.FittedBox (com parcimonia — pode deixar ilegivel).maxLines + overflow: TextOverflow.ellipsis, e largura limitada (Flexible/Expanded).SingleChildScrollView em volta do corpo (e confira resizeToAvoidBottomInset).Internalize isto antes de escrever qualquerFlex. A causa nº 1 de overflow horizontal e umRowcom variosTextonde ninguem decidiu, na escrita, entreExpanded,Wrapeellipsis.
Execute na ordem. Cada fase tem um gate: nao avance sem cumprir a condicao de saida. Pule fases que claramente nao se aplicam (ex.: em UI nova, comece na Fase A; num bug ja relatado, comece na Fase B), mas nunca pule a Fase D (provar).
Aplique o modelo mental ao escrever. Para cada Row/Column/lista/form, declare na hora a estrategia de overflow (rolar / dividir / quebrar / encolher / truncar). Consulte `references/patterns.md` para o antes/depois do cenario.
Flex com Text tem uma estrategia explicita (Expanded+ellipsis, Wrap, ou justificativa de por que cabe sempre). Toda lista dentro de Column tem limite de altura. Todo form tem scroll no corpo.Detalhe completo em `references/diagnosis.md`, incluindo a familia de erros de constraint ilimitada.
Aplique a correcao de primeira escolha (tabela da Secao 5; exemplos em patterns.md). Prefira Expanded/Flexible/Wrap/SingleChildScrollView a FittedBox e a alturas/larguras fixas chutadas. Se voce se pegar escrevendo height: 812, pare e pergunte qual e a intencao real.
Overflow e silencioso em release e facil de nao notar num device so. Prove em camadas:
python3 scripts/scan_overflow_risks.py lib/ como pre-filtro.assets/overflow_guard.dart pra test/ e escreva expectNoOverflow(...) multi-tamanho (e simulateKeyboard: true para forms). Rode flutter test.debugPaintSizeEnabled, Flutter Inspector, console.Detalhes e CI em `references/testing.md`.
textScaler grande e teclado quando aplicavel. "Rodei e nao vi a barra" NAO satisfaz este gate.Va direto aqui ao consertar. Se o caso for ambiguo ou faltar a mensagem, leia references/diagnosis.md.
| Sintoma (mensagem / observacao) | Causa provavel | Correcao de primeira escolha |
|---|---|---|
overflowed ... on the right num Row | filhos mais largos que a linha | Expanded/Flexible no(s) filho(s) elastico(s); Text longo ganha maxLines + ellipsis; ou troque Row por Wrap |
overflowed ... on the bottom num Column | filhos mais altos que a viewport | SingleChildScrollView em volta; ou Expanded no filho que deve esticar |
bottom overflowed by N so ao digitar | teclado reduz o corpo do Scaffold | SingleChildScrollView no corpo; confira resizeToAvoidBottomInset: true |
Vertical viewport was given unbounded height | Column/scroll sem altura limitada | de altura (Expanded, SizedBox) ou shrinkWrap: true na lista interna |
non-zero flex but incoming ... constraints are unbounded | Expanded/Flexible dentro de eixo ilimitado | tire o Expanded, ou de tamanho ao pai / use mainAxisSize: MainAxisSize.min |
texto cortado / ... sumido | sem tratamento de overflow no Text | maxLines + TextOverflow.ellipsis + largura limitada (Flexible) |
| imagem estoura o container | imagem sem restricao de tamanho | SizedBox/AspectRatio + BoxFit; ou Expanded |
| so estoura com fonte grande (acessibilidade) | layout assume textScaler 1.0 | Flexible/Wrap/scroll; nunca fixe altura por contagem de linhas; teste com textScaler 1.3–2.0 |
| so estoura em RTL / outro idioma | label traduzida mais comprida; espelhamento | testar Directionality(textDirection: TextDirection.rtl); Expanded+ellipsis; evitar largura fixa por idioma |
| conteudo cortado no topo/baixo (notch/barra) | falta SafeArea | envolver em SafeArea (nao e overflow de RenderFlex, mas o usuario reclama igual) |
Principio ao corrigir: prefira Expanded/Flexible/Wrap/SingleChildScrollView a FittedBox e a alturas fixas chutadas. Largura/altura fixa "resolve" no seu device e estoura no proximo.
Antes de declarar uma tela "sem overflow", percorra TUDO. Marque cada item como OK / FALHA / N/A com evidencia (qual teste, qual tamanho).
Eixos e flex
Row com Text/conteudo variavel tem filho flexivel ou estrategia de quebra/scroll explicita.Column mais alto que a tela rola (SingleChildScrollView) ou tem Expanded no filho elastico.Expanded/Flexible/Spacer dentro de SingleChildScrollView/Wrap/eixo ilimitado.ListView/GridView dentro de Column tem limite de altura (Expanded ou SizedBox).Densidade de texto e dados de borda
Text em Row tem maxLines + overflow: TextOverflow.ellipsis.Tamanhos e orientacao de device
Fontes grandes / acessibilidade
textScaler aumentado (1.3, 1.5, 2.0) — usuario com fonte grande.Internacionalizacao
TextDirection.rtl) nao corta nem espelha errado.Tema e ambiente
SafeArea/notch/barra de status — conteudo de borda a borda nao e cortado.simulateKeyboard: true) — form rola, botao acessivel, nada estoura embaixo.Estados da tela
Prova
expectNoOverflow que falha sem a correcao e passa com ela.flutter analyze + flutter test (bloqueante).Quando esta skill for usada para auditar uma tela/projeto (em vez de corrigir um unico bug), classifique cada achado:
Critica (estoura/crash em device comum ou no caminho feliz) · Alta (estoura em device pequeno, fonte grande, RTL ou teclado) · Media (so em combinacao rara de dados+tamanho) · Baixa (cosmetico, ou risco potencial sem repro confirmado).Confirmada (tem repro/teste que falha) · Provavel (analise estatica/leitura forte) · Hipotese (heuristica do scanner, precisa confirmar). Achado sem evidencia e Hipotese — rotule como tal.Trivial (uma linha: ellipsis/Expanded) · Pequeno (envolver em scroll, ajustar arvore) · Medio (refatorar layout responsivo) · Grande (repensar a tela).Quando esta skill produzir uma auditoria/diagnostico, estruture a saida EXATAMENTE assim:
2–5 frases: quantos achados, severidade dominante, e se a tela esta apta a ship. Sem rodeios.
[ID] Titulo curto do problema
- Local: caminho/arquivo.dart:LINHA (widget culpado)
- Severidade: Critica | Alta | Media | Baixa
- Confianca: Confirmada | Provavel | Hipotese
- Esforco: Trivial | Pequeno | Medio | Grande
- Causa: por que estoura (eixo, qual filho, qual constraint falha)
- Correcao: o widget/propriedade certo e por que
- Antes:
<trecho real / minimo do codigo problematico>
- Depois:
<trecho corrigido>
- Como verificar: teste/condicao que prova o conserto (tamanho, textScaler, teclado)| ID | Local | Severidade | Confianca | Esforco | Correcao em 1 linha |
|---|
Lista ordenada por prioridade (Critica/Alta primeiro; dentro do mesmo nivel, menor esforco primeiro). Agrupe correcoes triviais que dao pra fazer juntas.
A Secao 6 marcada para a(s) tela(s) auditada(s), com o tamanho/condicao que comprovou cada item.
Regra de saida: nunca mostre apenas codigo que funciona no device atual. Todo "Depois" precisa de um "Como verificar" que cubra pelo menos um tamanho menor e, quando texto/teclado/i18n estiverem envolvidos, a condicao correspondente.
Expanded so funciona como filho direto de Row/Column/Flex. Dentro de um SingleChildScrollView ou Wrap ele da erro — porque ali nao existe "espaco restante" definido. Releia o modelo mental (Secao 3).ListView constroi todos os filhos de uma vez. Use so pra listas curtas conhecidas; pra lista de verdade dentro de uma coluna, use Expanded em volta do ListView.Row, mas sao caros (podem ser O(n²)). Use pontualmente, nao como habito.SafeArea em telas de borda a borda.Expanded, FractionallySizedBox, LayoutBuilder ou tokens de spacing.BoxFit.scaleDown; prefira Expanded+ellipsis quando truncar e aceitavel.Spacer = Expanded de espaco; nao existe "espaco restante" num SingleChildScrollView. Troque por SizedBox(height: ...).LayoutBuilder pras constraints reais do pai; use MediaQuery.sizeOf/viewInsetsOf/paddingOf (menos rebuild) quando precisar de tela/insets.SingleChildScrollView > Column > Expanded(ListView)). Conflito de scroll/altura. Escolha uma estrategia: Expanded(ListView) ou lista shrinkWrap curta dentro do scroll externo, nunca os dois.Antes de entregar qualquer diagnostico/correcao, confirme:
references/*.md), do scanner (scripts/...) ou do harness (assets/overflow_guard.dart).ellipsis nao precisa de relatorio de 8 secoes.O principio subjacente do Flutter — constraints descem, tamanhos sobem, o pai posiciona; overflow = filho pede mais do que o pai da, num container que nem rola nem corta — e universal em UI. O Flutter e a ancora; aqui esta como o mesmo principio aparece em outras stacks, pra que o engenheiro de qualquer ecossistema extraia valor sem perder a afiacao Flutter.
Row/Column -> outras stacks)| Conceito Flutter | CSS (Flexbox/Grid) | React Native | SwiftUI | Jetpack Compose / Android Views |
|---|---|---|---|---|
Expanded (preenche o resto) | flex: 1 num flex item | style={{ flex: 1 }} | .frame(maxWidth: .infinity) / Spacer() | Modifier.weight(1f) / layout_weight |
Flexible(fit: loose) | flex: 0 1 auto | flexShrink: 1 | .layoutPriority() baixo | Modifier.weight(1f, fill = false) |
Wrap (quebra linha) | flex-wrap: wrap / Grid auto-fill | sem nativo: usar lib de wrap/Grid | WrapLayout (iOS 16 Layout) / LazyVGrid | FlowRow/FlowColumn (Compose) |
Texto: maxLines+ellipsis | overflow: hidden; text-overflow: ellipsis; white-space: nowrap (ou -webkit-line-clamp) | numberOfLines={1} | .lineLimit(1) + .truncationMode(.tail) | maxLines = 1, overflow = TextOverflow.Ellipsis |
FittedBox(scaleDown) | clamp()/min() em font-size; transform: scale | adjustsFontSizeToFit (Text) | .minimumScaleFactor(0.5) | AutoSize/medir e ajustar |
A armadilha CSS que e o irmao gemeo do `Expanded`-em-Row: um flex item nao encolhe abaixo do seu conteudo por padrao porque min-width: auto. Texto longo "estoura" o flex container exatamente como um Text sem Expanded num Row. A correcao canonica e min-width: 0 (ou min-height: 0 no eixo coluna) no item flexivel + overflow: hidden — o equivalente CSS de dar ao filho permissao pra ceder espaco. Em Grid, use minmax(0, 1fr) em vez de 1fr.
| Flutter | CSS | React Native | SwiftUI | Compose |
|---|---|---|---|---|
SingleChildScrollView | overflow: auto/scroll num container com altura limitada | <ScrollView> | ScrollView | Modifier.verticalScroll() |
ListView/GridView (virtualizado) | virtual list / content-visibility | <FlatList>/<SectionList> | List/LazyVStack | LazyColumn/LazyGrid |
Lista dentro de Column precisa de altura | flex child precisa de min-height: 0 pra rolar dentro de flex pai | flex: 1 no container da lista | frame/Spacer | Modifier.weight(1f) no container |
Principio comum: algo que rola precisa de um limite no eixo de rolagem. O Vertical viewport was given unbounded height do Flutter e o mesmo bug que, em CSS, faz um overflow: auto nunca rolar porque o pai flex nao tem min-height: 0 — o container cresce em vez de limitar e rolar.
| Flutter | CSS/Web | React Native | SwiftUI | Compose |
|---|---|---|---|---|
SingleChildScrollView + resizeToAvoidBottomInset + viewInsetsOf | env(keyboard-inset-height), 100dvh, visualViewport API | KeyboardAvoidingView | .ignoresSafeArea(.keyboard) ajuste / ScrollView | Modifier.imePadding() + scroll |
| Flutter | CSS | React Native | SwiftUI | Compose |
|---|---|---|---|---|
SafeArea / MediaQuery.paddingOf | env(safe-area-inset-*) + viewport-fit=cover | SafeAreaView / useSafeAreaInsets | safe area por padrao | Modifier.safeDrawingPadding() / WindowInsets |
| Flutter | CSS | React Native | SwiftUI | Compose |
|---|---|---|---|---|
LayoutBuilder (constraints do pai) | Container Queries (@container) / media queries | onLayout + medir | GeometryReader / size classes | BoxWithConstraints |
FractionallySizedBox(widthFactor) | width: 80% / fr units | width: '80%' | .frame(width: proxy.size.width * 0.8) | fracao de maxWidth |
| Flutter | CSS / Web | iOS / Android |
|---|---|---|
ThemeData, Theme.of(context), TextTheme, MediaQuery.textScaler | CSS custom properties (--space-4), clamp(), Tailwind config (theme scale), Material/Chakra theming | iOS Dynamic Type, Android sp/dimens, Material 3 tokens |
Principio comum (anti numero magico): tamanho fixo e divida tecnica em qualquer stack. Tokens/escala (spacing, breakpoints, tipografia) + unidades relativas (fr, %, dvh, sp, rem, clamp()) deixam o layout sobreviver a outro device, fonte grande e idioma. O height: 812 do Flutter, o height: 100vh que ignora a barra do mobile, o numberOfLines ausente do RN, o .fixedSize() errado do SwiftUI e o width = 360.dp do Compose sao o mesmo erro vestindo roupas diferentes.
Como verificar em qualquer stack (a regra de ouro transversal): teste no tamanho menor plausivel, com o dado mais longo, na maior densidade de fonte e no idioma mais comprido — automatizado, nao "olhei no meu monitor". Web: responsive mode + zoom de fonte. RN/Flutter: widget/component test multi-size + escala de fonte. SwiftUI: previews com size classes e Dynamic Type. Compose: @Preview com fontScale e widthDp.
references/patterns.md. Decida a estrategia de overflow antes de escrever o Flex.references/diagnosis.md se ambiguo.scripts/scan_overflow_risks.py + assets/overflow_guard.dart + references/testing.md.unbounded height/width, non-zero flex, forces an infinite). Leia quando o caso for ambiguo.flutter analyze/lints, widget test multi-tamanho, golden), ferramentas de debug e CI. Leia ao montar a verificacao.python3 scripts/scan_overflow_risks.py lib/ (ou --json pra CI). E pre-filtro, nao verdade absoluta — confirme com a Camada 3.test/; expoe expectNoOverflow(tester, widget, {sizes, simulateKeyboard}) que pumpa em varios tamanhos e falha se algum disparar overflow.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.