Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions site/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -744,15 +744,22 @@
scrollbar-color: hsl(var(--surface-quaternary)) transparent;
}

/* Prevent layout shift when modals open by maintaining scrollbar width.
scrollbar-gutter: stable reserves space for the scrollbar so Radix's
scroll-bar compensation (margin-right/padding-right) is unnecessary
and causes double spacing. We zero it out with !important to win
over Radix's injected !important styles. The @supports guard ensures
we only do this on browsers that actually support scrollbar-gutter.

There’s a related issue on GitHub: Radix UI Primitives Issue #3251
https://github.com/radix-ui/primitives/issues/3251
/* Prevent layout shift when modals and dropdowns open.

scrollbar-gutter: stable reserves space for the scrollbar. When Radix
locks the scroll, Radix hides the body scrollbar and injects
margin-right and padding-right. The reserved gutter already keeps the
page width constant. The injected compensation adds a second space and
causes a shift. Set --removed-body-scroll-bar-size and margin-right to
0 with !important to disable the compensation. The @supports guard
applies these rules only to browsers that support scrollbar-gutter.

Do not set overflow-y on body[data-scroll-locked]. A forced overflow-y
overrides the scroll lock. On pages that set overflow: hidden on
<html> (for example /agents), the body then shows a new scrollbar and
the page width changes.
Comment on lines +757 to +760

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add visual coverage for scroll-lock layout behavior

With classic scrollbars, this changes page-width behavior for every scroll-locking Radix overlay, but no story opens an overlay while rendering either a scrollable dashboard page or the /agents layout. The existing AgentsPageLayout stories therefore never activate data-scroll-locked, so Pixel cannot catch the layout shift this fix targets or a regression to it; add a story whose play function opens the affected dropdown or dialog on an overflowing page.

AGENTS.md reference: site/AGENTS.md:L7-L7

Useful? React with 👍 / 👎.


Related issue: https://github.com/radix-ui/primitives/issues/3251
*/
@supports (scrollbar-gutter: stable) {
html {
Expand All @@ -762,7 +769,6 @@
html body[data-scroll-locked] {
--removed-body-scroll-bar-size: 0 !important;
margin-right: 0 !important;
overflow-y: scroll !important;
}
}

Expand Down
28 changes: 6 additions & 22 deletions site/src/pages/AgentsPage/AgentsPageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,23 +180,13 @@ const AgentsPageLayout: FC = () => {
const [isSearchDialogOpen, setIsSearchDialogOpen] = useState(false);

// The global CSS sets scrollbar-gutter: stable on <html> to prevent
// layout shift on pages that toggle scrollbars. The agents page
// uses its own internal scroll containers so the reserved gutter
// space is unnecessary and wastes horizontal room.
// layout shift on pages that show and hide a scrollbar. The agents
// page scrolls in internal containers only. The reserved gutter is
// not necessary and uses horizontal space.
//
// Removing the gutter requires three things:
//
// 1. overflow:hidden on both <html> and <body> so neither element
// can produce a scrollbar.
// 2. scrollbar-gutter:auto on <html> so the browser stops
// reserving space for a scrollbar that will never appear.
// This is what makes react-remove-scroll-bar measure a gap of
// 0 when a Radix dropdown opens, so it injects no padding or
// margin compensation.
// 3. An injected <style> that overrides the global
// `overflow-y: scroll !important` on body[data-scroll-locked].
// Without this, opening any Radix dropdown would force a
// scrollbar onto <body>, re-introducing the layout shift.
// Set overflow: hidden on <html> and <body>. Neither element can
// then show a scrollbar. Set scrollbar-gutter: auto on <html> so that
// the browser does not reserve space for a scrollbar.
useEffect(() => {
const html = document.documentElement;
const body = document.body;
Expand All @@ -209,16 +199,10 @@ const AgentsPageLayout: FC = () => {
html.style.scrollbarGutter = "auto";
body.style.overflow = "hidden";

const style = document.createElement("style");
style.textContent =
"html body[data-scroll-locked] { overflow-y: hidden !important; }";
document.head.appendChild(style);

return () => {
html.style.overflow = prevHtmlOverflow;
html.style.scrollbarGutter = prevHtmlScrollbarGutter;
body.style.overflow = prevBodyOverflow;
style.remove();
};
}, []);

Expand Down
Loading