اسکرول نرم سایت و دکمه بازگشت به بالای صفحه

اسکرول نرم سایت و دکمه بازگشت به بالای صفحه

اسکرول نرم سایت و دکمه بازگشت به بالای صفحه

اسکرول نرم (Smooth Scroll) یکی از قابلیت‌های کاربردی در طراحی سایت است که با ایجاد حرکت روان و طبیعی هنگام پیمایش صفحات، تجربه کاربری بهتری برای بازدیدکنندگان فراهم می‌کند. در کنار آن، دکمه بازگشت به بالای صفحه (Back to Top) امکان دسترسی سریع به ابتدای سایت را تنها با یک کلیک فراهم می‌سازد. وجود نوار پیشرفت دایره‌ای در اطراف این دکمه نیز میزان پیمایش صفحه را به‌صورت بصری نمایش می‌دهد.

این قابلیت با بهبود نحوه تعامل کاربران با صفحات سایت، دسترسی به بخش‌های مختلف را آسان‌تر کرده و به ایجاد یک تجربه کاربری حرفه‌ای‌تر در طراحی سایت کمک می‌کند.

نحوه وارد کردن

برای فعال سازی افزونه کد اسنیپت رو دانلود و نصب کنین و قسمت افزودن کد یک عنوان گذاشته و کد رو پست کنین داخلش و گزینه ذخیره و فعال سازیی بزنین و تمام.

/* =========================================================
PALIWEB - LENIS SMOOTH SCROLL + SCROLL TO TOP
========================================================= */

add_action('wp_footer', function () {

    // داخل ادمین و ادیتور المنتور اجرا نشود
    $el = class_exists('\Elementor\Plugin') ? \Elementor\Plugin::$instance : null;

    if (is_admin() || ($el && isset($el->preview) && $el->preview->is_preview_mode())) {
        return;
    }

    ?>

<style>
/* Lenis (ضروری) */
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto!important}
.lenis.lenis-smooth [data-lenis-prevent]{overscroll-behavior:contain}
.lenis.lenis-stopped{overflow:hidden}
.lenis.lenis-scrolling iframe{pointer-events:none}

/* اسکرول بار صفحه (نارنجی) - دسکتاپ */
html,body{scrollbar-width:thin;scrollbar-color:#f97316 transparent}
@supports not (scrollbar-color:auto){
    html::-webkit-scrollbar,body::-webkit-scrollbar{width:8px;height:8px}
    html::-webkit-scrollbar-track,body::-webkit-scrollbar-track{background:transparent}
    html::-webkit-scrollbar-thumb,body::-webkit-scrollbar-thumb{background:#f97316;border-radius:8px}
    html::-webkit-scrollbar-thumb:hover,body::-webkit-scrollbar-thumb:hover{background:#ea580c}
}

/* اسکرول بار نارنجی اندروید (با JS ساخته می‌شود) */
html.pw-sb,html.pw-sb body{scrollbar-width:none}
html.pw-sb::-webkit-scrollbar,html.pw-sb body::-webkit-scrollbar{display:none;width:0;height:0}
#paliweb-scrollbar{
    position:fixed;
    top:0;
    inset-inline-end:2px;
    z-index:999998;
    width:3px;
    border-radius:3px;
    background:#f97316;
    opacity:0;
    pointer-events:none;
    will-change:transform,opacity;
    transition:opacity .3s ease;
}
#paliweb-scrollbar.pw-on{opacity:1}

/* دکمه */
#paliweb-scroll-top{
    --pw-orange:#f97316;
    --pw-track:inset 0 0 0 3px rgba(40,42,46,.10);
    position:fixed;
    left:24px;
    bottom:24px;
    z-index:999999;
    display:grid;
    place-items:center;
    width:52px;
    height:52px;
    padding:0;
    border:0;
    border-radius:50%;
    background:#f6f4ef;
    color:#33363b;
    box-shadow:var(--pw-track),0 6px 18px rgba(0,0,0,.18);
    cursor:pointer;
    -webkit-tap-highlight-color:transparent;
    opacity:0;
    visibility:hidden;
    pointer-events:none;
    transform:translateY(12px) scale(.9);
    transition:opacity .22s ease,visibility .22s ease,transform .3s cubic-bezier(.2,.8,.2,1),box-shadow .25s ease;
}
#paliweb-scroll-top.paliweb-visible{
    opacity:1;
    visibility:visible;
    pointer-events:auto;
    transform:none;
    will-change:transform;
}
#paliweb-scroll-top.paliweb-visible:hover{
    transform:translateY(-3px) scale(1.05);
    box-shadow:var(--pw-track),0 10px 24px rgba(0,0,0,.24);
}
#paliweb-scroll-top.paliweb-visible:active{transform:scale(.94)}
#paliweb-scroll-top:focus-visible{outline:2px solid var(--pw-orange);outline-offset:3px}

/* حلقه‌ی پیشرفت اسکرول */
#paliweb-scroll-top .pw-ring{
    position:absolute;
    inset:0;
    width:100%;
    height:100%;
    overflow:visible;
    transform:rotate(-90deg);
}
#paliweb-scroll-top .pw-ring-bar{
    fill:none;
    stroke:var(--pw-orange);
    stroke-width:3;
    stroke-linecap:round;
}

/* فلش */
#paliweb-scroll-top .pw-arrow{
    position:relative;
    display:block;
    width:20px;
    height:20px;
    transition:transform .25s ease;
}
#paliweb-scroll-top:hover .pw-arrow{transform:translateY(-2px)}

