a11y(2.4.11): add scroll-padding so sticky overlays don't obscure focused elements#3532
Merged
Conversation
…elements Ensures keyboard-focused items are not hidden behind the top nav, sticky banners, bottom nav, or sticky table headers/footers per SC 2.4.11. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
…line-before errors Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
rosanusi
marked this pull request as ready for review
June 11, 2026 16:35
…commodation-review # Conflicts: # src/lib/holocene/banner/banner.svelte
… destroy
Review follow-ups on the scroll-padding fix:
- app.css: compose --scroll-inset-top/--scroll-inset-bottom per breakpoint.
Mobile has no top-nav (top-nav is `{#if md.current}`) and the banner is
bottom-anchored (`max-md:fixed max-md:bottom-16`), so the previous constant
top inset over-reserved space on mobile and never covered the mobile bottom
banner. Desktop keeps top-nav + banner on top, bottom cleared.
- main-content-container: consume the composed insets; drops the invalid
unitless-0 calc() fallbacks.
- banner: reset --banner-height to 0px on destroy so a stale height can't
inflate scroll-padding-top after navigating away from a page with a banner.
- paginated-table: remove stray blank line in the style attribute.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Contributor
|
Merged
Verified with keyboard nav that the sticky-header padding does fire (a focused row parked under the header gets scrolled clear; without it the browser skips the scroll, thinking the row is already visible). Note it's an upward/Shift+Tab-only, ~1-row effect, so it's easy to miss when Tabbing downward. |
The blank line before the custom property in paginated-table's style attribute is required by stylelint's custom-property-empty-line-before rule; my earlier cosmetic removal broke CI lint.
ardiewen
approved these changes
Jul 10, 2026
rossedfort
added a commit
that referenced
this pull request
Jul 13, 2026
Auto-generated version bump from 2.52.0 to 2.52.1 Bump type: patch Changes included: - [`3be0df00`](3be0df0) fix(schedules): default absent second/minute/hour to 0 when editing (#3653) - [`508b65b7`](508b65b) fix(schedules): default emptied second/minute/hour to 0 on submit (#3655) - [`1f0e149c`](1f0e149) fix(workers): reject $LATEST qualifier in Lambda ARN validation (#3657) - [`b42b0776`](b42b077) a11y(2.4.3): inert-based focus containment + restore; drop trap from native dialogs (#3598) - [`cc491a29`](cc491a2) a11y(2.4.3): keep toast live region announcing during a focus trap [DT-4252] (#3654) - [`ddc7f8e2`](ddc7f8e) a11y(2.4.11): add scroll-padding so sticky overlays don't obscure focused elements (#3532) - [`b7e3a472`](b7e3a47) FilterBar icon update (#3660) - [`09318ec6`](09318ec) Add danger PR comment for api version bump (#3662) - [`273cc4be`](273cc4b) a11y(4.1.2): add label prop to Button primitive and enforce accessible names (#3556) - [`4507115f`](4507115) Use an editable combobox for the Cloud Run region field (DT-4232) (#3636) - [`694a7471`](694a747) a11y(1.4.13): migrate saved-query nav tooltips to Tooltip primitive (#3607) - [`8b384a40`](8b384a4) a11y(4.1.2): fix nested interactive elements in Copyable component (#3558) - [`1bfd2750`](1bfd275) fix describe SANO API requests to include runId parameter (#3661) - [`ba18b43e`](ba18b43) a11y(4.1.2): require label on CodeBlock primitive; add aria-readonly for read-only mode (#3557) - [`6e2290f1`](6e2290f) feat(deployments): make compute provider picker configurable (#3659) - [`4470b76a`](4470b76) fix(workers): persist WDV compute-config edits via update mask; revert $LATEST validation (#3658) - [`17fd591b`](17fd591) fix(nexus-operations): make start standalone nexus operation timeouts optional (#3656) Co-authored-by: rossedfort <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes WCAG 2.2 SC 2.4.11 (Focus Not Obscured — Minimum) across all authenticated routes. ui-main had seven persistent sticky/fixed overlays and zero scroll accommodation — keyboard-focused elements below the fold would auto-scroll flush with the viewport top, placing them entirely behind the top-nav or other overlays.
Root cause:
scroll-padding-topandscroll-padding-bottomwere never applied to any scroll container in the codebase (confirmed via negative grep). The fix is structural: add scroll accommodation to the two scroll contexts where obscuring occurs.Changes:
src/app.css— Adds--banner-height: 0pxand--bottom-nav-height: 4rem(reset to0pxatmdbreakpoint) to:rootso both values are always defined and mobile/desktop behave correctly without JavaScript.src/lib/holocene/main-content-container.svelte— Appliesscroll-padding-top: calc(var(--top-nav-height, 3rem) + var(--banner-height, 0px))andscroll-padding-bottom: var(--bottom-nav-height, 0px)on#content-wrapper. Covers: top-nav (always present), conditional banner stacking, and mobile bottom-nav.src/lib/holocene/banner/banner.svelte— Measures actual banner height viabind:clientHeightand publishes it to--banner-heighton:rootreactively. Resets to0pxwhen banner is dismissed or not shown, keeping the page-levelscroll-padding-topaccurate.src/lib/holocene/table/paginated-table/index.svelte— Appliesscroll-padding-top: var(--table-header-h, 2.25rem)andscroll-padding-bottom: {footerHeight}pxon the table scroll container (nested scroll context).footerHeightis measured live viabind:clientHeighton the sticky footer div. Covers: Holocene Table sticky<thead>and paginated-table sticky footer.Overlays addressed:
src/lib/components/top-nav.svelte:26scroll-padding-topvia--top-nav-height<thead>src/lib/holocene/table/table.svelte:74scroll-padding-topon paginated-table containersrc/lib/holocene/table/paginated-table/index.svelte:65scroll-padding-bottomtracked livesrc/lib/holocene/banner/banner.svelte:19--banner-heightmeasured and stacked into calc()src/lib/components/bottom-nav.svelte:138scroll-padding-bottomvia--bottom-nav-heightsrc/lib/holocene/drawer.svelte:70src/lib/holocene/toaster.svelte:26Screenshots
No visual change at rest. The fix affects scroll position when focusing elements below the viewport fold via keyboard navigation.
Design
N/A — structural CSS fix, no visual design change.
Testing
<thead>--banner-heightresets to0pxand scroll-padding-top shrinks accordinglyscrollIntoView— confirm no regressionChecklist
Docs
No documentation changes required.
A11y-Audit-Ref: 2.4.11-scroll-accommodation-missing