Skip to content

fix(AppShell): auto height mode sidenav and sticky backgrounds - #615

Merged
cixzhang merged 1 commit into
mainfrom
navi/fix/auto-height-sidenav
Mar 14, 2026
Merged

fix(AppShell): auto height mode sidenav and sticky backgrounds#615
cixzhang merged 1 commit into
mainfrom
navi/fix/auto-height-sidenav

Conversation

@cixzhang

Copy link
Copy Markdown
Contributor

Summary

Fixes sidenav not filling height in auto mode and sticky elements being transparent when content scrolls underneath.

Changes

Sticky backgrounds

  • Sticky header and sidenav wrappers get opaque backgrounds based on the shell variant
  • Can't use inherit — the section variant has no intermediate background to inherit from
  • Computed stickyBgStyle uses the nav area background (wash/surface) or falls back to surface

Sidenav height in auto mode

  • Sticky wrapper uses display: flex + flexDirection: column so the panel fills the container
  • Panel gets flex: 1 only in auto mode (via xstyle) to avoid breaking the row-based layout in fill mode
  • 100vh100dvh for the sticky sidenav height calculation

Accessibility

  • Removed duplicate role="navigation" + aria-label from the XDSLayoutPanel wrapper — XDSSideNav already renders as <nav role="navigation" aria-label="Side navigation">, so the panel wrapper was creating a redundant nested landmark

Test plan

  • Tested fill and auto modes in Shell Lab
  • Verified sticky header/sidenav have opaque backgrounds in all four variants (section, wash, surface, elevated)
  • Verified sidenav fills full height in auto mode
  • Verified fill mode sidenav is unaffected

Fixes #604
Part of #565

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Mar 14, 2026
@github-actions

github-actions Bot commented Mar 14, 2026

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

Modified Components

AppShell · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A 625B N/A
Lines of Code N/A 396 -
Complexity N/A Very High (51) -

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@xds/core 9.4KB 15.1KB 2.4KB

Accessibility Audit

Status: No accessibility violations detected.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

Fix sidenav not filling height in auto mode and sticky elements
being transparent when content scrolls underneath.

- Sticky header and sidenav wrappers get opaque backgrounds based
  on the shell variant (not inherit — section variant has no
  intermediate background to inherit from)
- Sidenav sticky wrapper uses display:flex + flexDirection:column
  so the panel fills the container
- Panel gets flex:1 only in auto mode (via xstyle) to avoid
  breaking the row-based layout in fill mode
- Use 100dvh instead of 100vh for sticky sidenav height
- Remove duplicate role=navigation from LayoutPanel — XDSSideNav
  already provides the navigation landmark with aria-label

Fixes #604
Part of #565
@cixzhang
cixzhang force-pushed the navi/fix/auto-height-sidenav branch from 54d9f95 to c88fe63 Compare March 14, 2026 03:34
@cixzhang
cixzhang merged commit d0fda31 into main Mar 14, 2026
12 checks passed
@cixzhang cixzhang mentioned this pull request Mar 14, 2026
@cixzhang
cixzhang deleted the navi/fix/auto-height-sidenav branch March 20, 2026 16:59
cixzhang added a commit that referenced this pull request Apr 26, 2026
Fix sidenav not filling height in auto mode and sticky elements
being transparent when content scrolls underneath.

- Sticky header and sidenav wrappers get opaque backgrounds based
  on the shell variant (not inherit — section variant has no
  intermediate background to inherit from)
- Sidenav sticky wrapper uses display:flex + flexDirection:column
  so the panel fills the container
- Panel gets flex:1 only in auto mode (via xstyle) to avoid
  breaking the row-based layout in fill mode
- Use 100dvh instead of 100vh for sticky sidenav height
- Remove duplicate role=navigation from LayoutPanel — XDSSideNav
  already provides the navigation landmark with aria-label

Fixes #604
Part of #565
ernestt added a commit that referenced this pull request Jun 2, 2026
The header wrapper only received a background in auto mode (via
stickyBgStyle for scroll opacity), while the sidenav panel always
received navAreaStyle. In fill mode (the default), the header was
transparent — relying on the root background showing through. This
caused a visible color mismatch between the top nav and side nav
in the elevated variant due to compositing layer differences.

Fix: apply navAreaStyle unconditionally to the header wrapper,
matching the sidenav panel. Both nav areas now paint their own
background layer identically in all height modes.

Introduced in PR #597 (d0d8fca) which added navAreaStyle to the
panel but only added it to the header for auto mode in PR #615.
ernestt added a commit that referenced this pull request Jun 4, 2026
…es (#2464)

* fix(AppShell): remove explicit navAreaStyle from elevated variant

The elevated variant's root already paints --color-background-body. Both
the header and sidenav should be transparent, letting the root show
through — same as the section variant.

PR #597 (d0d8fca) grouped 'elevated' with 'wash' in the navAreaStyle
condition, giving both an explicit navAreaWash background. This was
unnecessary for elevated (root already has that color) and caused the
header/sidenav to paint on separate layers, which created subtle
rendering inconsistencies between the two nav areas.

Fix: remove 'elevated' from the navAreaStyle condition so both header
and sidenav are transparent. The stickyBgStyle fallback (for auto mode
scroll opacity) now correctly uses navAreaWash for elevated instead of
navAreaSurface.

* fix(AppShell): apply navAreaStyle to header wrapper in all height modes

The header wrapper only received a background in auto mode (via
stickyBgStyle for scroll opacity), while the sidenav panel always
received navAreaStyle. In fill mode (the default), the header was
transparent — relying on the root background showing through. This
caused a visible color mismatch between the top nav and side nav
in the elevated variant due to compositing layer differences.

Fix: apply navAreaStyle unconditionally to the header wrapper,
matching the sidenav panel. Both nav areas now paint their own
background layer identically in all height modes.

Introduced in PR #597 (d0d8fca) which added navAreaStyle to the
panel but only added it to the header for auto mode in PR #615.

* fix(docsite): scope frosted top-nav CSS to outermost shell only

The docsite's translucent top-nav effect (backdrop-filter blur + 80%
transparent background) used bare .xds-top-nav and .xds-layout-header
selectors. These leaked into nested AppShells rendered inside component
examples and template previews, causing their top navs to get the
frosted glass treatment unintentionally.

Scope all affected rules with :not(.xds-app-shell .xds-app-shell) so
they only match the outermost (page-level) shell. Nested shells inside
the content area render with their normal opaque backgrounds.

* fix(docsite): correctly scope frosted top-nav to outermost AppShell

The previous scoping put the nested-shell guard on the outer .xds-app-shell
(`.xds-app-shell:not(.xds-app-shell .xds-app-shell) > .xds-layout .xds-top-nav`),
but the trailing .xds-top-nav was an unrestricted descendant — a nested
AppShell's top nav is still a descendant of the outer layout, so the frost
leaked into component examples and templates.

Move the guard onto the styled element itself via
`:where(:not(.xds-app-shell .xds-app-shell *))`. Any nav with two AppShell
ancestors is excluded and keeps its solid navAreaStyle background, staying
seamless with its sidenav. :where() keeps specificity at (0,1,0) so the
home-page, nav-mode, and theme-preview overrides still win unchanged.
cixzhang added a commit that referenced this pull request Jun 21, 2026
Fix sidenav not filling height in auto mode and sticky elements
being transparent when content scrolls underneath.

- Sticky header and sidenav wrappers get opaque backgrounds based
  on the shell variant (not inherit — section variant has no
  intermediate background to inherit from)
- Sidenav sticky wrapper uses display:flex + flexDirection:column
  so the panel fills the container
- Panel gets flex:1 only in auto mode (via xstyle) to avoid
  breaking the row-based layout in fill mode
- Use 100dvh instead of 100vh for sticky sidenav height
- Remove duplicate role=navigation from LayoutPanel — XDSSideNav
  already provides the navigation landmark with aria-label

Fixes #604
Part of #565
cixzhang pushed a commit that referenced this pull request Jun 21, 2026
…es (#2464)

* fix(AppShell): remove explicit navAreaStyle from elevated variant

The elevated variant's root already paints --color-background-body. Both
the header and sidenav should be transparent, letting the root show
through — same as the section variant.

PR #597 (d78a5d0) grouped 'elevated' with 'wash' in the navAreaStyle
condition, giving both an explicit navAreaWash background. This was
unnecessary for elevated (root already has that color) and caused the
header/sidenav to paint on separate layers, which created subtle
rendering inconsistencies between the two nav areas.

Fix: remove 'elevated' from the navAreaStyle condition so both header
and sidenav are transparent. The stickyBgStyle fallback (for auto mode
scroll opacity) now correctly uses navAreaWash for elevated instead of
navAreaSurface.

* fix(AppShell): apply navAreaStyle to header wrapper in all height modes

The header wrapper only received a background in auto mode (via
stickyBgStyle for scroll opacity), while the sidenav panel always
received navAreaStyle. In fill mode (the default), the header was
transparent — relying on the root background showing through. This
caused a visible color mismatch between the top nav and side nav
in the elevated variant due to compositing layer differences.

Fix: apply navAreaStyle unconditionally to the header wrapper,
matching the sidenav panel. Both nav areas now paint their own
background layer identically in all height modes.

Introduced in PR #597 (d78a5d0) which added navAreaStyle to the
panel but only added it to the header for auto mode in PR #615.

* fix(docsite): scope frosted top-nav CSS to outermost shell only

The docsite's translucent top-nav effect (backdrop-filter blur + 80%
transparent background) used bare .xds-top-nav and .xds-layout-header
selectors. These leaked into nested AppShells rendered inside component
examples and template previews, causing their top navs to get the
frosted glass treatment unintentionally.

Scope all affected rules with :not(.xds-app-shell .xds-app-shell) so
they only match the outermost (page-level) shell. Nested shells inside
the content area render with their normal opaque backgrounds.

* fix(docsite): correctly scope frosted top-nav to outermost AppShell

The previous scoping put the nested-shell guard on the outer .xds-app-shell
(`.xds-app-shell:not(.xds-app-shell .xds-app-shell) > .xds-layout .xds-top-nav`),
but the trailing .xds-top-nav was an unrestricted descendant — a nested
AppShell's top nav is still a descendant of the outer layout, so the frost
leaked into component examples and templates.

Move the guard onto the styled element itself via
`:where(:not(.xds-app-shell .xds-app-shell *))`. Any nav with two AppShell
ancestors is excluded and keeps its solid navAreaStyle background, staying
seamless with its sidenav. :where() keeps specificity at (0,1,0) so the
home-page, nav-mode, and theme-preview overrides still win unchanged.
cixzhang added a commit that referenced this pull request Jun 21, 2026
Fix sidenav not filling height in auto mode and sticky elements
being transparent when content scrolls underneath.

- Sticky header and sidenav wrappers get opaque backgrounds based
  on the shell variant (not inherit — section variant has no
  intermediate background to inherit from)
- Sidenav sticky wrapper uses display:flex + flexDirection:column
  so the panel fills the container
- Panel gets flex:1 only in auto mode (via xstyle) to avoid
  breaking the row-based layout in fill mode
- Use 100dvh instead of 100vh for sticky sidenav height
- Remove duplicate role=navigation from LayoutPanel — XDSSideNav
  already provides the navigation landmark with aria-label

Fixes #604
Part of #565
cixzhang pushed a commit that referenced this pull request Jun 21, 2026
…es (#2464)

* fix(AppShell): remove explicit navAreaStyle from elevated variant

The elevated variant's root already paints --color-background-body. Both
the header and sidenav should be transparent, letting the root show
through — same as the section variant.

PR #597 (9237ea5) grouped 'elevated' with 'wash' in the navAreaStyle
condition, giving both an explicit navAreaWash background. This was
unnecessary for elevated (root already has that color) and caused the
header/sidenav to paint on separate layers, which created subtle
rendering inconsistencies between the two nav areas.

Fix: remove 'elevated' from the navAreaStyle condition so both header
and sidenav are transparent. The stickyBgStyle fallback (for auto mode
scroll opacity) now correctly uses navAreaWash for elevated instead of
navAreaSurface.

* fix(AppShell): apply navAreaStyle to header wrapper in all height modes

The header wrapper only received a background in auto mode (via
stickyBgStyle for scroll opacity), while the sidenav panel always
received navAreaStyle. In fill mode (the default), the header was
transparent — relying on the root background showing through. This
caused a visible color mismatch between the top nav and side nav
in the elevated variant due to compositing layer differences.

Fix: apply navAreaStyle unconditionally to the header wrapper,
matching the sidenav panel. Both nav areas now paint their own
background layer identically in all height modes.

Introduced in PR #597 (9237ea5) which added navAreaStyle to the
panel but only added it to the header for auto mode in PR #615.

* fix(docsite): scope frosted top-nav CSS to outermost shell only

The docsite's translucent top-nav effect (backdrop-filter blur + 80%
transparent background) used bare .xds-top-nav and .xds-layout-header
selectors. These leaked into nested AppShells rendered inside component
examples and template previews, causing their top navs to get the
frosted glass treatment unintentionally.

Scope all affected rules with :not(.xds-app-shell .xds-app-shell) so
they only match the outermost (page-level) shell. Nested shells inside
the content area render with their normal opaque backgrounds.

* fix(docsite): correctly scope frosted top-nav to outermost AppShell

The previous scoping put the nested-shell guard on the outer .xds-app-shell
(`.xds-app-shell:not(.xds-app-shell .xds-app-shell) > .xds-layout .xds-top-nav`),
but the trailing .xds-top-nav was an unrestricted descendant — a nested
AppShell's top nav is still a descendant of the outer layout, so the frost
leaked into component examples and templates.

Move the guard onto the styled element itself via
`:where(:not(.xds-app-shell .xds-app-shell *))`. Any nav with two AppShell
ancestors is excluded and keeps its solid navAreaStyle background, staying
seamless with its sidenav. :where() keeps specificity at (0,1,0) so the
home-page, nav-mode, and theme-preview overrides still win unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant