Skip to content

Instantly share code, notes, and snippets.

@mrkwatz
Last active August 5, 2023 03:18
Show Gist options
  • Save mrkwatz/277fb19d210a7539304ca2388f24d8e3 to your computer and use it in GitHub Desktop.
Save mrkwatz/277fb19d210a7539304ca2388f24d8e3 to your computer and use it in GitHub Desktop.
Firefox 57 Windows 10 UWP Style Overlay Scrollbars

As far as I am aware the time has come and as of Firefox 72 XUL has been stripped from firefox and so the method used to inject this scrollbar theme is no longer supported -- reference the following for future scroll themes:

Mozilla is currently working to phase out the APIs used to make this theme work. I will try to maintain each version until that time but eventually there will be no workaround. When that time comes there is a new, but more limited api for applying simple themes to scrollbars. In nightly I am currently using the following userContent.css

:root{
	scrollbar-width: thin;
	scrollbar-color: rgb(82, 82, 82) rgb(31, 31, 31);
}

Preview

Installation

  • in about:config check that toolkit.legacyUserProfileCustomizations.stylesheets is set to true
  • Save each file to your Firefox profile's chrome folder, creating one if the folder does not already exist. More information: http://kb.mozillazine.org/UserChrome.css
    • If userChrome.css has already been modified in your profile add the userChrome.css rules below to that existing file. Note there should only be one xul namespace declaration, which should be the first line in the file.
  • Restart Firefox.

Notes

  • Behavior is changed. The up/down/left/right buttons are removed, and by default the feature to click a location on the scrollbar to scroll to it is disabled so that the scroll bar can be clicked through when it overlays an element on the page. Remove the pointer-events rules to restore.
  • The styles can be toggled at any time by going to the Tools menu in firefox and toggling the Windows 10 Style Scrollbars option. The page must be refreshed for the window scrollbars to update, but on-page elements should change instantly. Deprecated
  • Style may be edited in userChrome.js. For changes to take hold, clear your cache in ...\AppData\Local\Mozilla\Firefox\Profiles by deleting the folder for your profile.
  • Live debugging may be performed via Browser Toolbox console https://developer.mozilla.org/en-US/docs/Tools/Browser_Toolbox
    • Make edits to userChrome.js in a text editor and copy/paste the entire contents of the file into the console. Execute and refresh a page to see changes. Rules are cached so if you set a rule you need to clear your profile cache to if you want to remove the rule.
  • Known issue with hover states for window scrollbars cause transition flashing. This prevents full replication of windows 10 style scrollbar behavior, with the workaround being a simpler fade in/out rather than a full scaling animation. On-page elements do not have the hover state issues.

Changelog

  • 0.0.8
    • Integrated changes from the comments of this gist to increase compatibility.
    • The tools menu toggle has been removed.
  • 0.0.7.1
    • Addressed change with Firefox 69.0 that prevents script loading from a file by directly embedding the XML as a data url.
    • The unencoded dataurl (userChrome.xml) is found below for reference
  • 0.0.7
    • Changed how youtube is detected. The method is still inconsistent and a scroll bar will some times be displayed.
    • On youtube.com the scrollbar will be invisible except when being hovered over.
  • 0.0.6
    • Added a special case to hide scrollbars on youtube.com because google forgot what Fullscreen is supposed to be.
  • 0.0.5
    • Added z-index rule to fix compositing/click issues that came about some time after FF 57 (thanks @joshieecs)
    • Added rules to address linux/gtk compatability (thanks @axel668)
  • 0.0.4
    • Modified css string to use backticks and so not require formatting chars
  • 0.0.3
    • New transition animations
  • 0.0.2
    • Removed unused rules
    • Scrollbar width changed to 12px from 16px to better match native style

License

Reference the @notes in userChrome.js for licensing information of sourced parts. The css content provided by me is licensed as follows:

ISC License (ISC)

Copyright 2018 @MrKwatz

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
toolbarbutton#alltabs-button {
-moz-binding: url(data:text/plain;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8IS0tIENvcHlyaWdodCAoYykgMjAxNyBIYWdnYWkgTnVjaGkNCkF2YWlsYWJsZSBmb3IgdXNlIHVuZGVyIHRoZSBNSVQgTGljZW5zZToNCmh0dHBzOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvTUlUDQogLS0+DQoNCjwhLS0gUnVuIHVzZXJDaHJvbWUuanMvdXNlckNocm9tZS54dWwgYW5kIC51Yy5qcy8udWMueHVsLy5jc3MgZmlsZXMgIC0tPg0KPGJpbmRpbmdzIHhtbG5zPSJodHRwOi8vd3d3Lm1vemlsbGEub3JnL3hibCI+DQogICAgPGJpbmRpbmcgaWQ9ImpzIj4NCiAgICAgICAgPGltcGxlbWVudGF0aW9uPg0KICAgICAgICAgICAgPGNvbnN0cnVjdG9yPjwhW0NEQVRBWw0KICAgICAgICAgICAgICAgIGlmKHdpbmRvdy51c2VyQ2hyb21lSnNNb2QpIHJldHVybjsNCiAgICAgICAgICAgICAgICB3aW5kb3cudXNlckNocm9tZUpzTW9kID0gdHJ1ZTsNCg0KICAgICAgICAgICAgICAgIHZhciBjaHJvbWVGaWxlcyA9IEZpbGVVdGlscy5nZXREaXIoIlVDaHJtIiwgW10pLmRpcmVjdG9yeUVudHJpZXM7DQogICAgICAgICAgICAgICAgdmFyIHh1bEZpbGVzID0gW107DQogICAgICAgICAgICAgICAgdmFyIHNzcyA9IENjWydAbW96aWxsYS5vcmcvY29udGVudC9zdHlsZS1zaGVldC1zZXJ2aWNlOzEnXS5nZXRTZXJ2aWNlKENpLm5zSVN0eWxlU2hlZXRTZXJ2aWNlKTsNCg0KICAgICAgICAgICAgICAgIHdoaWxlKGNocm9tZUZpbGVzLmhhc01vcmVFbGVtZW50cygpKSB7DQogICAgICAgICAgICAgICAgICAgIHZhciBmaWxlID0gY2hyb21lRmlsZXMuZ2V0TmV4dCgpLlF1ZXJ5SW50ZXJmYWNlKENpLm5zSUZpbGUpOw0KICAgICAgICAgICAgICAgICAgICB2YXIgZmlsZVVSSSA9IFNlcnZpY2VzLmlvLm5ld0ZpbGVVUkkoZmlsZSk7DQoNCiAgICAgICAgICAgICAgICAgICAgaWYoZmlsZS5pc0ZpbGUoKSkgew0KICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJub25lIjsNCiAgICAgICAgICAgICAgICAgICAgICAgIGlmKC8oXnVzZXJDaHJvbWV8LnVjKS5qcyQvaS50ZXN0KGZpbGUubGVhZk5hbWUpKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJ1c2VyY2hyb21lL2pzIjsNCiAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYoLyhedXNlckNocm9tZXwudWMpLnh1bCQvaS50ZXN0KGZpbGUubGVhZk5hbWUpKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJ1c2VyY2hyb21lL3h1bCI7DQogICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmKC8uYXMuY3NzJC9pLnRlc3QoZmlsZS5sZWFmTmFtZSkpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImFnZW50c2hlZXQiOw0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZigvXig/ISh1c2VyQ2hyb21lfHVzZXJDb250ZW50KS5jc3MkKS4rLmNzcyQvaS50ZXN0KGZpbGUubGVhZk5hbWUpKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJ1c2Vyc2hlZXQiOw0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgaWYodHlwZSAhPSAibm9uZSIpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygiLS0tLS0tLS0tLVwgIiArIGZpbGUubGVhZk5hbWUgKyAiICgiICsgdHlwZSArICIpIik7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYodHlwZSA9PSAidXNlcmNocm9tZS9qcyIpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNlcnZpY2VzLnNjcmlwdGxvYWRlci5sb2FkU3ViU2NyaXB0V2l0aE9wdGlvbnMoZmlsZVVSSS5zcGVjLCB7dGFyZ2V0OiB3aW5kb3csIGlnbm9yZUNhY2hlOiB0cnVlfSk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZih0eXBlID09ICJ1c2VyY2hyb21lL3h1bCIpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHh1bEZpbGVzLnB1c2goZmlsZVVSSS5zcGVjKTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmKHR5cGUgPT0gImFnZW50c2hlZXQiKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZighc3NzLnNoZWV0UmVnaXN0ZXJlZChmaWxlVVJJLCBzc3MuQUdFTlRfU0hFRVQpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcy5sb2FkQW5kUmVnaXN0ZXJTaGVldChmaWxlVVJJLCBzc3MuQUdFTlRfU0hFRVQpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYodHlwZSA9PSAidXNlcnNoZWV0Iikgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYoIXNzcy5zaGVldFJlZ2lzdGVyZWQoZmlsZVVSSSwgc3NzLlVTRVJfU0hFRVQpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcy5sb2FkQW5kUmVnaXN0ZXJTaGVldChmaWxlVVJJLCBzc3MuVVNFUl9TSEVFVCk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoKGUpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coIiMjIyMjIyMjIyMgRVJST1I6ICIgKyBlICsgIiBhdCAiICsgZS5saW5lTnVtYmVyICsgIjoiICsgZS5jb2x1bW5OdW1iZXIpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygiLS0tLS0tLS0tLS8gIiArIGZpbGUubGVhZk5hbWUpOw0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiBsb2FkWFVMKCkgew0KICAgICAgICAgICAgICAgICAgICBpZih4dWxGaWxlcy5sZW5ndGggPiAwKSB7DQogICAgICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5sb2FkT3ZlcmxheSh4dWxGaWxlcy5zaGlmdCgpLCBudWxsKTsNCiAgICAgICAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQobG9hZFhVTCwgNSk7DQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICB9LCAwKTsNCiAgICAgICAgICAgIF1dPjwvY29uc3RydWN0b3I+DQogICAgICAgIDwvaW1wbGVtZW50YXRpb24+DQogICAgPC9iaW5kaW5nPg0KPC9iaW5kaW5ncz4=);
}
// ==UserScript==
// @name userChrome.js
// @namespace scrollbars_win10
// @version 0.0.8
// @note Windows 10 style by /u/mrkwatz https://www.reddit.com/r/FirefoxCSS/comments/7fkha6/firefox_57_windows_10_uwp_style_overlay_scrollbars/
// @note Brought to Firefox 57 by /u/Wiidesire https://www.reddit.com/r/firefox/comments/7f6kc4/floating_scrollbar_finally_possible_in_firefox_57/
// @note userChrome.js https://github.com/nuchi/firefox-quantum-userchromejs
// @note Forked from https://github.com/Endor8/userChrome.js/blob/master/floatingscrollbar/FloatingScrollbar.uc.js
// ==/UserScript==
(function () {
var css = `
:not(select):not(hbox) > scrollbar {
-moz-appearance: none!important;
position: relative!important;
background-color: transparent;
pointer-events: none;
z-index: 2147483647;
}
:not(select):not(hbox) > scrollbar * {
-moz-appearance: none!important;
background-color: transparent!important;
pointer-events: none;
}
:not(select):not(hbox) > scrollbar thumb {
-moz-appearance: none!important;
background-color: transparent;
pointer-events: auto;
}
:not(select):not(hbox) > scrollbar[orient = "vertical"] {
min-width: 12px!important;
-moz-margin-start: -12px;/*margin to fill the whole render window with content and overlay the scrollbars*/
}
:not(select):not(hbox) > scrollbar[orient = "horizontal"] {
height: 12px!important;
margin-top: -12px;
}
:not(select):not(hbox) > scrollbar[orient = "vertical"] thumb {
border-right: 2px solid rgba(133, 132, 131, 1);
width: 12px;
min-height: 12px;
transition: border 0.1s ease-in;
}
:not(select):not(hbox) > scrollbar[orient = "horizontal"] thumb {
border-bottom: 2px solid rgba(133, 132, 131, 1);
min-width: 12px;
transition: border 0.1s ease-in;
}
:not(select):not(hbox) > scrollbar:hover {
background-color: rgba(0, 0, 0, 0.25);
max-width: 12px!important;
point-events: auto;
}
:not(select):not(hbox) > scrollbar:hover thumb {
border-width: 12px;
transition: border 0s linear;
}
:not(select):not(hbox) > scrollbar scrollbarbutton, :not(select):not(hbox) > scrollbar gripper {
/*display: none;*/
}
@-moz-document domain("youtube.com") {
:not(select):not(hbox) > scrollbar[orient = "vertical"]:not(:hover) thumb {
opacity: 0 !important;
}
}
`;
var sss = Cc['@mozilla.org/content/style-sheet-service;1'].getService(Ci.nsIStyleSheetService);
var uri = makeURI('data:text/css;charset=UTF=8,' + encodeURIComponent(css));
sss.loadAndRegisterSheet(uri, sss.AGENT_SHEET);
})();
<?xml version=\"1.0\"?>
<!-- Copyright (c) 2017 Haggai Nuchi
Available for use under the MIT License:
https://opensource.org/licenses/MIT
-->
<!-- Run userChrome.js/userChrome.xul and .uc.js/.uc.xul/.css files -->
<bindings xmlns=\"http://www.mozilla.org/xbl\">
<binding id=\"js\">
<implementation>
<constructor><![CDATA[
if(window.userChromeJsMod) return;
window.userChromeJsMod = true;
var chromeFiles = FileUtils.getDir(\"UChrm\", []).directoryEntries;
var xulFiles = [];
var sss = Cc['@mozilla.org/content/style-sheet-service;1'].getService(Ci.nsIStyleSheetService);
while(chromeFiles.hasMoreElements()) {
var file = chromeFiles.getNext().QueryInterface(Ci.nsIFile);
var fileURI = Services.io.newFileURI(file);
if(file.isFile()) {
type = \"none\";
if(/(^userChrome|.uc).js$/i.test(file.leafName)) {
type = \"userchrome/js\";
}
else if(/(^userChrome|.uc).xul$/i.test(file.leafName)) {
type = \"userchrome/xul\";
}
else if(/.as.css$/i.test(file.leafName)) {
type = \"agentsheet\";
}
else if(/^(?!(userChrome|userContent).css$).+.css$/i.test(file.leafName)) {
type = \"usersheet\";
}
if(type != \"none\") {
console.log(\"----------\\ \" + file.leafName + \" (\" + type + \")\");
try {
if(type == \"userchrome/js\") {
Services.scriptloader.loadSubScriptWithOptions(fileURI.spec, {target: window, ignoreCache: true});
}
else if(type == \"userchrome/xul\") {
xulFiles.push(fileURI.spec);
}
else if(type == \"agentsheet\") {
if(!sss.sheetRegistered(fileURI, sss.AGENT_SHEET))
sss.loadAndRegisterSheet(fileURI, sss.AGENT_SHEET);
}
else if(type == \"usersheet\") {
if(!sss.sheetRegistered(fileURI, sss.USER_SHEET))
sss.loadAndRegisterSheet(fileURI, sss.USER_SHEET);
}
} catch(e) {
console.log(\"########## ERROR: \" + e + \" at \" + e.lineNumber + \":\" + e.columnNumber);
}
console.log(\"----------/ \" + file.leafName);
}
}
}
setTimeout(function loadXUL() {
if(xulFiles.length > 0) {
document.loadOverlay(xulFiles.shift(), null);
setTimeout(loadXUL, 5);
}
}, 0);
]]></constructor>
</implementation>
</binding>
</bindings>
@Netherspark
Copy link

How do I make the thumb button grow out slowly instead of just popping to full size?

The settings are there to control the speed it retracts, but I can't get it to work for the other way.

@neekt
Copy link

neekt commented Sep 7, 2019

I'm having the same issue as @seascape, using Linux; this breaks my Tools menu:

Screenshot from 2019-09-07 09-57-39

@LeLobster
Copy link

LeLobster commented Sep 10, 2019

@seascape @neekt

it's conflicting with this snippet from firefox's menu.js while rendering the menu

      e.originalTarget.setAttribute("hasbeenopened", "true");
      for (let el of e.originalTarget.querySelectorAll("menuitem, menu")) {
        el.render();
      }

Easy fix, because who cares about the toggleable checkbox in the menu
Comment out #87 in userChrome.js so the script no longer messes with the menu

#87 p.parentNode.insertBefore(m, p);

@seascape
Copy link

@LeLobster Thank you for the fix!

@echuber2
Copy link

echuber2 commented Sep 16, 2019

I think you [I mean, whoever maintains this script] need to remove this line to avoid confusion in the future:

@namespace url(http: //www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);

Note the mysterious space in http: // there. This is not allowed in a CSS raw URL token, according to the CSS spec: https://drafts.csswg.org/css-syntax-3/#consume-a-url-token In other words, this namespace URL is parsed as a bad URL and not even applied. I noticed that if I tried to correct the URL there, it broke things, whereas leaving the illegal space or simply removing the line entirely works.

I don't know where else to point this out, but this line appears in a lot of Firefox userscripts that have been floating around GitHub, pastebins, Reddit, etc.! Wish we could find who originated that and let them know.

@PavloVinnyk
Copy link

It does not work in Firefox beta 72. Any solutions?

@sfmict
Copy link

sfmict commented Jan 9, 2020

It does not work in Firefox beta 72. Any solutions?

For 72 in userContent.css

* {
	scrollbar-color: #444 #1f1f1f !important;
	scrollbar-width: thin !important;
}

@montagros
Copy link

I'm on FF 72.0.2 and script stoped work. I dont have userContent.css file. When I create it in chrome folder it's still doesn't work. Any solutions?

@insiderser
Copy link

@montagros
Copy link

@insiderser Thank You, but yes, I have this option turned to true.

@pmust
Copy link

pmust commented Mar 16, 2020

Is there a way to get this working as shown in the screenshots? If I don't have anything in the userContent.css file, then the original scrollbars are visible (uglyyy), but if I add the lines
:root{ scrollbar-width: thin; scrollbar-color: rgb(82, 82, 82) rgb(31, 31, 31); }
there, then I get this thin scrollbar. But I'd much prefer to have the scrollbar wider when hovering, just as it is shown in the screenshots. I am using FF 74.0

@seascape
Copy link

seascape commented Mar 16, 2020

@DemoniWaari
This is what I have in my userContent.css right now (FF74), and I am very pleased with how it looks/works. It's more functional than the previous hacks, as it's just the default bars with better colors. (When I was using this page's old only-visible-on-mouseover implementation I was having various troubles with it blocking mouseclicks inside add-on frames, at page edges, etc.)

/*                      */
/*   DARK SCROLLBARS    */
/*                      */
/* (updated for FF72)   */
/* (FF72: new, very simple method from Jan 9 comment here: https://gist.github.com/mrkwatz/277fb19d210a7539304ca2388f24d8e3 ) */
/* this also works for the scrollbar in Tab Center Reborn and other add-ons! */

* { scrollbar-color: #444 #1f1f1f !important; }

Scrolling to the top of this long page, I see the maintainer is recommending this method now too, along with an option to make it thinner. It's simple and works great.

@pmust
Copy link

pmust commented Mar 22, 2020 via email

Copy link

ghost commented Apr 19, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment