diff --git a/.changeset/red-doors-retire.md b/.changeset/red-doors-retire.md new file mode 100644 index 00000000000..05fe017f4a8 --- /dev/null +++ b/.changeset/red-doors-retire.md @@ -0,0 +1,5 @@ +--- +'@shopify/polaris': minor +--- + +Updated the Frame and Topbar components to stay clear of a scrollbar. This reduces the overall jumpiness in the UI when scrollbars appear and disappear when using a Polaris app. diff --git a/polaris-react/src/components/AppProvider/AppProvider.tsx b/polaris-react/src/components/AppProvider/AppProvider.tsx index 16729d935aa..c6499d1f979 100644 --- a/polaris-react/src/components/AppProvider/AppProvider.tsx +++ b/polaris-react/src/components/AppProvider/AppProvider.tsx @@ -25,6 +25,43 @@ import type {FeaturesConfig} from '../../utilities/features'; import './AppProvider.scss'; import './global.scss'; +const MAX_SCROLLBAR_WIDTH = 20; +const SCROLLBAR_TEST_ELEMENT_PARENT_SIZE = 30; +const SCROLLBAR_TEST_ELEMENT_CHILD_SIZE = + SCROLLBAR_TEST_ELEMENT_PARENT_SIZE + 10; + +function measureScrollbars() { + const parentEl = document.createElement('div'); + parentEl.setAttribute( + 'style', + `position: absolute; opacity: 0; transform: translate3d(-9999px, -9999px, 0); pointer-events: none; width:${SCROLLBAR_TEST_ELEMENT_PARENT_SIZE}px; height:${SCROLLBAR_TEST_ELEMENT_PARENT_SIZE}px;`, + ); + + const child = document.createElement('div'); + child.setAttribute( + 'style', + `width:100%; height: ${SCROLLBAR_TEST_ELEMENT_CHILD_SIZE}; overflow:scroll`, + ); + parentEl.appendChild(child); + document.body.appendChild(parentEl); + + const scrollbarWidth = + SCROLLBAR_TEST_ELEMENT_PARENT_SIZE - + (parentEl.firstElementChild?.clientWidth ?? 0); + + const scrollbarWidthWithSafetyHatch = Math.min( + scrollbarWidth, + MAX_SCROLLBAR_WIDTH, + ); + + document.documentElement.style.setProperty( + '--pc-app-provider-scrollbar-width', + `${scrollbarWidthWithSafetyHatch}px`, + ); + + document.body.removeChild(parentEl); +} + interface State { intl: I18n; link: LinkLikeComponent | undefined; @@ -65,6 +102,7 @@ export class AppProvider extends Component { this.setBodyStyles(); this.setRootAttributes(); } + measureScrollbars(); } componentDidUpdate({ diff --git a/polaris-react/src/components/Frame/Frame.scss b/polaris-react/src/components/Frame/Frame.scss index e97cb0724ba..703df46581f 100644 --- a/polaris-react/src/components/Frame/Frame.scss +++ b/polaris-react/src/components/Frame/Frame.scss @@ -231,7 +231,11 @@ $sidebar-breakpoint: 1200px; align-items: stretch; min-width: 0; - max-width: 100%; + @media #{$p-breakpoints-sm-up} { + // stylelint-disable -- polaris/conventions/polaris/custom-property-allowed-list -- Polaris component custom properties + max-width: calc(100vw - var(--pc-app-provider-scrollbar-width)); + // stylelint-enable -- polaris/conventions/polaris/custom-property-allowed-list + } // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY @include safe-area-for(padding-right, 0, right); diff --git a/polaris-react/src/components/TopBar/TopBar.scss b/polaris-react/src/components/TopBar/TopBar.scss index 6ec80607024..da8fe99acc3 100644 --- a/polaris-react/src/components/TopBar/TopBar.scss +++ b/polaris-react/src/components/TopBar/TopBar.scss @@ -13,9 +13,6 @@ $right-column: 1fr; .TopBar { position: relative; - display: grid; - grid-template-columns: $left-column $search-column $right-column; - align-items: center; height: $top-bar-height; box-shadow: var(--p-shadow-sm); background-color: var(--p-color-bg); @@ -45,6 +42,15 @@ $right-column: 1fr; } } +.Container { + display: grid; + grid-template-columns: $left-column $search-column $right-column; + align-items: center; + // stylelint-disable -- polaris/conventions/polaris/custom-property-allowed-list -- Polaris component custom properties + width: calc(100vw - var(--pc-app-provider-scrollbar-width)); + // stylelint-enable -- polaris/conventions/polaris/custom-property-allowed-list +} + .LogoDisplayControl { display: none; @media #{$p-breakpoints-md-up} { diff --git a/polaris-react/src/components/TopBar/TopBar.tsx b/polaris-react/src/components/TopBar/TopBar.tsx index 3631f10b4ee..af31059f62e 100644 --- a/polaris-react/src/components/TopBar/TopBar.tsx +++ b/polaris-react/src/components/TopBar/TopBar.tsx @@ -142,14 +142,16 @@ export const TopBar: React.FunctionComponent & { return (
-
- {navigationButtonMarkup} - {contextMarkup} -
-
{searchMarkup}
-
-
{secondaryMenu}
- {userMenu} +
+
+ {navigationButtonMarkup} + {contextMarkup} +
+
{searchMarkup}
+
+
{secondaryMenu}
+ {userMenu} +
);