Skip to content

Repository files navigation

mr-scroll

CILicense

The best custom scroll for the web.

Live demo here.

Features

  • Custom and easy to style scrollbar
  • Uses the native browser scrollbar behind the scenes -> smooth scrolling, middle mouse click drag works, follows the behavior you're used to
  • Behaves exactly like a native scrollbar (detects content size changes, so it's always visually in sync unlike every other custom scrollbar)
  • Different modes: scroll, auto, overlay, hidden
  • Show on hover
  • Hidden content fade (shows a fading effect to indicate there's hidden content out of view)
  • Emits various useful events you can handle (scrolled, state changed, position changed, top/bottom reached with configurable thresholds, etc)
    • Great for implementing infinite paging
  • Works exactly the same across supported browsers
  • Supported on all modern browsers, including mobile browsers

And finally, we have efficient idiomatic wrapper packages for popular frameworks (angular, react, vue2, vue3).

Packages

Can't find your framework? This means we don't have a wrapper for it just yet. Feel free to suggest/contribute one.

Support packages

We also have support packages:

All packages in the @mr-scroll org here: https://www.npmjs.com/org/mr-scroll

Config

Check the respective wrapper package and samples for an example usage.

NameTypeDefaultDescription
mode'auto' | 'overlay' | 'hidden''auto'The mode that the scroll will adapt.
topThresholdnumber50The top threshold in px. Affects when the topReached event is raised.
bottomThresholdnumber50The bottom threshold in px. Affects when the bottomReached event is raised.
leftThresholdnumber50The left threshold in px. Affects when the leftReached event is raised.
rightThresholdnumber50The right threshold in px. Affects when the rightReached event is raised.
showOnHoverbooleanfalseRespresents whether or not to show the scrollbar only on hover.

Events

Check the respective wrapper package or sample for an example usage.

NameEvent dataDescription
scrolled{ left: number; top: number }Raised whenever the scrollbar is scrolled.
topReachedN/ARaised when the top is reached, taken into account the topThreshold config.
bottomReachedN/ARaised when the bottom is reached, taken into account the bottomThreshold config.
leftReachedN/ARaised when the left is reached, taken into account the leftThreshold config.
rightReachedN/ARaised when the right is reached, taken into account the rightThreshold config.
positionHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed.
positionAbsoluteHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed without taking thresholds into account.
stateHChanged'hidden' | 'scrolling'Raised when the horizontal state is changed.
positionVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed.
positionAbsoluteVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed without taking thresholds into account.
stateVChanged'hidden' | 'scrolling'Raised when the vertical state is changed.

Mixins

Defined here.

The @mr-scroll/core package provides several helper mixins in SCSS. You'll always @include the mixins in the direct parent of an mr-scroll.

To use them, you'll import the pure file and include any mixin you want:

@import'@mr-scroll/core/src/scss/pure';
.foo {
@includemsc-[mixinname](...);
}

If you're using the SCSS module system:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.foo {
@includemsc.[mixinname](...);
}

As an example, using the height mixin:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.my-scroll-parent {
@includemsc.height(200px);
}

Styling

To style mr-scroll in our whole app we can set some global CSS variables. But keep in mind that this sets the styles for all scrolls in the whole hierarchy.

Here is a list of the CSS variables you can override, and their default values:

--mr-scroll-bar-size-normal:12px;
--mr-scroll-bar-size-overlay:8px;
--mr-scroll-bar-margin:3px;
--mr-scroll-track-color: transparent;
--mr-scroll-thumb-border-radius:2px;
--mr-scroll-thumb-color:#aaa;
--mr-scroll-hidden-content-fade-size:25px;

Sometimes you want to override a certain style just for one scroll without affecting the others. For that, you can use any of the override-* mixins in that mr-scroll's direct parent:

NameDescription
override-thumb-border-radiusOverrides the thumb border radius.
override-hidden-content-fade-sizeOverrides the hidden content fade size.

General usage

Generally, we want to control our scroll in only 3 different ways: fixed height, max height, or fully adaptive. Here is how to do each.

  • Fixed height: You'll use the height mixin on the direct parent for mr-scroll (or simply just set a height: ...px; on an .mr-scroll).

  • Max height: You'll use the max-height mixin on the direct parent for mr-scroll (or simply just set a max-height: ...px; on an .mr-scroll).

  • Adaptive: This is a bit harder to implement when you have a complex layout, but it's still easy. In complex layouts, flexible design doesn't always work well with scrolls. The trick is to use the flex-adaptive-container mixin we provide on parents, all the way up to the root container (or a fixed/absolute container). This will lead to a fully working adaptive layout. For an example of this, check the the full-page page in the angular sample.

Samples

Samples contain working examples of how to use mr-scroll.


CCSS

This project follows CCSS for CSS naming conventions.

About

The best custom scroll for the web.

Resources

Code of conduct

Stars

17 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - mrahhal/mr-scroll: The best custom scroll for the web. · GitHub
Skip to content

Repository files navigation

mr-scroll

CILicense

The best custom scroll for the web.

Live demo here.

Features

  • Custom and easy to style scrollbar
  • Uses the native browser scrollbar behind the scenes -> smooth scrolling, middle mouse click drag works, follows the behavior you're used to
  • Behaves exactly like a native scrollbar (detects content size changes, so it's always visually in sync unlike every other custom scrollbar)
  • Different modes: scroll, auto, overlay, hidden
  • Show on hover
  • Hidden content fade (shows a fading effect to indicate there's hidden content out of view)
  • Emits various useful events you can handle (scrolled, state changed, position changed, top/bottom reached with configurable thresholds, etc)
    • Great for implementing infinite paging
  • Works exactly the same across supported browsers
  • Supported on all modern browsers, including mobile browsers

And finally, we have efficient idiomatic wrapper packages for popular frameworks (angular, react, vue2, vue3).

Packages

Can't find your framework? This means we don't have a wrapper for it just yet. Feel free to suggest/contribute one.

Support packages

We also have support packages:

All packages in the @mr-scroll org here: https://www.npmjs.com/org/mr-scroll

Config

Check the respective wrapper package and samples for an example usage.

NameTypeDefaultDescription
mode'auto' | 'overlay' | 'hidden''auto'The mode that the scroll will adapt.
topThresholdnumber50The top threshold in px. Affects when the topReached event is raised.
bottomThresholdnumber50The bottom threshold in px. Affects when the bottomReached event is raised.
leftThresholdnumber50The left threshold in px. Affects when the leftReached event is raised.
rightThresholdnumber50The right threshold in px. Affects when the rightReached event is raised.
showOnHoverbooleanfalseRespresents whether or not to show the scrollbar only on hover.

Events

Check the respective wrapper package or sample for an example usage.

NameEvent dataDescription
scrolled{ left: number; top: number }Raised whenever the scrollbar is scrolled.
topReachedN/ARaised when the top is reached, taken into account the topThreshold config.
bottomReachedN/ARaised when the bottom is reached, taken into account the bottomThreshold config.
leftReachedN/ARaised when the left is reached, taken into account the leftThreshold config.
rightReachedN/ARaised when the right is reached, taken into account the rightThreshold config.
positionHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed.
positionAbsoluteHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed without taking thresholds into account.
stateHChanged'hidden' | 'scrolling'Raised when the horizontal state is changed.
positionVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed.
positionAbsoluteVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed without taking thresholds into account.
stateVChanged'hidden' | 'scrolling'Raised when the vertical state is changed.

Mixins

Defined here.

The @mr-scroll/core package provides several helper mixins in SCSS. You'll always @include the mixins in the direct parent of an mr-scroll.

To use them, you'll import the pure file and include any mixin you want:

@import'@mr-scroll/core/src/scss/pure';
.foo {
@includemsc-[mixinname](...);
}

If you're using the SCSS module system:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.foo {
@includemsc.[mixinname](...);
}

As an example, using the height mixin:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.my-scroll-parent {
@includemsc.height(200px);
}

Styling

To style mr-scroll in our whole app we can set some global CSS variables. But keep in mind that this sets the styles for all scrolls in the whole hierarchy.

Here is a list of the CSS variables you can override, and their default values:

--mr-scroll-bar-size-normal:12px;
--mr-scroll-bar-size-overlay:8px;
--mr-scroll-bar-margin:3px;
--mr-scroll-track-color: transparent;
--mr-scroll-thumb-border-radius:2px;
--mr-scroll-thumb-color:#aaa;
--mr-scroll-hidden-content-fade-size:25px;

Sometimes you want to override a certain style just for one scroll without affecting the others. For that, you can use any of the override-* mixins in that mr-scroll's direct parent:

NameDescription
override-thumb-border-radiusOverrides the thumb border radius.
override-hidden-content-fade-sizeOverrides the hidden content fade size.

General usage

Generally, we want to control our scroll in only 3 different ways: fixed height, max height, or fully adaptive. Here is how to do each.

  • Fixed height: You'll use the height mixin on the direct parent for mr-scroll (or simply just set a height: ...px; on an .mr-scroll).

  • Max height: You'll use the max-height mixin on the direct parent for mr-scroll (or simply just set a max-height: ...px; on an .mr-scroll).

  • Adaptive: This is a bit harder to implement when you have a complex layout, but it's still easy. In complex layouts, flexible design doesn't always work well with scrolls. The trick is to use the flex-adaptive-container mixin we provide on parents, all the way up to the root container (or a fixed/absolute container). This will lead to a fully working adaptive layout. For an example of this, check the the full-page page in the angular sample.

Samples

Samples contain working examples of how to use mr-scroll.


CCSS

This project follows CCSS for CSS naming conventions.

About

The best custom scroll for the web.

Resources

Code of conduct

Stars

17 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - mrahhal/mr-scroll: The best custom scroll for the web. · GitHub
Skip to content

Repository files navigation

mr-scroll

CILicense

The best custom scroll for the web.

Live demo here.

Features

  • Custom and easy to style scrollbar
  • Uses the native browser scrollbar behind the scenes -> smooth scrolling, middle mouse click drag works, follows the behavior you're used to
  • Behaves exactly like a native scrollbar (detects content size changes, so it's always visually in sync unlike every other custom scrollbar)
  • Different modes: scroll, auto, overlay, hidden
  • Show on hover
  • Hidden content fade (shows a fading effect to indicate there's hidden content out of view)
  • Emits various useful events you can handle (scrolled, state changed, position changed, top/bottom reached with configurable thresholds, etc)
    • Great for implementing infinite paging
  • Works exactly the same across supported browsers
  • Supported on all modern browsers, including mobile browsers

And finally, we have efficient idiomatic wrapper packages for popular frameworks (angular, react, vue2, vue3).

Packages

Can't find your framework? This means we don't have a wrapper for it just yet. Feel free to suggest/contribute one.

Support packages

We also have support packages:

All packages in the @mr-scroll org here: https://www.npmjs.com/org/mr-scroll

Config

Check the respective wrapper package and samples for an example usage.

NameTypeDefaultDescription
mode'auto' | 'overlay' | 'hidden''auto'The mode that the scroll will adapt.
topThresholdnumber50The top threshold in px. Affects when the topReached event is raised.
bottomThresholdnumber50The bottom threshold in px. Affects when the bottomReached event is raised.
leftThresholdnumber50The left threshold in px. Affects when the leftReached event is raised.
rightThresholdnumber50The right threshold in px. Affects when the rightReached event is raised.
showOnHoverbooleanfalseRespresents whether or not to show the scrollbar only on hover.

Events

Check the respective wrapper package or sample for an example usage.

NameEvent dataDescription
scrolled{ left: number; top: number }Raised whenever the scrollbar is scrolled.
topReachedN/ARaised when the top is reached, taken into account the topThreshold config.
bottomReachedN/ARaised when the bottom is reached, taken into account the bottomThreshold config.
leftReachedN/ARaised when the left is reached, taken into account the leftThreshold config.
rightReachedN/ARaised when the right is reached, taken into account the rightThreshold config.
positionHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed.
positionAbsoluteHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed without taking thresholds into account.
stateHChanged'hidden' | 'scrolling'Raised when the horizontal state is changed.
positionVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed.
positionAbsoluteVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed without taking thresholds into account.
stateVChanged'hidden' | 'scrolling'Raised when the vertical state is changed.

Mixins

Defined here.

The @mr-scroll/core package provides several helper mixins in SCSS. You'll always @include the mixins in the direct parent of an mr-scroll.

To use them, you'll import the pure file and include any mixin you want:

@import'@mr-scroll/core/src/scss/pure';
.foo {
@includemsc-[mixinname](...);
}

If you're using the SCSS module system:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.foo {
@includemsc.[mixinname](...);
}

As an example, using the height mixin:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.my-scroll-parent {
@includemsc.height(200px);
}

Styling

To style mr-scroll in our whole app we can set some global CSS variables. But keep in mind that this sets the styles for all scrolls in the whole hierarchy.

Here is a list of the CSS variables you can override, and their default values:

--mr-scroll-bar-size-normal:12px;
--mr-scroll-bar-size-overlay:8px;
--mr-scroll-bar-margin:3px;
--mr-scroll-track-color: transparent;
--mr-scroll-thumb-border-radius:2px;
--mr-scroll-thumb-color:#aaa;
--mr-scroll-hidden-content-fade-size:25px;

Sometimes you want to override a certain style just for one scroll without affecting the others. For that, you can use any of the override-* mixins in that mr-scroll's direct parent:

NameDescription
override-thumb-border-radiusOverrides the thumb border radius.
override-hidden-content-fade-sizeOverrides the hidden content fade size.

General usage

Generally, we want to control our scroll in only 3 different ways: fixed height, max height, or fully adaptive. Here is how to do each.

  • Fixed height: You'll use the height mixin on the direct parent for mr-scroll (or simply just set a height: ...px; on an .mr-scroll).

  • Max height: You'll use the max-height mixin on the direct parent for mr-scroll (or simply just set a max-height: ...px; on an .mr-scroll).

  • Adaptive: This is a bit harder to implement when you have a complex layout, but it's still easy. In complex layouts, flexible design doesn't always work well with scrolls. The trick is to use the flex-adaptive-container mixin we provide on parents, all the way up to the root container (or a fixed/absolute container). This will lead to a fully working adaptive layout. For an example of this, check the the full-page page in the angular sample.

Samples

Samples contain working examples of how to use mr-scroll.


CCSS

This project follows CCSS for CSS naming conventions.

About

The best custom scroll for the web.

Resources

Code of conduct

Stars

17 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - mrahhal/mr-scroll: The best custom scroll for the web. · GitHub
Skip to content

Repository files navigation

mr-scroll

CILicense

The best custom scroll for the web.

Live demo here.

Features

  • Custom and easy to style scrollbar
  • Uses the native browser scrollbar behind the scenes -> smooth scrolling, middle mouse click drag works, follows the behavior you're used to
  • Behaves exactly like a native scrollbar (detects content size changes, so it's always visually in sync unlike every other custom scrollbar)
  • Different modes: scroll, auto, overlay, hidden
  • Show on hover
  • Hidden content fade (shows a fading effect to indicate there's hidden content out of view)
  • Emits various useful events you can handle (scrolled, state changed, position changed, top/bottom reached with configurable thresholds, etc)
    • Great for implementing infinite paging
  • Works exactly the same across supported browsers
  • Supported on all modern browsers, including mobile browsers

And finally, we have efficient idiomatic wrapper packages for popular frameworks (angular, react, vue2, vue3).

Packages

Can't find your framework? This means we don't have a wrapper for it just yet. Feel free to suggest/contribute one.

Support packages

We also have support packages:

All packages in the @mr-scroll org here: https://www.npmjs.com/org/mr-scroll

Config

Check the respective wrapper package and samples for an example usage.

NameTypeDefaultDescription
mode'auto' | 'overlay' | 'hidden''auto'The mode that the scroll will adapt.
topThresholdnumber50The top threshold in px. Affects when the topReached event is raised.
bottomThresholdnumber50The bottom threshold in px. Affects when the bottomReached event is raised.
leftThresholdnumber50The left threshold in px. Affects when the leftReached event is raised.
rightThresholdnumber50The right threshold in px. Affects when the rightReached event is raised.
showOnHoverbooleanfalseRespresents whether or not to show the scrollbar only on hover.

Events

Check the respective wrapper package or sample for an example usage.

NameEvent dataDescription
scrolled{ left: number; top: number }Raised whenever the scrollbar is scrolled.
topReachedN/ARaised when the top is reached, taken into account the topThreshold config.
bottomReachedN/ARaised when the bottom is reached, taken into account the bottomThreshold config.
leftReachedN/ARaised when the left is reached, taken into account the leftThreshold config.
rightReachedN/ARaised when the right is reached, taken into account the rightThreshold config.
positionHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed.
positionAbsoluteHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed without taking thresholds into account.
stateHChanged'hidden' | 'scrolling'Raised when the horizontal state is changed.
positionVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed.
positionAbsoluteVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed without taking thresholds into account.
stateVChanged'hidden' | 'scrolling'Raised when the vertical state is changed.

Mixins

Defined here.

The @mr-scroll/core package provides several helper mixins in SCSS. You'll always @include the mixins in the direct parent of an mr-scroll.

To use them, you'll import the pure file and include any mixin you want:

@import'@mr-scroll/core/src/scss/pure';
.foo {
@includemsc-[mixinname](...);
}

If you're using the SCSS module system:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.foo {
@includemsc.[mixinname](...);
}

As an example, using the height mixin:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.my-scroll-parent {
@includemsc.height(200px);
}

Styling

To style mr-scroll in our whole app we can set some global CSS variables. But keep in mind that this sets the styles for all scrolls in the whole hierarchy.

Here is a list of the CSS variables you can override, and their default values:

--mr-scroll-bar-size-normal:12px;
--mr-scroll-bar-size-overlay:8px;
--mr-scroll-bar-margin:3px;
--mr-scroll-track-color: transparent;
--mr-scroll-thumb-border-radius:2px;
--mr-scroll-thumb-color:#aaa;
--mr-scroll-hidden-content-fade-size:25px;

Sometimes you want to override a certain style just for one scroll without affecting the others. For that, you can use any of the override-* mixins in that mr-scroll's direct parent:

NameDescription
override-thumb-border-radiusOverrides the thumb border radius.
override-hidden-content-fade-sizeOverrides the hidden content fade size.

General usage

Generally, we want to control our scroll in only 3 different ways: fixed height, max height, or fully adaptive. Here is how to do each.

  • Fixed height: You'll use the height mixin on the direct parent for mr-scroll (or simply just set a height: ...px; on an .mr-scroll).

  • Max height: You'll use the max-height mixin on the direct parent for mr-scroll (or simply just set a max-height: ...px; on an .mr-scroll).

  • Adaptive: This is a bit harder to implement when you have a complex layout, but it's still easy. In complex layouts, flexible design doesn't always work well with scrolls. The trick is to use the flex-adaptive-container mixin we provide on parents, all the way up to the root container (or a fixed/absolute container). This will lead to a fully working adaptive layout. For an example of this, check the the full-page page in the angular sample.

Samples

Samples contain working examples of how to use mr-scroll.


CCSS

This project follows CCSS for CSS naming conventions.

About

The best custom scroll for the web.

Resources

Code of conduct

Stars

17 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - mrahhal/mr-scroll: The best custom scroll for the web. · GitHub
Skip to content

Repository files navigation

mr-scroll

CILicense

The best custom scroll for the web.

Live demo here.

Features

  • Custom and easy to style scrollbar
  • Uses the native browser scrollbar behind the scenes -> smooth scrolling, middle mouse click drag works, follows the behavior you're used to
  • Behaves exactly like a native scrollbar (detects content size changes, so it's always visually in sync unlike every other custom scrollbar)
  • Different modes: scroll, auto, overlay, hidden
  • Show on hover
  • Hidden content fade (shows a fading effect to indicate there's hidden content out of view)
  • Emits various useful events you can handle (scrolled, state changed, position changed, top/bottom reached with configurable thresholds, etc)
    • Great for implementing infinite paging
  • Works exactly the same across supported browsers
  • Supported on all modern browsers, including mobile browsers

And finally, we have efficient idiomatic wrapper packages for popular frameworks (angular, react, vue2, vue3).

Packages

Can't find your framework? This means we don't have a wrapper for it just yet. Feel free to suggest/contribute one.

Support packages

We also have support packages:

All packages in the @mr-scroll org here: https://www.npmjs.com/org/mr-scroll

Config

Check the respective wrapper package and samples for an example usage.

NameTypeDefaultDescription
mode'auto' | 'overlay' | 'hidden''auto'The mode that the scroll will adapt.
topThresholdnumber50The top threshold in px. Affects when the topReached event is raised.
bottomThresholdnumber50The bottom threshold in px. Affects when the bottomReached event is raised.
leftThresholdnumber50The left threshold in px. Affects when the leftReached event is raised.
rightThresholdnumber50The right threshold in px. Affects when the rightReached event is raised.
showOnHoverbooleanfalseRespresents whether or not to show the scrollbar only on hover.

Events

Check the respective wrapper package or sample for an example usage.

NameEvent dataDescription
scrolled{ left: number; top: number }Raised whenever the scrollbar is scrolled.
topReachedN/ARaised when the top is reached, taken into account the topThreshold config.
bottomReachedN/ARaised when the bottom is reached, taken into account the bottomThreshold config.
leftReachedN/ARaised when the left is reached, taken into account the leftThreshold config.
rightReachedN/ARaised when the right is reached, taken into account the rightThreshold config.
positionHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed.
positionAbsoluteHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed without taking thresholds into account.
stateHChanged'hidden' | 'scrolling'Raised when the horizontal state is changed.
positionVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed.
positionAbsoluteVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed without taking thresholds into account.
stateVChanged'hidden' | 'scrolling'Raised when the vertical state is changed.

Mixins

Defined here.

The @mr-scroll/core package provides several helper mixins in SCSS. You'll always @include the mixins in the direct parent of an mr-scroll.

To use them, you'll import the pure file and include any mixin you want:

@import'@mr-scroll/core/src/scss/pure';
.foo {
@includemsc-[mixinname](...);
}

If you're using the SCSS module system:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.foo {
@includemsc.[mixinname](...);
}

As an example, using the height mixin:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.my-scroll-parent {
@includemsc.height(200px);
}

Styling

To style mr-scroll in our whole app we can set some global CSS variables. But keep in mind that this sets the styles for all scrolls in the whole hierarchy.

Here is a list of the CSS variables you can override, and their default values:

--mr-scroll-bar-size-normal:12px;
--mr-scroll-bar-size-overlay:8px;
--mr-scroll-bar-margin:3px;
--mr-scroll-track-color: transparent;
--mr-scroll-thumb-border-radius:2px;
--mr-scroll-thumb-color:#aaa;
--mr-scroll-hidden-content-fade-size:25px;

Sometimes you want to override a certain style just for one scroll without affecting the others. For that, you can use any of the override-* mixins in that mr-scroll's direct parent:

NameDescription
override-thumb-border-radiusOverrides the thumb border radius.
override-hidden-content-fade-sizeOverrides the hidden content fade size.

General usage

Generally, we want to control our scroll in only 3 different ways: fixed height, max height, or fully adaptive. Here is how to do each.

  • Fixed height: You'll use the height mixin on the direct parent for mr-scroll (or simply just set a height: ...px; on an .mr-scroll).

  • Max height: You'll use the max-height mixin on the direct parent for mr-scroll (or simply just set a max-height: ...px; on an .mr-scroll).

  • Adaptive: This is a bit harder to implement when you have a complex layout, but it's still easy. In complex layouts, flexible design doesn't always work well with scrolls. The trick is to use the flex-adaptive-container mixin we provide on parents, all the way up to the root container (or a fixed/absolute container). This will lead to a fully working adaptive layout. For an example of this, check the the full-page page in the angular sample.

Samples

Samples contain working examples of how to use mr-scroll.


CCSS

This project follows CCSS for CSS naming conventions.

About

The best custom scroll for the web.

Resources

Code of conduct

Stars

17 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - mrahhal/mr-scroll: The best custom scroll for the web. · GitHub
Skip to content

Repository files navigation

mr-scroll

CILicense

The best custom scroll for the web.

Live demo here.

Features

  • Custom and easy to style scrollbar
  • Uses the native browser scrollbar behind the scenes -> smooth scrolling, middle mouse click drag works, follows the behavior you're used to
  • Behaves exactly like a native scrollbar (detects content size changes, so it's always visually in sync unlike every other custom scrollbar)
  • Different modes: scroll, auto, overlay, hidden
  • Show on hover
  • Hidden content fade (shows a fading effect to indicate there's hidden content out of view)
  • Emits various useful events you can handle (scrolled, state changed, position changed, top/bottom reached with configurable thresholds, etc)
    • Great for implementing infinite paging
  • Works exactly the same across supported browsers
  • Supported on all modern browsers, including mobile browsers

And finally, we have efficient idiomatic wrapper packages for popular frameworks (angular, react, vue2, vue3).

Packages

Can't find your framework? This means we don't have a wrapper for it just yet. Feel free to suggest/contribute one.

Support packages

We also have support packages:

All packages in the @mr-scroll org here: https://www.npmjs.com/org/mr-scroll

Config

Check the respective wrapper package and samples for an example usage.

NameTypeDefaultDescription
mode'auto' | 'overlay' | 'hidden''auto'The mode that the scroll will adapt.
topThresholdnumber50The top threshold in px. Affects when the topReached event is raised.
bottomThresholdnumber50The bottom threshold in px. Affects when the bottomReached event is raised.
leftThresholdnumber50The left threshold in px. Affects when the leftReached event is raised.
rightThresholdnumber50The right threshold in px. Affects when the rightReached event is raised.
showOnHoverbooleanfalseRespresents whether or not to show the scrollbar only on hover.

Events

Check the respective wrapper package or sample for an example usage.

NameEvent dataDescription
scrolled{ left: number; top: number }Raised whenever the scrollbar is scrolled.
topReachedN/ARaised when the top is reached, taken into account the topThreshold config.
bottomReachedN/ARaised when the bottom is reached, taken into account the bottomThreshold config.
leftReachedN/ARaised when the left is reached, taken into account the leftThreshold config.
rightReachedN/ARaised when the right is reached, taken into account the rightThreshold config.
positionHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed.
positionAbsoluteHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed without taking thresholds into account.
stateHChanged'hidden' | 'scrolling'Raised when the horizontal state is changed.
positionVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed.
positionAbsoluteVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed without taking thresholds into account.
stateVChanged'hidden' | 'scrolling'Raised when the vertical state is changed.

Mixins

Defined here.

The @mr-scroll/core package provides several helper mixins in SCSS. You'll always @include the mixins in the direct parent of an mr-scroll.

To use them, you'll import the pure file and include any mixin you want:

@import'@mr-scroll/core/src/scss/pure';
.foo {
@includemsc-[mixinname](...);
}

If you're using the SCSS module system:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.foo {
@includemsc.[mixinname](...);
}

As an example, using the height mixin:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.my-scroll-parent {
@includemsc.height(200px);
}

Styling

To style mr-scroll in our whole app we can set some global CSS variables. But keep in mind that this sets the styles for all scrolls in the whole hierarchy.

Here is a list of the CSS variables you can override, and their default values:

--mr-scroll-bar-size-normal:12px;
--mr-scroll-bar-size-overlay:8px;
--mr-scroll-bar-margin:3px;
--mr-scroll-track-color: transparent;
--mr-scroll-thumb-border-radius:2px;
--mr-scroll-thumb-color:#aaa;
--mr-scroll-hidden-content-fade-size:25px;

Sometimes you want to override a certain style just for one scroll without affecting the others. For that, you can use any of the override-* mixins in that mr-scroll's direct parent:

NameDescription
override-thumb-border-radiusOverrides the thumb border radius.
override-hidden-content-fade-sizeOverrides the hidden content fade size.

General usage

Generally, we want to control our scroll in only 3 different ways: fixed height, max height, or fully adaptive. Here is how to do each.

  • Fixed height: You'll use the height mixin on the direct parent for mr-scroll (or simply just set a height: ...px; on an .mr-scroll).

  • Max height: You'll use the max-height mixin on the direct parent for mr-scroll (or simply just set a max-height: ...px; on an .mr-scroll).

  • Adaptive: This is a bit harder to implement when you have a complex layout, but it's still easy. In complex layouts, flexible design doesn't always work well with scrolls. The trick is to use the flex-adaptive-container mixin we provide on parents, all the way up to the root container (or a fixed/absolute container). This will lead to a fully working adaptive layout. For an example of this, check the the full-page page in the angular sample.

Samples

Samples contain working examples of how to use mr-scroll.


CCSS

This project follows CCSS for CSS naming conventions.

About

The best custom scroll for the web.

Resources

Code of conduct

Stars

17 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - mrahhal/mr-scroll: The best custom scroll for the web. · GitHub
Skip to content

Repository files navigation

mr-scroll

CILicense

The best custom scroll for the web.

Live demo here.

Features

  • Custom and easy to style scrollbar
  • Uses the native browser scrollbar behind the scenes -> smooth scrolling, middle mouse click drag works, follows the behavior you're used to
  • Behaves exactly like a native scrollbar (detects content size changes, so it's always visually in sync unlike every other custom scrollbar)
  • Different modes: scroll, auto, overlay, hidden
  • Show on hover
  • Hidden content fade (shows a fading effect to indicate there's hidden content out of view)
  • Emits various useful events you can handle (scrolled, state changed, position changed, top/bottom reached with configurable thresholds, etc)
    • Great for implementing infinite paging
  • Works exactly the same across supported browsers
  • Supported on all modern browsers, including mobile browsers

And finally, we have efficient idiomatic wrapper packages for popular frameworks (angular, react, vue2, vue3).

Packages

Can't find your framework? This means we don't have a wrapper for it just yet. Feel free to suggest/contribute one.

Support packages

We also have support packages:

All packages in the @mr-scroll org here: https://www.npmjs.com/org/mr-scroll

Config

Check the respective wrapper package and samples for an example usage.

NameTypeDefaultDescription
mode'auto' | 'overlay' | 'hidden''auto'The mode that the scroll will adapt.
topThresholdnumber50The top threshold in px. Affects when the topReached event is raised.
bottomThresholdnumber50The bottom threshold in px. Affects when the bottomReached event is raised.
leftThresholdnumber50The left threshold in px. Affects when the leftReached event is raised.
rightThresholdnumber50The right threshold in px. Affects when the rightReached event is raised.
showOnHoverbooleanfalseRespresents whether or not to show the scrollbar only on hover.

Events

Check the respective wrapper package or sample for an example usage.

NameEvent dataDescription
scrolled{ left: number; top: number }Raised whenever the scrollbar is scrolled.
topReachedN/ARaised when the top is reached, taken into account the topThreshold config.
bottomReachedN/ARaised when the bottom is reached, taken into account the bottomThreshold config.
leftReachedN/ARaised when the left is reached, taken into account the leftThreshold config.
rightReachedN/ARaised when the right is reached, taken into account the rightThreshold config.
positionHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed.
positionAbsoluteHChanged'start' | 'middle' | 'end' | 'full'Raised when the horizontal position is changed without taking thresholds into account.
stateHChanged'hidden' | 'scrolling'Raised when the horizontal state is changed.
positionVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed.
positionAbsoluteVChanged'start' | 'middle' | 'end' | 'full'Raised when the vertical position is changed without taking thresholds into account.
stateVChanged'hidden' | 'scrolling'Raised when the vertical state is changed.

Mixins

Defined here.

The @mr-scroll/core package provides several helper mixins in SCSS. You'll always @include the mixins in the direct parent of an mr-scroll.

To use them, you'll import the pure file and include any mixin you want:

@import'@mr-scroll/core/src/scss/pure';
.foo {
@includemsc-[mixinname](...);
}

If you're using the SCSS module system:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.foo {
@includemsc.[mixinname](...);
}

As an example, using the height mixin:

@use'@mr-scroll/core/src/scss/pure'asmsc;
.my-scroll-parent {
@includemsc.height(200px);
}

Styling

To style mr-scroll in our whole app we can set some global CSS variables. But keep in mind that this sets the styles for all scrolls in the whole hierarchy.

Here is a list of the CSS variables you can override, and their default values:

--mr-scroll-bar-size-normal:12px;
--mr-scroll-bar-size-overlay:8px;
--mr-scroll-bar-margin:3px;
--mr-scroll-track-color: transparent;
--mr-scroll-thumb-border-radius:2px;
--mr-scroll-thumb-color:#aaa;
--mr-scroll-hidden-content-fade-size:25px;

Sometimes you want to override a certain style just for one scroll without affecting the others. For that, you can use any of the override-* mixins in that mr-scroll's direct parent:

NameDescription
override-thumb-border-radiusOverrides the thumb border radius.
override-hidden-content-fade-sizeOverrides the hidden content fade size.

General usage

Generally, we want to control our scroll in only 3 different ways: fixed height, max height, or fully adaptive. Here is how to do each.

  • Fixed height: You'll use the height mixin on the direct parent for mr-scroll (or simply just set a height: ...px; on an .mr-scroll).

  • Max height: You'll use the max-height mixin on the direct parent for mr-scroll (or simply just set a max-height: ...px; on an .mr-scroll).

  • Adaptive: This is a bit harder to implement when you have a complex layout, but it's still easy. In complex layouts, flexible design doesn't always work well with scrolls. The trick is to use the flex-adaptive-container mixin we provide on parents, all the way up to the root container (or a fixed/absolute container). This will lead to a fully working adaptive layout. For an example of this, check the the full-page page in the angular sample.

Samples

Samples contain working examples of how to use mr-scroll.


CCSS

This project follows CCSS for CSS naming conventions.

About

The best custom scroll for the web.

Resources

Code of conduct

Stars

17 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages