Scroll to Top Button

Scroll to Top button that appears after scrolling down 20%

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Scroll to Top Button
// @namespace    U2Nyb2xsIHRvIFRvcCBCdXR0b24
// @version      2.4
// @description  Scroll to Top button that appears after scrolling down 20%
// @author       smed79
// @license      MIT
// @icon         https://i25.servimg.com/u/f25/11/94/21/24/scroll10.png
// @match        *://*/*
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function() {
  'use strict';

  // --- Create the host container ---
  const host = document.createElement('div');
  host.id = 'r2t-simple-btn';
  
  // Attach shadow DOM to perfectly isolate CSS from the website
  const shadow = host.attachShadow({ mode: 'closed' });

  // Add the CSS and HTML
  // Key fixes: added `contain`, `will-change`, and switched to `translate3d` for GPU isolation
  shadow.innerHTML = `
    <style>
      :host {
          all: initial;
          position: fixed;
          bottom: 25px;
          right: 25px;
          z-index: 2147483647;
          pointer-events: none;
          contain: layout paint style; /* Tells the browser this element won't affect page layout */
      }
      .circle {
          box-sizing: border-box;
          margin: 0;
          padding: 0;
          width: 40px;
          height: 40px;
          border-radius: 50%;
          background: rgba(0, 0, 0, 0.55);
          box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
          cursor: pointer;
          pointer-events: auto;
          display: flex;
          align-items: center;
          justify-content: center;
          opacity: 0;
          visibility: hidden;
          
          /* Force GPU layer and hardware acceleration */
          transform: translate3d(0, 15px, 0); 
          will-change: transform, opacity, visibility;
          backface-visibility: hidden; 
          
          transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s ease, background-color 0.2s ease;
          -webkit-tap-highlight-color: transparent;
      }
      .circle.show {
          opacity: 1;
          visibility: visible;
          transform: translate3d(0, 0, 0);
      }
      .circle:hover {
          background: rgba(0, 0, 0, 0.85);
      }
      .glyph {
          box-sizing: border-box;
          display: block;
          width: 12px;
          height: 12px;
          border-top: 4px solid #fff;
          border-left: 4px solid #fff;
          border-radius: 2px;
          transform: rotate(45deg) translate(2px, 2px);
          pointer-events: none;
      }
    </style>
    <div class="circle">
      <div class="glyph"></div>
    </div>
  `;

  const circle = shadow.querySelector('.circle');
  (document.documentElement || document.body).appendChild(host);

  // --- Scroll Logic (Throttled with requestAnimationFrame) ---
  let isTicking = false;

  window.addEventListener('scroll', () => {
      if (!isTicking) {
          window.requestAnimationFrame(() => {
              const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
              if (scrollHeight > 0) {
                  const scrollPercent = window.scrollY / scrollHeight;
                  if (scrollPercent > 0.20) {
                      circle.classList.add('show');
                  } else {
                      circle.classList.remove('show');
                  }
              }
              isTicking = false;
          });
          isTicking = true;
      }
  }, { passive: true });

  // --- Click Logic ---
  circle.addEventListener('click', () => {
      try { 
          window.scrollTo({ top: 0, behavior: 'smooth' }); 
      } catch (err) { 
          window.scrollTo(0, 0); 
      }
  });

})();