Как я отвоевал свой интерфейс у YouTube: битва за сетку видео на чистом CSS

Инструкции , Веб-разработка

Современный веб всё чаще решает за пользователя, как должен выглядеть интерфейс. Алгоритмы и скрипты динамически пересчитывают макеты, подгоняя их под усредненные метрики. Но когда инструменты становятся частью твоей повседневной жизни, хочется полного контроля. Моя битва с YouTube началась с двух, казалось бы, простых желаний: я хотел видеть ровно 5 видео в ряду на главной странице и удобную сетку 3x3 в рекомендациях после окончания ролика. Спойлер: скрипты Google сопротивлялись до последнего. Для внедрения своих CSS-правил я использую отличное расширение Enhancer for YouTube — в его настройках есть удобный блок «Пользовательская тема», куда можно внедрить любой код.

Акт первый: Синдром «уползающей» сетки

Настроить 5 колонок на главной странице с помощью пользовательского CSS несложно — достаточно задать контейнеру grid-template-columns: repeat(5, 1fr). Но при прокрутке страницы вниз начиналась магия: сетка плавно превращалась в 4,5 видео, а затем в 4. Правый край просто обрезался. Проблема крылась в скрытом конфликте: JS-движок YouTube (Polymer) динамически вешал на карточки роликов жесткий min-width. Когда грид пытался сжать элементы, чтобы уместить пятерку, min-width упирался. Решение: Пришлось не только жестко сбросить min-width: 0 !important для самих карточек, но и «хакнуть» CSS-переменные самого YouTube (--ytd-rich-grid-items-per-row: 5), чтобы JS-логика смирилась с новой реальностью. Для верности строки были развернуты через display: contents, объединяя всё в единый монолитный грид.

Акт второй: Анархия конечных заставок

Вторая проблема ждала в конце видео. По умолчанию YouTube предлагает скудную полоску из 3 рекомендованных видео (или накладывает авторские элементы). Мне нужна была полноценная видеостена 3x3. Здесь YouTube использует тяжелую артиллерию: скрипты высчитывают absolute координаты (top, left) для каждой плитки в зависимости от размера плеера. Лишние плитки просто скрываются. Решение:

К черту абсолютное позиционирование! Контейнер .videowall-endscreen был переведен во Flexbox. У каждой плитки я принудительно отключил координаты (top: auto !important, left: auto !important) и задал им ширину в 32% и высоту в 28%. Движок продолжал пытаться расставлять элементы по координатам, но Flexbox игнорировал их, аккуратно складывая плитки в идеальную матрицу из 9 элементов.

Акт третий: Бой с тенью (и темным экраном)

Сетка 3x3 технически заработала, но YouTube нанес ответный удар.

Во-первых, по окончании просмотра видео вместо ожидаемой сетки вылезал Pause Overlay — узкая раздражающая полоска всего с тремя роликами по центру экрана. Меня это очень сильно напрягало, так как я привык к классической и информативной сетке 3х3. Пришлось выжечь классы этой полоски через display: none !important, чтобы она не перекрывала мою видеостену.

Во-вторых, авторские элементы (End Cards) ложились поверх моей сетки, превращая экран в кашу. Их тоже пришлось скрыть.

И наконец, финальный босс: пытаясь сделать сетку более читаемой, я задал ей темный фон background: rgba(0, 0, 0, 0.8). Но контейнер оказался «липким». При переключении на следующее видео этот полупрозрачный слой не всегда исчезал, накладывая на ролик эффект тонированного стекла. Пришлось отказаться от фона в пользу transparent и добавить text-shadow для текста, чтобы он читался на любом фоне.

Итог

Мы привыкли мириться с тем, что нам предлагают корпорации. Но пара строк правильного кода способна вернуть автономию и сделать цифровое пространство по-настоящему удобным. Ниже приведен полный CSS-код моей победы, который необходимо вставить в блок кастомных стилей расширения Enhancer for YouTube.

