YouTube Fullscreen Scroll Disabler

Disable scrolling when YouTube is in fullscreen mode and hide scrollbar. Also hide certain fullscreen UI elements.

Verzia zo dňa 14.10.2025. Pozri najnovšiu verziu.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         YouTube Fullscreen Scroll Disabler
// @namespace    https://youtube.com
// @version      1.0.2
// @description  Disable scrolling when YouTube is in fullscreen mode and hide scrollbar. Also hide certain fullscreen UI elements.
// @author       Lolen10
// @match        *://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?domain=youtube.com
// @grant        none
// @license      GNU GPLv3
// ==/UserScript==

(function() {
    'use strict';

    // Store references to hidden elements and their previous display values
    let hiddenElements = [];

    // Store previous overflow values so we can restore them
    let previousOverflow = { html: '', body: '' };
    let styleElementId = 'ytfs-scrollblocker-style';
    let listenersAdded = false;

    // Event listeners for fullscreen change
    document.addEventListener('fullscreenchange', toggleScrollAndContent, false);
    document.addEventListener('webkitfullscreenchange', toggleScrollAndContent, false); // Older WebKit
    document.addEventListener('mozfullscreenchange', toggleScrollAndContent, false);    // Firefox

    // Also handle when the user presses F (YouTube's fullscreen toggle) or when the player switches programmatically.
    // We'll run the toggle function once on script load to handle pages that already are fullscreen (rare).
    setTimeout(toggleScrollAndContent, 500);

    function toggleScrollAndContent() {
        if (isFullScreen()) {
            enterFullscreenMode();
        } else {
            exitFullscreenMode();
        }
    }

    function isFullScreen() {
        return !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement);
    }

    // ---------- Fullscreen enter/exit ----------

    function enterFullscreenMode() {
        // Disable scroll input
        disableScroll();

        // Hide content below the #single-column-container (existing behavior)
        removeContentBelowContainer();

        // Hide ytp fullscreen grid main content(s)
        hideBySelectorAll('.ytp-fullscreen-grid-main-content');

        // Hide expand button(s)
        hideBySelectorAll('.ytp-fullscreen-grid-expand-button.ytp-button');
    }

    function exitFullscreenMode() {
        // Re-enable scrolling
        enableScroll();

        // Restore previously hidden elements
        restoreHiddenElements();
    }

    // ---------- Hiding / restoring helpers ----------

    function hideBySelectorAll(selector) {
        const nodes = document.querySelectorAll(selector);
        nodes.forEach(node => {
            // Avoid hiding same node twice
            if (!hiddenElements.some(entry => entry.el === node)) {
                hiddenElements.push({ el: node, prevDisplay: node.style.display || '' });
                node.style.display = 'none';
            }
        });
    }

    // Remove all content below #single-column-container (keeps previous behavior but stores prev display)
    function removeContentBelowContainer() {
        const container = document.getElementById('single-column-container');
        if (container) {
            let nextSibling = container.nextElementSibling;
            while (nextSibling) {
                if (!hiddenElements.some(entry => entry.el === nextSibling)) {
                    hiddenElements.push({ el: nextSibling, prevDisplay: nextSibling.style.display || '' });
                    nextSibling.style.display = 'none';
                }
                nextSibling = nextSibling.nextElementSibling;
            }
        }
    }

    function restoreHiddenElements() {
        hiddenElements.forEach(entry => {
            try {
                entry.el.style.display = entry.prevDisplay;
            } catch (err) {
                // element might have been removed from DOM — ignore
            }
        });
        hiddenElements = [];
    }

    // ---------- Scroll blocking ----------

    function preventScroll(e) {
        // Only prevent if in fullscreen (defensive)
        if (!isFullScreen()) return;
        e.preventDefault();
        e.stopPropagation();
        return false;
    }

    function preventKeyScroll(e) {
        if (!isFullScreen()) return;
        // Keys that can scroll the page
        const blockedKeys = [
            'PageUp', 'PageDown', 'Home', 'End', ' '
        ];
        if (blockedKeys.includes(e.key)) {
            // Allow if user is focused in an input/textarea/contenteditable
            const target = e.target;
            const tag = target && target.tagName ? target.tagName.toLowerCase() : '';
            const isEditable = target && (target.isContentEditable || tag === 'input' || tag === 'textarea' || target.getAttribute('role') === 'textbox');
            if (!isEditable) {
                e.preventDefault();
                e.stopPropagation();
                return false;
            }
        }
    }

    function disableScroll() {
        if (listenersAdded) return; // don't add twice

        // Save previous overflow values
        previousOverflow.html = document.documentElement.style.overflow || '';
        previousOverflow.body = document.body.style.overflow || '';

        // Force hide overflow to block scrollbar-based scrolling as a robust fallback
        try {
            document.documentElement.style.overflow = 'hidden';
            document.body.style.overflow = 'hidden';
        } catch (err) {
            // ignore if not allowed
        }

        // Insert style to hide scrollbars (visual)
        if (!document.getElementById(styleElementId)) {
            const style = document.createElement('style');
            style.id = styleElementId;
            style.type = 'text/css';
            style.appendChild(document.createTextNode(
                'html, body { overscroll-behavior: none !important; height: 100% !important; } ' +
                '::-webkit-scrollbar { display: none !important; width: 0 !important; height: 0 !important; }'
            ));
            (document.head || document.documentElement).appendChild(style);
        }

        // Add wheel & touchmove listeners (passive: false to allow preventDefault)
        window.addEventListener('wheel', preventScroll, { passive: false, capture: true });
        window.addEventListener('touchmove', preventScroll, { passive: false, capture: true });

        // Keydown to block space/arrow/page keys
        window.addEventListener('keydown', preventKeyScroll, { passive: false, capture: true });

        listenersAdded = true;
    }

    function enableScroll() {
        if (!listenersAdded) {
            // still attempt to clean up style/overflow even if listeners weren't marked as added
            cleanupOverflowAndStyle();
            return;
        }

        window.removeEventListener('wheel', preventScroll, { capture: true });
        window.removeEventListener('touchmove', preventScroll, { capture: true });
        window.removeEventListener('keydown', preventKeyScroll, { capture: true });

        cleanupOverflowAndStyle();

        listenersAdded = false;
    }

    function cleanupOverflowAndStyle() {
        // Restore previous overflow values
        try {
            document.documentElement.style.overflow = previousOverflow.html || '';
            document.body.style.overflow = previousOverflow.body || '';
        } catch (err) {
            // ignore
        }

        // Remove style element that hid scrollbars
        const style = document.getElementById(styleElementId);
        if (style && style.parentNode) {
            style.parentNode.removeChild(style);
        }
    }

    // Keep things tidy if the user navigates or the page rebuilds heavy parts of the DOM:
    // If the fullscreen element is removed unexpectedly, make sure we restore.
    const observer = new MutationObserver(() => {
        if (!isFullScreen() && (hiddenElements.length > 0 || listenersAdded)) {
            // Force restore if DOM changed and we are no longer fullscreen
            exitFullscreenMode();
        }
    });

    observer.observe(document.documentElement, { childList: true, subtree: true });

    // Clean up on unload
    window.addEventListener('beforeunload', () => {
        try { observer.disconnect(); } catch (e) {}
        enableScroll();
    });

})();