vidscroll0.3.3

Styling hooks

CSS variables, data attributes, shadow parts and the default styles.

vidscroll ships no stylesheet to import. It adds a few default rules, all wrapped in :where() so they have zero specificity: any rule you write wins, without !important.

CSS variables

VariableSet onValue
–video-progressThe ScrollVideo or ScrollFrames block, the <vid-scroll> element, the core containerSmoothed progress through the whole video, 0 to 1, four decimals. Set once the video starts.
–progressEach sectionProgress through the section’s range: 0 before, 1 after.
–loader-progressThe <vid-scroll> elementLoading progress, 0 to 1, while loading. Removed when done.

All three are inherited by everything inside.

Data attributes

SelectorElement
[data-vidscroll]The outer block. Its height is length plus one screen.
[data-vidscroll-stage]The pinned, screen-sized stage
[data-vidscroll-overlay]The layer over the video that holds your content
[data-vidscroll-media]The video, or the canvas in ScrollFrames. [data-fit] holds cover or contain.
[data-vidscroll-preview]The first-frame video shown while loading
[data-vidscroll-next]The optimized copy while it’s being swapped in, behind the current video
[data-vidscroll-section=“id”]A section; [data-active] while active
[data-vidscroll-loader]The loading overlay; [data-phase] holds the phase, [data-background] marks the corner badge

In <vid-scroll>, the stage, media and loader are inside the element’s shadow root, so style them with the parts below instead. The element itself carries data-phase and data-background while loading.

Shadow parts

For <vid-scroll> only:

SelectorElement
vid-scroll::part(stage)The pinned stage
vid-scroll::part(video)The video
vid-scroll::part(overlay)The layer holding your content
vid-scroll::part(loader)The loading overlay and corner badge

Default styles

These are the rules vidscroll adds (the element applies the same ones inside its shadow root):

vidscroll defaults
:where([data-vidscroll]) { position: relative; }
:where([data-vidscroll-stage]) { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; background: #000; }
:where([data-vidscroll-media]) { display: block; width: 100%; height: 100%; object-fit: cover; }
:where([data-vidscroll-media][data-fit="contain"]) { object-fit: contain; }
:where([data-vidscroll-preview]) { position: absolute; inset: 0; }
:where([data-vidscroll-next]) { position: absolute; inset: 0; z-index: -1; }
:where([data-vidscroll-overlay]) { position: absolute; inset: 0; pointer-events: none; }
:where([data-vidscroll-section]) { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; opacity: 0; visibility: hidden; transition: opacity 0.4s ease, visibility 0s linear 0.4s; }
:where([data-vidscroll-section][data-active]) { opacity: 1; visibility: visible; transition: opacity 0.4s ease; }
:where([data-vidscroll-section][data-active] > *) { pointer-events: auto; }
:where([data-vidscroll-loader]) { position: absolute; inset: 0; z-index: 1; display: grid; place-items: center; background: rgb(0 0 0 / 0.55); color: #fff; font-family: system-ui, sans-serif; }
:where([data-vidscroll-loader][data-background]) { inset: auto 16px 16px auto; padding: 8px 14px; border-radius: 999px; pointer-events: none; }

React renders them in a <style> element next to each component. The core and the element add them to the page’s <head> once, as <style data-vidscroll-styles>, and they’re exported as the styles string from vidscroll/core.