YouTube Fullscreen Fix — Disable “More Videos” Grid + Preserve Controls

Hide fullscreen “More Videos” grid & vignette; keep scroll-wheel volume. Prevent tick-4/7 jiggle without forcing visibility. V-key manual hide. Hide interactive overlay in fullscreen. Allow normal autohide in FS and windowed modes.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

ستحتاج إلى تثبيت إضافة مثل Stylus لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتتمكن من تثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

(لدي بالفعل مثبت أنماط للمستخدم، دعني أقم بتثبيته!)

// ==UserScript==
// @name         YouTube Fullscreen Fix — Disable “More Videos” Grid + Preserve Controls
// @namespace    orangekite
// @version      1.3.6
// @description  Hide fullscreen “More Videos” grid & vignette; keep scroll-wheel volume. Prevent tick-4/7 jiggle without forcing visibility. V-key manual hide. Hide interactive overlay in fullscreen. Allow normal autohide in FS and windowed modes.
// @match        https://www.youtube.com/*
// @run-at       document-start
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  GM_addStyle(`
/* Fullscreen-scoped: match when either the player OR an ancestor is fullscreen */
.html5-video-player:fullscreen,
:fullscreen .html5-video-player {
  --ytp-grid-scroll-percentage: 0 !important;
  --ytp-grid-peek-height: 0px !important;
  --ytp-grid-peek-gradient: 0 !important;
  --ytp-controls-peek-height: 0px !important;
  --ytp-controls-peek-percent: 0 !important;
}

/* Hide the fullscreen recommendations grid and its moving parts */
.html5-video-player:fullscreen [class*="fullscreen-grid"],
.html5-video-player:fullscreen [class*="fullerscreen-grid"],
.html5-video-player:fullscreen [class*="grid-stills"],
.html5-video-player:fullscreen [class*="videowall-still"],
:fullscreen .html5-video-player [class*="fullscreen-grid"],
:fullscreen .html5-video-player [class*="fullerscreen-grid"],
:fullscreen .html5-video-player [class*="grid-stills"],
:fullscreen .html5-video-player [class*="videowall-still"] {
  display: none !important;
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
  height: 0 !important;
  max-height: 0 !important;
  overflow: hidden !important;
}

/* Hide the vignette/scrim/gradient behind the grid */
.html5-video-player:fullscreen [class*="grid-vignette"],
.html5-video-player:fullscreen [class*="grid-scrim"],
.html5-video-player:fullscreen [class*="gradient-bottom"],
:fullscreen .html5-video-player [class*="grid-vignette"],
:fullscreen .html5-video-player [class*="grid-scrim"],
:fullscreen .html5-video-player [class*="gradient-bottom"] {
  display: none !important;
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

/* Hide “fullerscreen” education/teaser overlays */
.html5-video-player:fullscreen [class*="fullerscreen"],
.html5-video-player:fullscreen .ytp-fullerscreen-edu-panel,
.html5-video-player:fullscreen .ytp-cards-teaser,
.html5-video-player:fullscreen .ytp-cards-teaser-box,
:fullscreen .html5-video-player [class*="fullerscreen"],
:fullscreen .html5-video-player .ytp-fullerscreen-edu-panel,
:fullscreen .html5-video-player .ytp-cards-teaser,
:fullscreen .html5-video-player .ytp-cards-teaser-box {
  display: none !important;
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

/* Safety net for lingering vignette/scrim overlays */
.html5-video-player:fullscreen [class*="vignette"],
.html5-video-player:fullscreen [class*="scrim"],
:fullscreen .html5-video-player [class*="vignette"],
:fullscreen .html5-video-player [class*="scrim"] {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

/* --- IMPORTANT: Don't force visibility; just remove jiggle when bar is VISIBLE --- */

/* Neutralize any “peek” transforms but ONLY when not autohidden */
:is(.html5-video-player:fullscreen, :fullscreen .html5-video-player):not(.ytp-autohide):not(.ytp-hide-controls)
  [class*="peek"] {
  transform: none !important;
  translate: 0 !important;
}

/* Stop tick-4 jiggle: anchor the chrome only when not autohidden */
:is(.html5-video-player:fullscreen, :fullscreen .html5-video-player):not(.ytp-autohide):not(.ytp-hide-controls)
  .ytp-chrome-bottom {
  bottom: 0 !important;
  transform: translateY(0) !important;
  translate: 0 !important;
  margin-bottom: 0 !important;
  transition: none !important;
}

/* If YouTube injects inline translateY on the chrome, zero it (when not autohidden) */
:is(.html5-video-player:fullscreen, :fullscreen .html5-video-player):not(.ytp-autohide):not(.ytp-hide-controls)
  .ytp-chrome-bottom[style*="translate"] {
  transform: translateY(0) !important;
}

/* Permanently remove interactive overlay in fullscreen */
.html5-video-player:fullscreen :is(.ytp-overlay-bottom-right, .branding-img-container.ytp-button),
:fullscreen .html5-video-player :is(.ytp-overlay-bottom-right, .branding-img-container.ytp-button) {
  display: none !important;
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}
  `);

  // ---------------- Core JS helper: keep things smooth; V-key manual hide
  let manualHideActive = false;

  // NOTE: Do NOT force opacity/visibility in FS. Let YT autohide work.
  const restoreChrome = () => {
    const player = document.querySelector('.html5-video-player.ytp-fullscreen');
    if (!player) return;
    const chrome = player.querySelector('.ytp-chrome-bottom');
    if (!chrome) return;

    if (manualHideActive) return;

    // If YT temporarily sets display:none during transitions, restore native display.
    if (!chrome.dataset.nativeDisplay) {
      chrome.dataset.nativeDisplay = getComputedStyle(chrome).display || 'flex';
    }
    const disp = getComputedStyle(chrome).display;
    if (disp === 'none' || chrome.style.display === 'none') {
      chrome.style.display = chrome.dataset.nativeDisplay;
    }

    // IMPORTANT: Do not set opacity/visibility/transform here.
    // We only rely on CSS anchoring when not autohidden.
    chrome.style.removeProperty('opacity');
    chrome.style.removeProperty('visibility');
    chrome.style.removeProperty('transform');
  };

  // Keep controls stable during wheel "peek" while in FS
  window.addEventListener('wheel', restoreChrome, { passive: true });

  // Scrub inline styles on FS boundaries so normal autohide works in both modes
  document.addEventListener('fullscreenchange', () => {
    const fsPlayer  = document.querySelector('.html5-video-player.ytp-fullscreen');
    const fsChrome  = fsPlayer?.querySelector('.ytp-chrome-bottom');
    manualHideActive = false;

    if (document.fullscreenElement) {
      // Entering FS: remove stale inline overrides and ensure native display
      if (fsChrome) {
        if (!fsChrome.dataset.nativeDisplay) {
          fsChrome.dataset.nativeDisplay = getComputedStyle(fsChrome).display || 'flex';
        }
        fsChrome.style.removeProperty('opacity');
        fsChrome.style.removeProperty('visibility');
        fsChrome.style.removeProperty('transform');
        fsChrome.style.removeProperty('bottom');
        fsChrome.style.removeProperty('margin-bottom');
        if (getComputedStyle(fsChrome).display === 'none') {
          fsChrome.style.display = fsChrome.dataset.nativeDisplay;
        }
      }
    } else {
      // Exiting FS: clean all players so windowed autohide resumes
      document.querySelectorAll('.html5-video-player .ytp-chrome-bottom').forEach(chrome => {
        chrome.style.removeProperty('opacity');
        chrome.style.removeProperty('visibility');
        chrome.style.removeProperty('transform');
        chrome.style.removeProperty('display');
        chrome.style.removeProperty('bottom');
        chrome.style.removeProperty('margin-bottom');
      });
    }
  }, { passive: true });

  // V-key: manual hide/show for the control bar (fullscreen only)
  (() => {
    const playerSelector = '.html5-video-player.ytp-fullscreen';
    const chromeSelector = '.ytp-chrome-bottom';

    function applyManualHideStyles(chrome, hide) {
      if (hide) {
        chrome.style.setProperty('opacity', '0', 'important');
        chrome.style.setProperty('visibility', 'hidden', 'important');
        chrome.style.removeProperty('transform');
      } else {
        chrome.style.removeProperty('opacity');
        chrome.style.removeProperty('visibility');
        restoreChrome();
      }
    }

    window.addEventListener('keydown', e => {
      if (e.key.toLowerCase() !== 'v') return;
      const player = document.querySelector(playerSelector);
      if (!player) return;
      const chrome = player.querySelector(chromeSelector);
      if (!chrome) return;

      manualHideActive = !manualHideActive;
      applyManualHideStyles(chrome, manualHideActive);
    }, true);

    // Keep behavior consistent if other events fire while hidden
    const syncIfNeeded = () => {
      if (!manualHideActive) return;
      const player = document.querySelector(playerSelector);
      const chrome = player?.querySelector(chromeSelector);
      if (chrome) applyManualHideStyles(chrome, true);
    };
    window.addEventListener('wheel', syncIfNeeded, { passive: true });
    window.addEventListener('keyup', syncIfNeeded, { passive: true });
  })();

})();