/* ریسپانسیو */
@media (max-width:767px){
    #paliweb-scroll-top{left:16px;bottom:16px;width:46px;height:46px}
    #paliweb-scroll-top .pw-arrow{width:18px;height:18px}
}
@media (min-width:768px) and (max-width:1024px){
    #paliweb-scroll-top{left:20px;bottom:20px}
}
@media (prefers-reduced-motion:reduce){
    #paliweb-scroll-top,#paliweb-scroll-top .pw-arrow{transition:none}
}
</style>

<button id="paliweb-scroll-top" type="button" aria-label="بازگشت به بالای صفحه" title="بازگشت به بالا">
    <svg class="pw-ring" viewBox="0 0 52 52" aria-hidden="true"><circle class="pw-ring-bar" cx="26" cy="26" r="24.5"/></svg>
    <svg class="pw-arrow" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M6 14L12 8L18 14" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>

<script>
(() => {
    'use strict';

    const button = document.getElementById('paliweb-scroll-top');

    if (!button) return;

    const is = (query) => window.matchMedia(query).matches;

    /* ---------- دکمه + نوار پیشرفت ---------- */

    const SHOW_AFTER = 100; // پیکسل؛ کمتر = ظاهر شدن زودتر

    const bar = button.querySelector('.pw-ring-bar');
    const length = 2 * Math.PI * parseFloat(bar.getAttribute('r'));

    let maxScroll = 1;
    let progress = -1;
    let visible = false;
    let barOn = true;
    let queued = false;
    let viewH = window.innerHeight;
    let thumbH = 40;
    let thumbOn = false;
    let hideTimer;

    // اسکرول بار نارنجی برای اندروید (روی آیفون/آیپد ساخته نمی‌شود)
    // (سیستم‌عامل اجازه‌ی تغییر رنگ اسکرول بار اصلی را نمی‌دهد)
    const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
        (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);

    let thumb = null;

    if (!isIOS && is('(hover: none), (pointer: coarse)')) {
        thumb = document.createElement('div');
        thumb.id = 'paliweb-scrollbar';
        thumb.setAttribute('aria-hidden', 'true');
        document.body.appendChild(thumb);
        document.documentElement.classList.add('pw-sb');
    }

    bar.style.strokeDasharray = length;
    bar.style.strokeDashoffset = length;

    const measure = () => {
        viewH = window.innerHeight;
        maxScroll = Math.max(1, document.documentElement.scrollHeight - viewH);

        if (thumb) {
            thumbH = Math.max(40, Math.min(viewH - 8, viewH * viewH / (maxScroll + viewH)));
            thumb.style.height = thumbH + 'px';
        }
    };

    const hideThumb = () => {
        thumbOn = false;
        thumb.classList.remove('pw-on');
    };

    const update = () => {
        queued = false;

        const y = window.scrollY || 0;
        const p = Math.min(1, Math.max(0, y / maxScroll));

        if (p !== progress) {
            const moved = progress >= 0;

            progress = p;
            bar.style.strokeDashoffset = length * (1 - p);

            const on = p > 0.002; // جلوگیری از نقطه‌ی کوچک در حالت صفر

            if (on !== barOn) {
                barOn = on;
                bar.style.opacity = on ? '1' : '0';
            }

            if (thumb) {
                thumb.style.transform = `translateY(${4 + p * (viewH - 8 - thumbH)}px)`;

                if (moved) {
                    if (!thumbOn) {
                        thumbOn = true;
                        thumb.classList.add('pw-on');
                    }

                    clearTimeout(hideTimer);
                    hideTimer = setTimeout(hideThumb, 900);
                }
            }
        }

        const show = y > SHOW_AFTER;

        if (show !== visible) {
            visible = show;
            button.classList.toggle('paliweb-visible', show);
        }
    };

    window.addEventListener('scroll', () => {
        if (queued) return;
        queued = true;
        requestAnimationFrame(update);
    }, { passive: true });

    window.addEventListener('resize', measure, { passive: true });
    window.addEventListener('load', () => { measure(); update(); });

    if ('ResizeObserver' in window) {
        new ResizeObserver(measure).observe(document.body);
    }

    button.addEventListener('click', () => {
        if (window.paliwebLenis) {
            window.paliwebLenis.scrollTo(0, { duration: 1.3 });
        } else {
            window.scrollTo({ top: 0, behavior: 'smooth' });
        }
    });

    measure();
    update();

    /* ---------- Lenis (فقط دسکتاپ با ماوس) ---------- */

    if (
        !is('(min-width: 768px) and (hover: hover) and (pointer: fine)') ||
        is('(prefers-reduced-motion: reduce)') ||
        window.paliwebLenis
    ) {
        return;
    }

    // المنت‌هایی که اسکرول داخلی خودشان را دارند
    const NATIVE = '.elementor-popup-modal,.dialog-widget-content,.select2-container,.woocommerce-mini-cart,.elementor-menu-cart__container';

    const script = document.createElement('script');

    script.src = 'https://cdn.jsdelivr.net/npm/lenis@1.3.17/dist/lenis.min.js';
    script.async = true;

    script.onload = () => {
        if (typeof Lenis === 'undefined' || window.paliwebLenis) return;

        window.paliwebLenis = new Lenis({
            autoRaf: true,
            duration: 1.1, // کمتر = سریع‌تر
            easing: (t) => Math.min(1, 1.001 - 2 ** (-10 * t)), // توقف نرم
            smoothWheel: true,
            wheelMultiplier: 1,
            syncTouch: false,
            prevent: (node) => !!node.closest?.(NATIVE)
        });

        measure();
    };

    document.head.appendChild(script);
})();
</script>

<?php

});

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *