Skip to content

Commit 7a70238

Browse files
[Frame] Add custom scrollbar styles for reframe (#11965)
Edit: updated to use custom scrollbar styles instead of native ones ### WHY are these changes introduced? Fixes Shopify/archive-polaris-backlog-2024#1379 ### WHAT is this pull request doing? https://admin.web.custom-scroll.sophie-schneider.us.spin.dev/store/shop1 |Change|Why?| |-|-| |Adds a `2px` margin to the right of the scrollbar|so it fits within the rounded corner container| |Use custom scrollbar|Match our other scrollbars in the admin, hide the track so the right margin is less obvious. Using native scrollbars on safari and `webkit` pseudo selector doesn't respect user's OS scroll settings| |Add lighter token for rest state of scrollbar|I cannot style the scrollbar thumb hover state without the `webkit` pseudo selector so this changes the scrollbar color depending on whether or not the user is hovering over the full scroll container| ### Potential future improvements 1. Add a larger margin on firefox so the scrollbar isn't cut off there 2. Implement and "Overlay scrollbar" when "Always show scrollbars" setting is on 3. Add border line for when "Always show scrollbars" setting is on to always show the scroll track even when there isn't scrollable content See demo below where there isn't a layout shift for the "Always show scrollbars" setting on but it causes the content to look off centre because of the gutter. ![Screen Recording 2024-05-03 at 3 51 37 PM](https://github.com/Shopify/polaris/assets/20652326/e9943bed-dcd6-460c-a8f0-dabbdcc6bb90) ### How to 🎩 https://admin.web.custom-scroll.sophie-schneider.us.spin.dev/store/shop1 Tophat with OS scroll settings set to "Always" and "When scrolling" Check on chrome, firefox, safari, edge <img width="713" alt="Screenshot 2024-05-06 at 12 03 45 PM" src="https://github.com/Shopify/polaris/assets/20652326/ef9cfc0c-bd57-46d6-80d8-15795f1e84ab"> ### 🎩 checklist - [x] Tested a [snapshot](https://github.com/Shopify/polaris/blob/main/documentation/Releasing.md#-snapshot-releases) - [x] Tested on [mobile](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md#cross-browser-testing) - [x] Tested on [multiple browsers](https://help.shopify.com/en/manual/shopify-admin/supported-browsers) - [x] Tested for [accessibility](https://github.com/Shopify/polaris/blob/main/documentation/Accessibility%20testing.md)
1 parent 4f3bf99 commit 7a70238

File tree

5 files changed

+79
-4
lines changed

5 files changed

+79
-4
lines changed

.changeset/sixty-pugs-wave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/polaris': patch
3+
---
4+
5+
Added scrollbar styles for reframe
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/polaris-tokens': minor
3+
---
4+
5+
Added `color-scrollbar-thumb-bg` token

polaris-react/src/components/Frame/Frame.module.css

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
.Frame-TopBarAndReframe {
4040
/* stylelint-disable -- Polaris component custom properties */
4141
--pc-sidebar-width: calc(356px + var(--p-space-100));
42+
--pc-scrollbar-spacer: 0;
43+
4244
/* stylelint-enable */
4345
background-color: var(--p-color-bg-inverse);
4446
transition: width var(--p-motion-duration-250) var(--p-motion-ease);
@@ -48,6 +50,13 @@
4850
}
4951
}
5052

53+
.ScrollbarAlwaysVisible {
54+
/* Only apply spacing when scrollbar is set to always visible to create a gutter and prevent layout shifts */
55+
/* stylelint-disable -- Polaris component custom properties */
56+
--pc-scrollbar-spacer: var(--p-space-050);
57+
/* stylelint-enable */
58+
}
59+
5160
.Navigation {
5261
position: fixed;
5362
z-index: var(--p-z-index-8);
@@ -307,7 +316,8 @@
307316
/* stylelint-disable -- polaris/conventions/polaris/custom-property-allowed-list -- Polaris component custom properties */
308317
width: calc(
309318
100vw - var(--pg-navigation-width) -
310-
var(--pc-app-provider-scrollbar-width) - var(--pc-frame-offset, 0px)
319+
var(--pc-app-provider-scrollbar-width) - var(--pc-frame-offset, 0px) -
320+
var(--pc-scrollbar-spacer)
311321
);
312322
/* stylelint-enable -- polaris/conventions/polaris/custom-property-allowed-list */
313323

@@ -326,7 +336,7 @@
326336
width: calc(
327337
100vw - var(--pg-navigation-width) -
328338
var(--pc-app-provider-scrollbar-width) - var(--pc-sidebar-width) -
329-
var(--pc-frame-offset, 0px)
339+
var(--pc-frame-offset, 0px) - var(--pc-scrollbar-spacer)
330340
);
331341
margin-right: unset;
332342
}
@@ -462,6 +472,38 @@
462472

463473
.Scrollable {
464474
width: 100%;
475+
476+
/* Not using the spacer custom property so the space is applied always */
477+
margin-right: var(--p-space-050);
465478
/* stylelint-disable-next-line polaris/conventions/polaris/custom-property-allowed-list -- top bar global space */
466479
height: calc(100% - var(--pg-top-bar-height));
480+
481+
scrollbar-width: thin;
482+
scrollbar-color: var(--p-color-scrollbar-thumb-bg) transparent;
483+
transition: scrollbar-color var(--p-motion-duration-100)
484+
var(--p-motion-ease-in);
485+
486+
&:hover {
487+
scrollbar-color: var(--p-color-scrollbar-thumb-bg-hover) transparent;
488+
}
489+
}
490+
491+
.Scrollable-ScrollbarAlwaysVisible {
492+
/* Safari scrollbar styles until it adopts scrollbar-color, scrollbar-width */
493+
&::-webkit-scrollbar {
494+
/* Matches scrollbar-width: thin */
495+
width: 11px;
496+
background-color: var(--p-color-bg);
497+
}
498+
499+
&::-webkit-scrollbar-thumb {
500+
background-color: var(--p-color-scrollbar-thumb-bg);
501+
border: var(--p-border-width-050) solid transparent;
502+
border-radius: var(--p-border-radius-300);
503+
background-clip: content-box;
504+
505+
&:hover {
506+
background-color: var(--p-color-scrollbar-thumb-bg-hover);
507+
}
508+
}
467509
}

polaris-react/src/components/Frame/Frame.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ interface State {
7272
loadingStack: number;
7373
toastMessages: ToastPropsWithID[];
7474
showContextualSaveBar: boolean;
75+
scrollbarAlwaysVisible: boolean;
7576
}
7677

7778
const APP_FRAME_MAIN = 'AppFrameMain';
@@ -88,6 +89,7 @@ class FrameInner extends PureComponent<CombinedProps, State> {
8889
loadingStack: 0,
8990
toastMessages: [],
9091
showContextualSaveBar: false,
92+
scrollbarAlwaysVisible: false,
9193
};
9294

9395
private contextualSaveBar: ContextualSaveBarProps | null = null;
@@ -102,6 +104,7 @@ class FrameInner extends PureComponent<CombinedProps, State> {
102104
this.setGlobalRibbonRootProperty();
103105
this.setOffset();
104106
this.setBodyStyles();
107+
this.setScrollbarAlwaysVisible();
105108
}
106109

107110
componentDidUpdate(prevProps: FrameProps) {
@@ -253,6 +256,7 @@ class FrameInner extends PureComponent<CombinedProps, State> {
253256
topBar && styles.hasTopBar,
254257
sidebar && styles.hasSidebar,
255258
sidebar && hasDynamicTopBar && styles['hasSidebar-TopBarAndReframe'],
259+
this.state.scrollbarAlwaysVisible && styles.ScrollbarAlwaysVisible,
256260
);
257261

258262
const contextualSaveBarMarkup = this.props.dynamicTopBarAndReframe ? (
@@ -322,7 +326,11 @@ class FrameInner extends PureComponent<CombinedProps, State> {
322326
<Scrollable
323327
scrollbarWidth="thin"
324328
horizontal={false}
325-
className={styles.Scrollable}
329+
className={classNames(
330+
styles.Scrollable,
331+
this.state.scrollbarAlwaysVisible &&
332+
styles['Scrollable-ScrollbarAlwaysVisible'],
333+
)}
326334
id={APP_FRAME_SCROLLABLE}
327335
>
328336
<div
@@ -377,6 +385,17 @@ class FrameInner extends PureComponent<CombinedProps, State> {
377385
setRootProperty('--pc-frame-offset', offset);
378386
};
379387

388+
private setScrollbarAlwaysVisible = () => {
389+
const scrollbarWidth = parseInt(
390+
document.documentElement.style.getPropertyValue(
391+
'--pc-app-provider-scrollbar-width',
392+
),
393+
10,
394+
);
395+
396+
this.setState({scrollbarAlwaysVisible: scrollbarWidth > 0});
397+
};
398+
380399
private setGlobalRibbonRootProperty = () => {
381400
const {globalRibbonHeight} = this.state;
382401
setRootProperty(

polaris-tokens/src/themes/base/color.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ export type ColorBackgroundAlias =
120120
| 'radio-button-bg-surface-disabled'
121121
| 'video-thumbnail-play-button-bg-fill-hover'
122122
| 'video-thumbnail-play-button-bg-fill'
123-
| 'scrollbar-thumb-bg-hover';
123+
| 'scrollbar-thumb-bg-hover'
124+
| 'scrollbar-thumb-bg';
124125

125126
export type ColorBorderAlias =
126127
| 'border-brand'
@@ -1223,4 +1224,7 @@ export const color: {
12231224
'color-scrollbar-thumb-bg-hover': {
12241225
value: colors.gray[12],
12251226
},
1227+
'color-scrollbar-thumb-bg': {
1228+
value: colors.gray[11],
1229+
},
12261230
};

0 commit comments

Comments
 (0)