AniList: add a back-to-top button

Adds a back-to-top button to AniList.

// ==UserScript==
// @name         AniList: add a back-to-top button
// @namespace    plennhar-anilist-add-a-back-to-top-button
// @version      1.0
// @description  Adds a back-to-top button to AniList.
// @author       Plennhar
// @match        https://anilist.co/*
// @run-at       document-idle
// @grant        none
// @noframes
// @license      GPL-3.0-or-later
// ==/UserScript==
// SPDX-FileCopyrightText: 2025 Plennhar
// SPDX-License-Identifier: GPL-3.0-or-later

(function () {
	'use strict';
	if (window.__alBackToTopInjected) return;
	window.__alBackToTopInjected = true;

	const css = `
    :root {
      --al-btt-left: 16px;
      --al-btt-bottom: 16px;
    }
    #al-back-to-top {
      position: fixed;
      left: var(--al-btt-left);
      bottom: var(--al-btt-bottom);
      z-index: 2147483647;
      width: 44px;
      height: 44px;
      border-radius: 999px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      user-select: none;
      border: 1px solid rgba(0,0,0,.18);
      background: rgba(255,255,255,.92);
      color: #222;
      box-shadow: 0 6px 18px rgba(0,0,0,.16);
      opacity: 0;
      transform: translateY(8px);
      transition: opacity 160ms ease, transform 160ms ease, background 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
      pointer-events: none;
    }
    #al-back-to-top.visible {
      opacity: 1;
      transform: translateY(0);
      pointer-events: auto;
    }
    #al-back-to-top:hover {
      background: #fff;
      border-color: rgba(0,0,0,.22);
      box-shadow: 0 8px 22px rgba(0,0,0,.22);
    }
    #al-back-to-top:active {
      transform: translateY(1px);
    }
    #al-back-to-top svg {
      width: 20px;
      height: 20px;
      display: block;
    }
    @media (prefers-color-scheme: dark) {
      #al-back-to-top {
        background: rgba(25,25,28,.84);
        color: #fff;
        border-color: rgba(255,255,255,.16);
        box-shadow: 0 6px 18px rgba(0,0,0,.35);
      }
      #al-back-to-top:hover {
        background: rgba(25,25,28,.96);
        border-color: rgba(255,255,255,.22);
        box-shadow: 0 8px 22px rgba(0,0,0,.5);
      }
    }
  `;
	const style = document.createElement('style');
	style.textContent = css;
	document.head.appendChild(style);

	const btn = document.createElement('button');
	btn.id = 'al-back-to-top';
	btn.type = 'button';
	btn.setAttribute('aria-label', 'Back to top');
	btn.title = 'Back to top';
	btn.innerHTML = `
    <svg viewBox="0 0 24 24" aria-hidden="true">
      <path d="M12 5.5a1 1 0 0 1 .7.29l6.5 6.5a1 1 0 1 1-1.4 1.42L13 9.31V19a1 1 0 1 1-2 0V9.3l-4.8 4.9a1 1 0 1 1-1.4-1.42l6.5-6.5A1 1 0 0 1 12 5.5z"/>
    </svg>
  `;
	document.body.appendChild(btn);

	const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
	const scrollToTop = () => {
		const behavior = prefersReduced ? 'auto' : 'smooth';
		window.scrollTo({ top: 0, left: 0, behavior });
	};
	btn.addEventListener('click', scrollToTop);
	btn.addEventListener('keydown', (e) => {
		if (e.key === 'Enter' || e.key === ' ') {
			e.preventDefault();
			scrollToTop();
		}
	});

	const THRESHOLD = 400;
	const toggle = () => {
		const y = window.scrollY || document.documentElement.scrollTop || 0;
		if (y > THRESHOLD) btn.classList.add('visible');
		else btn.classList.remove('visible');
	};

	window.addEventListener('scroll', toggle, { passive: true });
	window.addEventListener('resize', toggle, { passive: true });
	const mo = new MutationObserver(() => toggle());
	mo.observe(document.body, { childList: true, subtree: true });

	requestAnimationFrame(toggle);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址