Skip to content

Fix header collisions and the mobile menu - #542

Merged
zieka merged 7 commits into
masterfrom
fix/header-mobile-collisions
Sep 2, 2026
Merged

Fix header collisions and the mobile menu#542
zieka merged 7 commits into
masterfrom
fix/header-mobile-collisions

Conversation

@zieka

@zieka zieka commented Sep 2, 2026

Copy link
Copy Markdown
Member

Problem

  • The header overlapped itself at narrow widths, and the mobile menu was broken in two separate ways (Mobile menu transparent #541).
  • Between 997px and roughly 1180px — 1024px laptops and iPads — the absolutely centred search field and colour-mode toggle rendered on top of the GitHub / Slack / Discord / Moderne docs links.
  • On a phone the wordmark's fixed widths (312px, 220px under 768px) pushed the search button and colour-mode toggle past the right edge, and theme-classic's own mobile rule then positioned the search field on top of the toggle.
  • Opening the menu on a phone gave a transparent panel with the page legible through it (Mobile menu transparent #541).
  • Away from a doc page the drawer listed nothing but the four off-site links: the section nav is hidden below 997px and the drawer's second level only exists where a sidebar does, leaving no route into the docs.
  • Every embedded video ran off the side of the viewport below 640px, because react-player writes its size inline as 640x360.

Objectives

  1. Keep the navbar to a single row with nothing overlapping, at any viewport width.
  2. Make the mobile drawer opaque.
  3. Give the mobile drawer the top-level navigation the section nav provides on desktop.
  4. Keep video embeds inside the page on a phone.
Assumptions
  • Site CSS is emitted after Infima. The existing .navbarRight flex override already depends on this; min-width: max-content beats .navbar__items { min-width: 0 } on the same basis.
  • The wordmark is the right thing to shrink — it is the widest item in the row and the only elastic one. It reaches ~124px at a 320px viewport, small but legible.
  • theme-classic's <NavbarSearch> wrapper contributes nothing except the class that positions the field, so dropping it is preferable to overriding a hashed class name.
  • findSection is the one matcher for "which section is the reader in". A URL prefix cannot answer it: Lists and Reference both serve documents from /reference, and Concepts is served at /concepts-explanations while its documents live at /concepts-and-explanations.
  • The drawer's second level (the doc sidebar, reached via "Back to main menu") stays exactly as Docusaurus renders it; only the first level changes.
  • All twelve pages that embed video use 16:9 YouTube URLs.
Changes
  • (1) src/theme/Navbar/Content/styles.module.css: the centre zone is laid out in flow, with both side zones on an equal share (flex: 1), which lands it on the same midline the absolute positioning targeted. The right zone holds at min-width: max-content so the links never spill leftwards.
  • (1) src/theme/Navbar/Content/index.tsx: renders <SearchBar /> directly instead of through <NavbarSearch>, so upstream's mobile position: absolute never applies; drops the now-redundant mobileControls wrapper and renders the centre zone conditionally.
  • (1) src/css/custom.css: .navbar__logo becomes elastic (flex: 0 1 auto, min-width: 0, object-fit: contain) and the two fixed-width media queries go away.
  • (2) src/css/custom.css: .navbar-sidebar re-points --ifm-navbar-background-color rather than setting background-color, so anything else in the drawer reads the same ground.
  • (3) src/theme/Navbar/MobileSidebar/PrimaryMenu/: new swizzle listing the sections above the navbar items, marked active by findSection and closing the drawer on click.
  • (3) src/config/navSections.ts: adds mobileSections, derived from primarySections with the Releases dropdown flattened to its index page; finishes the ALL_RELEASES_HREF constant so /changelog has one definition.
  • (4) src/css/custom.css: .reactPlayer gains max-width: 100% and aspect-ratio: 16 / 9, fixing all twelve pages at once.
  • No tests: this repo has no test suite.
Notes
  • Verified with scripted geometry assertions (zone, link, search, toggle overlap; section-nav and page overflow) at 16 widths from 1440px down to 320px, run against the production build; drawer checked in light and dark, on a doc page and off one. Lint and Build are green.
  • The drawer deliberately does not share a component with SecondaryNav: the overlap is about six lines, while the DOM contract (Infima menu__* classes vs local ones), the data (flattened Releases vs a stateful dropdown) and the behaviour (drawer-close vs outside-click/Escape) all differ. They do share the data and the matcher, which is the part that could drift.
  • height: auto !important on .reactPlayer is the only way to beat react-player's inline height. Registering ReactPlayer in src/theme/MDXComponents would remove the need and drop twelve import lines — worth a follow-up.
  • Pre-existing and not addressed here: SecondaryNav's dropdownItemActive cannot mark the per-release entries, findSection's prefix fallback has no path-boundary check, and the twelve video pages pass controls="true" as a string.
  • Follow-up worth taking: four places now repeat the same masked-glyph CSS block (sidebar caret, breadcrumb separator, and both chevrons); one utility class would leave each consumer with mask-image, width, height.

Closes #541

The centre zone was positioned absolutely, so the side zones kept their
full half of the row and the external links ran under the search field
and the colour-mode toggle between 997px and roughly 1180px — 1024px
laptops and iPads sat in the middle of that band. Laid out in flow, with
the side zones on an equal share, the centre lands on the same midline
without overlapping anything.

Below the breakpoint the wordmark's fixed widths (312px, 220px under
768px) pushed the search button and the toggle off the right edge. It now
shrinks to fit. Dropping theme-classic's <NavbarSearch> wrapper takes the
search field out of the rule that pinned it to the navbar's right edge on
mobile, where it landed on top of the toggle.
The navbar's background is transparent because the fixed wrapper in
Navbar/Layout paints the header, and Infima's drawer reads the same
variable — so opening the menu on a phone showed the page through it.

Fixes #541
The drawer's first level listed the four off-site links and nothing else:
the section nav is hidden below 997px and the drawer's second level only
exists on pages that have a sidebar, so away from a doc page there was no
way into the docs at all.

It now opens on the same sections the section nav shows on desktop, drawn
from the same config and marked active by the same matcher the sidebar
filter uses, with the Releases dropdown flattened to its index page.
Follows the two-level mobile menu on docs.moderne.io.
react-player writes its size inline as 640x360, so every embedded video
ran off the side of the viewport below that width. Capping the width and
deriving the height from the ratio fixes all twelve pages at once.
@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite Sep 2, 2026
@zieka
zieka marked this pull request as ready for review September 2, 2026 19:08

@sjungling sjungling left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimize code comments

@github-project-automation github-project-automation Bot moved this from In Progress to Ready to Review in OpenRewrite Sep 2, 2026
Why over what, inline over doc blocks, and standard labels where they
apply. Rationale a reader wants at this depth is in the PR and the commit
messages.
The header copied from the other swizzles points at "the MIT license
found in the LICENSE file in the root directory of this source tree" —
true in the Docusaurus repo, but this tree's LICENSE is Apache-2.0. The
derived part is the navbar-items list, so that is what it now credits.
Nothing in the file is Facebook's expression. What it shares with
theme-classic's PrimaryMenu is two hook calls, an Infima class name and a
map over NavbarItem — the only way to call that API, not a copied
implementation. Nine of the twelve swizzles here carry no notice either.
@zieka
zieka merged commit 77829b0 into master Sep 2, 2026
2 checks passed
@zieka
zieka deleted the fix/header-mobile-collisions branch September 2, 2026 19:42
@github-project-automation github-project-automation Bot moved this from Ready to Review to Done in OpenRewrite Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Mobile menu transparent

2 participants