TikTok Scroll & Layout Fix

Разблокирует скролл ленты и чинит съехавшую верстку модальных окон (подписчики/подписки) в TikTok.

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

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

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         TikTok Scroll & Layout Fix
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Разблокирует скролл ленты и чинит съехавшую верстку модальных окон (подписчики/подписки) в TikTok.
// @author       torch
// @match        *://*.tiktok.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tiktok.com
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 1. Добавляем CSS-правила с !important, которые не дадут TikTok сломать скролл и сдвинуть верстку
    const style = document.createElement('style');
    style.innerHTML = `
        /* Возвращаем скроллбар и убираем сдвиг страницы (padding-right) */
        html, body {
            overflow-y: auto !important;
            overflow-x: hidden !important;
            padding-right: 0 !important;
            margin-right: 0 !important;
        }

        /* Убираем атрибут блокировки напрямую через CSS для надежности */
        body[data-scroll-locked] {
            overflow: auto !important;
        }

        /* Чиним окно подписчиков, чтобы оно не улетало за пределы экрана и внутри него работал скролл */
        [data-e2e="follow-info-popup"] {
            max-height: 80vh !important;
            display: flex !important;
            flex-direction: column !important;
        }
        
        [data-e2e="follow-info-popup"] div[class*="DivUserListContainer"] {
            overflow-y: auto !important;
            overscroll-behavior: contain;
            flex: 1 1 auto !important;
        }

        /* Запрещаем сдвиг для самого контейнера модального окна */
        div[class*="ModalContainer"], div[class*="ModalContentContainer"] {
            padding-right: 0 !important;
        }
    `;
    document.head.appendChild(style);

    // 2. Используем MutationObserver для перехвата скриптов TikTok, 
    // которые пытаются повесить блокировку в реальном времени.
    const observer = new MutationObserver((mutations) => {
        let shouldFix = false;
        mutations.forEach((mutation) => {
            if (mutation.type === 'attributes') {
                shouldFix = true;
            }
        });

        if (shouldFix) {
            const body = document.body;
            // Принудительно удаляем атрибут, блокирующий скролл
            if (body.hasAttribute('data-scroll-locked')) {
                body.removeAttribute('data-scroll-locked');
            }
            // Подчищаем инлайн-стили, сдвигающие контент
            if (body.style.overflow === 'hidden') {
                body.style.overflow = '';
            }
            if (body.style.paddingRight) {
                body.style.paddingRight = '';
            }
        }
    });

    // Запускаем наблюдение за тегом <body>
    observer.observe(document.body, {
        attributes: true,
        attributeFilter: ['data-scroll-locked', 'style', 'class']
    });

    // 3. Выполняем первичную очистку на случай, если страница уже загрузилась сломанной
    if (document.body.hasAttribute('data-scroll-locked')) {
        document.body.removeAttribute('data-scroll-locked');
    }
    document.body.style.overflow = '';
    document.body.style.paddingRight = '';

})();