Полный код решения:

/* ==========================================================================
   ЧАСТЬ 1: ГЛАВНАЯ СТРАНИЦА (Стабильная сетка из 5 видео)
   ========================================================================== */
ytd-rich-grid-renderer {
  --ytd-rich-grid-items-per-row: 5 !important;
  --ytd-rich-grid-posts-per-row: 5 !important;
  --ytd-rich-grid-min-item-width: 0px !important;
}

ytd-rich-grid-row,
ytd-rich-grid-row > #contents {
  display: contents !important;
}

ytd-rich-grid-renderer > #contents {
  display: grid !important;
  grid-template-columns: repeat(5, 1fr) !important;
  gap: 16px !important;
  width: 94% !important;
  margin: 0 auto !important;
  max-width: none !important;
}

/* Сброс min-width предотвращает "сползание" при скролле */
ytd-rich-item-renderer {
  width: 100% !important;
  margin: 0 !important;
  min-width: 0 !important; 
  max-width: none !important;
}

/* Скрываем мусор на главной (Shorts, баннеры, рекламу) */
ytd-rich-section-renderer,
ytd-statement-banner-renderer,
ytd-primetime-promo-renderer,
ytd-rich-shelf-renderer,
#masthead-ad {
  display: none !important;
}

#contents.ytd-rich-grid-renderer {
  padding-top: 10px !important;
}

/* Спиннер загрузки на всю ширину, чтобы не ломал грид */
ytd-continuation-item-renderer {
  grid-column: 1 / -1 !important;
}

/* ==========================================================================
   ЧАСТЬ 2: КОНЕЦ ВИДЕО (Сетка рекомендаций 3x3)
   ========================================================================== */

/* Контейнер видеостены переводим во Flexbox */
.html5-endscreen.videowall-endscreen {
  display: flex !important;
  flex-wrap: wrap !important;
  justify-content: center !important;
  align-content: center !important;
  padding: 2% !important;
  
  opacity: 1 !important;
  visibility: visible !important;
  z-index: 100 !important;
  background: transparent !important; 
  pointer-events: auto !important;
}

/* Отменяем абсолютное позиционирование JS и задаем размеры плиткам */
.html5-endscreen .ytp-videowall-still {
  display: block !important;
  visibility: visible !important;
  opacity: 1 !important;
  
  position: relative !important;
  top: auto !important;
  left: auto !important;
  transform: none !important;
  
  width: 32% !important; 
  height: 28% !important; 
  margin: 0.5% !important;
}

/* Подгонка картинок */
.html5-endscreen .ytp-videowall-still-image {
  border-radius: 4px !important;
  background-size: cover !important;
  opacity: 1 !important;
  display: block !important;
}

/* Скрываем аватарки авторов для экономии места */
.ytp-videowall-still-info-author {
  display: none !important;
}

/* Форматирование заголовков с тенью для читаемости */
.ytp-videowall-still-info-title {
  font-size: 110% !important;
  line-height: 1.2 !important;
  max-height: 2.4em !important;
  overflow: hidden !important;
  white-space: normal !important;
  text-shadow: 1px 1px 2px black !important;
}

/* ==========================================================================
   ЧАСТЬ 3: ОЧИСТКА ИНТЕРФЕЙСА (Удаление лишних оверлеев)
   ========================================================================== */

/* Убираем узкую полоску "Больше видео" по окончании ролика */
.ytp-pause-overlay,
.ytp-pause-overlay-container {
  display: none !important;
}

/* Скрываем элементы, добавленные авторами (перекрывают сетку) */
.ytp-ce-element,
.ytp-ce-covering-overlay {
  display: none !important;
}

/* Скрываем окно автовоспроизведения "Следующее видео" */
.ytp-upnext {
  display: none !important;
}

/* Скрываем кнопки навигации в эндскрине */
.ytp-endscreen-previous, 
.ytp-endscreen-next {
  display: none !important; 
}