Přeskočit na obsah

Sticky save bar překryje sekci — funkčně OK, UX rozbité

import { Aside } from ‘@astrojs/starlight/components’;

Formulář s několika sekcemi (např. „Firma”, „Fakturace a ceny”, „Sklad a příjem”, …) má dole sticky bottom-0 save bar přes celou šířku. Uživatel vidí:

  • ✅ Horní sekce viditelné a použitelné
  • Sekce v oblasti bottom baru zcela chybí — např. „Sklad a příjem” jen s hlavičkou, obsah nikde
  • ✅ Save funguje (data se ukládají do DB — Playwright/API test zelený)

Uživatel si toggle / input v „skrytém” místě prostě nevšimne a nikdy ho nezapne. Bug reportovaný jako „nefunguje toggle X” — ale toggle funguje, jen ho není vidět.

// Původní layout:
<div className="space-y-5">
<Section title="Firma"></Section>
<Section title="Fakturace"></Section>
<Section title="Sklad a příjem"></Section> {/* <— tahle se skryje */}
<Section title="Zobrazení"></Section>
<Section title="Banka"></Section>
{/* Sticky save bar */}
<div className="sticky bottom-0 -mx-4 bg-white border-t px-4 py-3">
<button>Uložit</button>
</div>
</div>

Sticky element:

  • bg-white (neprůhledný)
  • Roste přes celou šířku (-mx-4)
  • Je poslední child → sticky ho drží u dolního okraje viewportu
  • Sekce nad ním, které padnou do jeho geometrické oblasti, jsou vizuálně pod ním (překryty)

Full-page screenshot to nezachytí, protože fixed/sticky ve full-page renderu se vykreslí na svém dokumentovém místě (uvnitř toku), ne na reálné viewport pozici při scrollu.

Responsive FAB pattern — floating na desktopu vpravo dole, inline full-width na mobilu:

{/* Mobile: inline na konci formuláře, full-width */}
<div className="flex items-center justify-end gap-3 pt-2 sm:hidden">
<button
onClick={save}
className="inline-flex w-full items-center justify-center gap-2 rounded-xl
bg-blue-600 px-5 py-3 text-sm font-medium text-white">
Uložit
</button>
</div>
{/* Desktop: fixed floating vpravo dole, kompaktní */}
<div className="pointer-events-none fixed bottom-0 right-0 z-40 hidden p-6 sm:flex">
<div className="pointer-events-auto flex items-center gap-3 rounded-2xl border
border-slate-200 bg-white/95 px-4 py-3 shadow-lg backdrop-blur-sm">
<button onClick={save}>Uložit</button>
</div>
</div>

Klíčové:

  • pointer-events-none na wrapperu + pointer-events-auto na inner boxu — click-through mimo tlačítko
  • bg-white/95 backdrop-blur-sm — obsah pod je vidět, ale button je čitelný
  • hidden sm:flex / sm:hidden — bez JS detekce, pure Tailwind

Jak se tomu vyvarovat v jiných systémech

Sekce “Jak se tomu vyvarovat v jiných systémech”
  • Detection preemptive:

    • Grep pro sticky bottom-0 s bg-white|bg-slate-50|bg-slate-100|bg-neutral — pokud se najde, hrozí ten pattern.
    • Playwright screenshot test s fullPage: false (viewport-only) po každém formulářovém deployi.
    • Test scroll: page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) + screenshot — pozice fixed prvků.
  • Anti-pattern:

    • Sticky element s neprůhledným pozadím na full-width, který má výšku větší než padding-bottom parenta.
    • fullPage: true screenshot jako jediný důkaz „vypadá to OK” — nezachytí layered fixed/sticky problémy.
    • Testy jen na desktopu 1920px — mobil má jiné breakpointy a jiné layouts.
  • Lepší přístupy:

    • Floating Action Button (FAB) v rohu (Material Design pattern) — nezasahuje do toku
    • Sticky bar s padding-bottom roven výšce baru na parentu → obsah nikdy nepadne pod něj
    • Sticky bar s backdrop-blur + bg-white/80 → obsah pod ním prosvítá, uživatel ví že tam něco je
  • E2E test:

    await page.setViewportSize({ width: 1440, height: 900 });
    await page.goto("/formular");
    await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
    await page.screenshot({ fullPage: false, path: "form-scrolled.png" });
    // Manuální revize screenshotu — každá sekce viditelná?

Sister bugs / související

Sekce “Sister bugs / související”
Přidal aiarchitekt.cz · 11. 6. 2026 2:00
Provozuje aiarchitekt.cz