Skip to content

v2.0.0-next.0

Pre-release
Pre-release
Compare
Choose a tag to compare
@Julien-Marcou Julien-Marcou released this 20 Feb 16:48

Breaking changes

This is a breaking change release, you'll need to migrate your existing code if you upgrade from the v1.

Why a breaking change release ?

More modern

The web has come a long way since Scrollable-Component has been originally designed (June 2020).
The following CSS rules are now widely supported (thanks to Edge transitioning to Chromium):

  • ::part() to customize parts of a web component
  • position: sticky; to create fixed overlay within a viewport
  • display: grid; to ease layout creation

And the following JS features are becoming widely supported:

  • ResizeObserverEntry to ease bounding box computation (still waiting for Safari to catch up on this one)
  • Private class fields to improve code cleanliness

New design

This version aims to fix several design flaws inherent to the v1:

  • Make the root element of the component the viewport itself

    • It allows you to directly interact with it as a native viewport instead of targeting a child element
    • It allows you to fallback to a native viewport when the JS is disabled or while the page hasn't finished loading yet
  • Make the custom scrollbars part of the viewport

    • Before, when using your scroll wheel while hovering a custom scrollbar, nothing would have happened
    • Now, it scrolls the viewport like a native scrollbar
  • Remove almost all of the CSS properties in favor of the ::part() pseudo element

    • It allows you to directly apply your own CSS rules to any parts of the components without any restriction
    • It improves the maintainability of the code, as no additionnal CSS properties will be required in order to increase the customizability of the component
    • It reduces the weight of the component
  • Make the component sizing more predictable

    • When sizing/positioning the component absolutely, in some cases, it would have resulted differently from a native viewport rendering, not shrinking or growing like we would expect it to
    • Although the new design still has some differences compared to native viewports, it's now easier to size and position (even easier than native viewports in some cases, e.g. horizontal carrousel)

New Features

In addition to this new design elements, there is some new features.

  • You can now use CSS ::part() to further customize the component

    • use ::part(content) to target the content of the viewport
    • use ::part(scrollbar) to target both scrollbars
    • use ::part(scrollbar-track) to target both scrollbar tracks
    • use ::part(scrollbar-thumb) to target both scrollbar thumbs
    • use ::part(vertical-scrollbar) to target the vertical scrollbar
    • use ::part(vertical-scrollbar-track) to target the vertical scrollbar track
    • use ::part(vertical-scrollbar-thumb) to target the vertical scrollbar thumb
    • use ::part(horizontal-scrollbar) to target the horizontal scrollbar
    • use ::part(horizontal-scrollbar-track) to target the horizontal scrollbar track
    • use ::part(horizontal-scrollbar-thumb) to target the horizontal scrollbar thumb
    • use ::part(active) to target the active scrollbar thumb (when you drag the scrollbar thumb)
    • CSS parts can be combined with the :hover pseudo-selector & the :before & :after pseudo-elements
  • New CSS properties

    • --scrollbar-thumb-fill-color-active to set the background color of the scrollbar thumb when it's active
    • --scrollbar-z-index to set the z-index of both scrollbars
  • You can now add the edge-detection="true" attribute to detect when the viewport is fully scrolled to one of its edges

    • When there is vertical overflow:
      • Adds a top-overflow class when the viewport can be scrolled up, removes it when fully scrolled to the top
      • Adds a bottom-overflow class when the viewport can be scrolled down, removes it when fully scrolled to the bottom
    • When there is horizontal overflow:
      • Adds a left-overflow class when the viewport can be scrolled left, removes it when fully scrolled to the left
      • Adds a right-overflow class when the viewport can be scrolled right, removes it when fully scrolled to the right
  • You can now add the scrollbar-overlay="false" attribute to make the scrollbars part of the content (like most of the native scrollbars on desktop) instead of them being on top of the content (like most of the native scrollbars on smartphones)

    • When the viewport is overflowing, the scrollbar reduces the place available for the content
    • When the viewport is not overflowing, the scrollbar takes no place

Migration guide

Build optimizer

