Devafusion.net

Engineering log

Fixed the footer Accessibility panel overflowing off-screen on mobile viewports

The footer's 'Accessibility' disclosure panel (ThemeSelector) used a plain w-max width with no viewport cap, anchored absolute right-0 against its trigger button. On a narrow mobile viewport (reported on a Pixel 9, 412px wide) the panel grew wider than the screen and overflowed off both edges, with button labels clipped and no way to scroll it back into view - the control was effectively unusable on mobile. Capped the panel's width to the viewport, added a max-height with vertical scroll as a safety net, and let each control row wrap instead of forcing one unbreakable line.

Decisions

  • Capped the panel to w-[calc(100vw-2rem)] max-w-sm rather than a fixed px width - this keeps the existing desktop sizing (max-w-sm is close to the prior effective width there) while guaranteeing the panel never exceeds the viewport on any screen size, without needing a separate mobile-only breakpoint rule.
  • Added max-h-[70vh] overflow-y-auto as a safety net alongside the width cap, rather than relying on width alone - a short mobile viewport (landscape, or a visitor with the AAA 44px touch-target/accessible-xl text-size opt-ups both active) could still make the stacked content taller than the screen even once it's no longer too wide.
  • Added flex-wrap to each control row (colour theme, text size, touch-target size) so buttons reflow onto a second line inside the now width-capped panel instead of staying forced into one row that would otherwise re-introduce the same overflow the width cap was meant to fix.

Milestones

  • src/web/components/theme/theme-selector.tsx: #a11y-panel's className changed from w-max to w-[calc(100vw-2rem)] max-w-sm max-h-[70vh] overflow-y-auto; flex-wrap added to the colour-theme, text-size, and touch-target-size control rows.

Validation

  • npm run test:unit -- theme-selector: all 14 existing tests pass unchanged (no behavioural change, only layout classes).
  • Confirmed the panel is rendered with className="hidden" by default (isOpen=false), so this change has zero effect on home-layout.visual.spec.ts's full-page baseline screenshot of the closed default state - not re-run against the pinned Playwright Docker image since no visible pixels change in that state.

This site uses Google Analytics to understand traffic. See the privacy and cookies page for details.