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); } } })();