NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @namespace https://openuserjs.org/users/jsd
// @name Unfix Everything
// @description position:fixed is abused so much, we may as well abolish it by default.
// @author jsd
// @license MIT
// @version 0.4.2
// @grant none
// @include http*
// @exclude *twitch.tv*
// @exclude *aws.amazon.com*
// @exclude *docs.google.com*
// @exclude *online-go.com*
// ==/UserScript==
// This script attempts to detect and render un-fixed in position any menu bars and
// the like that stick to the top or bottom of web pages, because in almost all cases
// I'd rather not waste vertical space in the browser viewport.
// Use at your own risk, obviously. In some cases you may not see "we use cookies"
// warnings or other vitally important information.
(function() {
'use strict';
// Set allow_sidebars to 0 if you want side-bars and other tall things to be unfixed.
// There is less to gain and more potential problems with these elements, so it's 1 by default.
// Warning: Haven't tested this in a while...
var allow_sidebars = 1;
// Takes an element list, un-fixes it.
function z_unfix(els)
{
if (typeof els === "undefined")
{
return;
}
for(var i = 0; i < els.length; i++)
{
if (!els[i])
continue;
// Get position attribute from style
var style = null;
try {
style = window.getComputedStyle(els[i]);
} catch(err) {
style = null;
}
if (!style)
{
style = els[i].style;
if (typeof style === "undefined" || style === null)
continue;
}
// the default is static
var pos = style.getPropertyValue('position');
if (typeof pos === "undefined")
pos = "static";
// for Washington Post
if (els[i].nodeName === "amp-img" || els[i].tagName === "amp-img")
pos = "relative";
// for bugzilla.mozilla.org
// ... an annoying one. We need a more general fix for this style.
if (els[i].id === "wrapper" && els[i].children && els[i].children[0] && els[i].children[0].id==="header")
els[i].style.setProperty("overflow", "auto", "important");
if (els[i].id === "bugzilla-body")
{
els[i].style.setProperty("overflow-y", "visible", "important");
els[i].style.setProperty("overflow-x", "visible", "important");
continue;
}
// So we must deal with it.
if (els[i].style && ((pos === "fixed") || (pos === "sticky")))
{
var rect = els[i].getBoundingClientRect();
var cHeight = document.documentElement.clientHeight;
var cWidth = document.documentElement.clientHeight;
var bDontHide = 0;
var bUnsure = 0;
var scrollPos = window.scrollY || window.scrollTop || document.getElementsByTagName("body")[0].scrollTop;
// For quadrazid.com, and anyone else helpful enough to say "modal"
if (rect.height == 0)
{
if (els[i].className && (els[i].className.indexOf("modal") >= 0))
{
console.log("modal");
continue;
}
}
// for twitter
if (els[i].className && (els[i].className.indexOf("allery") >= 0 || els[i].className.indexOf("verlay") >=0))
{
continue;
}
// allow sidebars and other tall elements if that's turned on
if (rect.height > (cHeight * 0.7))
{
if (allow_sidebars)
{
console.log("pass");
continue;
}
}
// don't do elements that are vertically centred, as it tends to break things.
// ... mostly those stupid "Give us your email" forms that pop up.
else if (Math.abs((rect.top + (rect.height / 2)) - (cHeight / 2)) < 30 )
{
continue;
}
// stuff meant to stick to bottom of window is a problem, so let's not even
// display it, if it's not too tall. It's mostly "We use cookies" notices.
else if (Math.abs(rect.bottom - cHeight) < 3)
{
if (rect.height < 150 && rect.height > 0)
els[i].style.setProperty("display", "none");
}
// If it's near the bottom (or off the screen as at zomato.com)...
// Catches, for example, animated bottom bars that slide up.
else if (rect.top > cHeight - 30)
{
if (!bDontHide)
els[i].style.setProperty("display", "none");
}
// Added this for nytimes.com's latest promotional nonsense.
else if ((rect.top > cHeight - 150) && (rect.width > cWidth / 3) && !bDontHide)
{
els[i].style.setProperty("display", "none");
}
console.log('unfix ' + rect.top + ' ' + rect.height + ' ' + scrollPos + ' ' + els[i].id + ' ' + els[i].className);
// Not sure how to best choose between static, absolute, relative...
if (pos === "fixed")
{
pos = ((rect.height > 0) ? "absolute" : "static");
} else if (pos === "sticky")
pos = "relative";
if (bUnsure)
els[i].style.setProperty("position", pos);
else
els[i].style.setProperty("position", pos, "important");
}
}
}
// unfix stylesheets, needed for rules not applied until after page load
function unfix_sheet(sheet)
{
if (!sheet)
return;
var rules = sheet.cssRules;
if (!rules || !rules.length)
return;
for (var j = 0; j < rules.length; j++)
{
var rule = rules[j];
if (typeof rule === "undefined")
continue;
// console.log(rule.selectorText);
var st = rule.selectorText;
if (!st)
continue;
if (st.indexOf("ytd") > 0) // try not to break youtube too much
continue;
var flag = 0;
if (rule.type === CSSRule.IMPORT_RULE)
{
unfix_sheet(rule.getStyleSheet());
}
else //if (rule.type === CSSRule.STYLE_RULE)
{
// fix bad layout on imdark.com while we're in here
if (st.indexOf("myplayers") >= 0)
flag=1;
// catches one or two...
if (st.indexOf("sticky") >= 0)
flag = 1;
// catches quite a few ... hopefully not too many.
else if (st.indexOf("secondary") >= 0 || st.indexOf("snap") >= 0 || st.indexOf("header") >= 0)
{
var sv;
if (rule.style && (sv = rule.style.getPropertyValue("position")))
{
if (sv === "fixed" || sv === "sticky")
flag = 1;
}
if (rule.cssText && rule.cssText.indexOf("fixed") >= 0)
flag = 1;
}
if (flag)
{
//console.log("delete: " + st);
sheet.deleteRule(j);
j--;
}
}
// if (rule.style.getPropertyValue("position") === "fixed")
// ... too complicated.
}
}
// necessary for the more stubborn cases.
function recursive_unfix(x)
{
if (!x)
return;
z_unfix([x]);
if (x.children)
for (var l = 0; l < x.children.length; l++)
recursive_unfix(x.children[l]);
}
// watch for dynamic page changes
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var obs;
function re_observe()
{
obs.observe( document.getElementsByTagName("body")[0], { childList:true, subtree:true, attributes:true});
}
// on any browsers with no MutationObserver, we will succeed less often
if (MutationObserver)
{
obs = new MutationObserver(function(mutations, observer)
{
for (var j=0; j < mutations.length; j++)
{
if (mutations[j].type === "attributes" && mutations[j].target)
{
var style = window.getComputedStyle(mutations[j].target);
if (style)
{
var s = style.getPropertyValue("position");
if (s !== "fixed" && s !== "sticky")
continue;
}
z_unfix([mutations[j].target]);
}
else if (mutations[j].type === "childList" && mutations[j].addedNodes.length > 0)
{
for (var k = 0; k < mutations[j].addedNodes.length; k++)
{
//var el = mutations[j].addedNodes[k].parentElement; // excessive
var el = mutations[j].addedNodes[k];
// This seems effective.
if (!el)
el = mutations[j].addedNodes[k];
recursive_unfix(el);
}
}
}
re_observe();
});
obs.observe( document.getElementsByTagName("body")[0], { childList:true, subtree:true, attributes:true});
}
console.log("Unfix");
// unfix things on load
z_unfix(document.getElementsByTagName("*"));
// still-experimental stylesheet munging -- seems not to break too much, now.
var sheets = document.styleSheets;
if (sheets)
for (var j=0; j < sheets.length; j++)
{
try {
unfix_sheet(sheets[j]);
}catch (err){
console.log("css exception: " + err.message);
}
}
})();