Some build optimizers may require you to target esnext (angular/angular-cli#22486) es2022.

The viewport and content component properties have been removed

As the component now is the viewport itself, you can still use the JavaScript API to interact with it:

const scrollableComponent = document.querySelector('scrollable-component');

// v1 - Before the migration
scrollableComponent.viewport.addEventListener('scroll', (event) => {
  // Your code
});

// v2 - After the migration
scrollableComponent.addEventListener('scroll', (event) => {
  // Your code
});

Most of the CSS properties have been removed

Removed all the --*-z-index CSS properties, except --scrollbar-z-index-hover

/* v1 - Before */
scrollable-component {
  --viewport-z-index: 0;
  --horizontal-scrollbar-z-index: 10;
  --vertical-scrollbar-z-index: 20;
  --scrollbar-z-index-hover: 30;
}

/* v2 - After */
scrollable-component {
  --content-z-index: 0;
  --scrollbar-z-index: 10;
  --scrollbar-z-index-hover: 20;
}

Removed all the --viewport-* CSS properties

/* v1 - Before */
scrollable-component {
  --viewport-overflow-x: auto;
  --viewport-overflow-y: auto;
  --viewport-scroll-snap-type: none;
  --viewport-scroll-behavior: auto;
  --viewport-overscroll-behavior: auto;
  --viewport-z-index: 0;
}

/* v2 - After */
scrollable-component {
  overflow-x: auto;
  overflow-y: auto;
  scroll-snap-type: none;
  scroll-behavior: auto;
  overscroll-behavior: auto;
  /* `--viewport-z-index` has been replaced by `--content-z-index` */
}

Removed all the --vertical-scrollbar-* CSS properties

/* v1 - Before */
scrollable-component {
  --vertical-scrollbar-padding: var(--scrollbar-padding);
  --vertical-scrollbar-background: none;
  --vertical-scrollbar-background-size: auto;
  --vertical-scrollbar-z-index: 20;

  --vertical-scrollbar-track-background: none;
  --vertical-scrollbar-track-background-size: auto;

  --vertical-scrollbar-thumb-background: none;
  --vertical-scrollbar-thumb-background-size: auto;
}

/* v2 - After */
scrollable-component::part(vertical-scrollbar) {
  padding: var(--scrollbar-padding);
  background: none;
  background-size: auto;
  /* z-index has no effect here, use `--scrollbar-z-index` & `--scrollbar-z-index-hover` instead */
}
scrollable-component::part(vertical-scrollbar-track) {
  background: none;
  background-size: auto;
}
scrollable-component::part(vertical-scrollbar-thumb) {
  background: none;
  background-size: auto;
}

Removed all the --horizontal-scrollbar-* CSS properties

/* v1 - Before */
scrollable-component {
  --horizontal-scrollbar-padding: var(--scrollbar-padding);
  --horizontal-scrollbar-background: none;
  --horizontal-scrollbar-background-size: auto;
  --horizontal-scrollbar-z-index: 10;

  --horizontal-scrollbar-track-background: none;
  --horizontal-scrollbar-track-background-size: auto;

  --horizontal-scrollbar-thumb-background: none;
  --horizontal-scrollbar-thumb-background-size: auto;
}

/* v2 - After */
scrollable-component::part(horizontal-scrollbar) {
  padding: var(--scrollbar-padding);
  background: none;
  background-size: auto;
  /* z-index has no effect here, use --scrollbar-z-index & --scrollbar-z-index-hover instead */
}
scrollable-component::part(horizontal-scrollbar-track) {
  background: none;
  background-size: auto;
}
scrollable-component::part(horizontal-scrollbar-thumb) {
  background: none;
  background-size: auto;
}

Removed all the --scrollbar-* CSS properties, except:

  • --scrollbar-width
  • --scrollbar-padding
  • --scrollbar-z-index
  • --scrollbar-z-index-hover
  • --scrollbar-track-fill-color
  • --scrollbar-track-fill-color-hover
  • --scrollbar-thumb-fill-color
  • --scrollbar-thumb-fill-color-hover
  • --scrollbar-thumb-fill-color-active
/* v1 - Before */
scrollable-component {
  --scrollbar-fill-color: transparent;
  --scrollbar-fill-color-hover: transparent;
  --scrollbar-border-width: 0;
  --scrollbar-border-style: none;
  --scrollbar-border-color: #999;
  --scrollbar-border-radius: 0;
  --scrollbar-box-shadow: none;

  --scrollbar-track-border-width: 0;
  --scrollbar-track-border-style: none;
  --scrollbar-track-border-color: #999;
  --scrollbar-track-border-radius: 0;
  --scrollbar-track-box-shadow: none;

  --scrollbar-thumb-border-width: 0;
  --scrollbar-thumb-border-style: none;
  --scrollbar-thumb-border-color: #999;
  --scrollbar-thumb-border-radius: var(--scrollbar-width);
  --scrollbar-thumb-box-shadow: none;
}

/* v2 - After */
scrollable-component::part(scrollbar) {
  background-color: transparent;
  border-width: 0;
  border-style: none;
  border-color: #999;
  border-radius: 0;
  box-shadow: none;
}
scrollable-component::part(scrollbar):hover {
  background-color: transparent;
}
scrollable-component::part(scrollbar-track) {
  border-width: 0;
  border-style: none;
  border-color: #999;
  border-radius: 0;
  box-shadow: none;
}
scrollable-component::part(scrollbar-thumb) {
  border-width: 0;
  border-style: none;
  border-color: #999;
  border-radius: var(--scrollbar-width);
  box-shadow: none;
}