components icon indicating copy to clipboard operation
components copied to clipboard

fix: Implement TopNavigation breakpoints in CSS

Open TrevorBurnham opened this issue 1 year ago • 9 comments

Description

This PR switches from JavaScript-based breakpoints to CSS container queries for TopNavigation, making its appearance consistent when rendered with SSR. I've added Sass mixins for this purpose that can be reused across other components to replace the useBreakpoints hook.

I've opted to use container queries rather than media queries for backward compatibility's sake, since useBreakpoints checks container size rather than viewport size. However, this introduces a complication: To use container queries, we need to add container-type: inline-size to the TopNavigation element's styles.

I noticed that adding container-type: inline-size causes overflowing content to get clipped in Safari due to a longstanding bug in that browser. [Update 4/5: After updating to Safari 18.4 on my Mac, I no longer see the bug, so it looks like Apple just fixed this.] To address that, I've enabled expandToViewport to render utility dropdowns in a portal. I've also added position: relative and z-index: 1 to the TopNavigation styles to give it a stacking context, which appears to help with the issue. However, there is still a possibility that users who are rendering their own dropdowns in the TopNavigation (e.g. by using an Autosuggest searchbox) without expandToViewport may see issues in older versions of Safari where the dropdown is rendered behind other content with a higher z-index. I would suggest calling this out in the release notes and recommending the use of expandToViewport for dropdowns in TopNavigation.

Once this change is merged, I'd love to start applying this same change to other components that use useBreakpoints. Container queries are supported in all modern browsers.

Fixes #3337

How has this been tested?

I've run this change locally, eyeballed it at different breakpoints, and clicked various controls to ensure that they're visible. I'm open to ideas for testing the breakpoint behavior more thoroughly.

Review checklist

The following items are to be evaluated by the author(s) and the reviewer(s).

Correctness

  • Changes include appropriate documentation updates.
  • Changes are backward-compatible if not indicated, see CONTRIBUTING.md.
  • Changes do not include unsupported browser features, see CONTRIBUTING.md.
  • Changes were manually tested for accessibility, see accessibility guidelines.

Security

Testing

  • Changes are covered with new/existing unit tests?
  • Changes are covered with new/existing integration tests?

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

TrevorBurnham avatar Mar 24 '25 18:03 TrevorBurnham

Hello @TrevorBurnham,

Thanks for contributing the fix!

Our team is taking a look and running internal screenshot tests and manual tests.

Could you please fix the failing unit tests? P.S. the "Measure bundle size" action is expected to fail, please ignore it.

pan-kot avatar Mar 26 '25 12:03 pan-kot

@pan-kot Sure thing. I've pushed a fix for the unit tests: 51e8d78

TrevorBurnham avatar Mar 26 '25 13:03 TrevorBurnham

Codecov Report

:white_check_mark: All modified and coverable lines are covered by tests. :white_check_mark: Project coverage is 97.16%. Comparing base (59b27e4) to head (15d4318). :warning: Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3371      +/-   ##
==========================================
- Coverage   97.17%   97.16%   -0.01%     
==========================================
  Files         856      856              
  Lines       25241    25226      -15     
  Branches     8939     8932       -7     
==========================================
- Hits        24527    24512      -15     
  Misses        665      665              
  Partials       49       49              

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

codecov[bot] avatar Mar 27 '25 09:03 codecov[bot]

@TrevorBurnham, thanks for addressing the tests! Please also take a look at test coverage.

Also, there is a small regression: the right hand size padding became smaller, see attachments:

Expected: expected

Actual: actual

pan-kot avatar Mar 27 '25 16:03 pan-kot

Thanks! Can you give me instructions for viewing the component before/after? What I've been doing is running npm run build and then running a project against the built components directory, but some of the styles seem to be lost in that process (possibly because the "visual refresh" flag doesn't work).

TrevorBurnham avatar Mar 27 '25 16:03 TrevorBurnham

Thanks! Can you give me instructions for viewing the component before/after? What I've been doing is running npm run build and then running a project against the built components directory, but some of the styles seem to be lost in that process (possibly because the "visual refresh" flag doesn't work).

The npm run build should be fine: you can build the mainline and then your commit, and compare the differences. The ./pages/lib folder should contain the static assets for the dev pages.

pan-kot avatar Mar 28 '25 10:03 pan-kot

I've updated the PR branch to fix the visual inconsistencies and improve code coverage.

One call-out: Previously TopNavigation passed a prop called offsetRight to the ButtonTrigger for utility menu dropdowns, then added styles based on the .offset-right-* class. Since the offsetRight value depended on the breakpoint in JavaScript, that approach doesn't work; there needs to be a CSS selector that can be used in the TopNavigation styles to reference the ButtonTrigger element. So I added a prop called internalClass to allow a classname to be passed through. Let me know if there's a better way to do this.

TrevorBurnham avatar Mar 31 '25 11:03 TrevorBurnham

I've rebased this branch and made the following changes:

  1. Added position: relative and z-index: 1 to the TopNavigation to work around a Safari bug where overflow content from containers with container-type: inline-size can be incorrectly rendered behind other elements, causing clipping. I've updated the PR description with more details about this bug, which I think is the most serious potential issue with this change.
  2. Renamed internalClassName to just className and added an explanatory comment re: feedback.
  3. Reduced unnecessary test changes and comments re: feedback.

TrevorBurnham avatar Apr 05 '25 22:04 TrevorBurnham

@pan-kot I've rebased and updated this branch.

TrevorBurnham avatar Oct 25 '25 15:10 TrevorBurnham