You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将smooth-scrollbar.js指定到.content容器而非body,修复自定义光标滚动不跟随问题

Fixing Smooth-Scrollbar + Custom Cursor Sync Issue

Got it, let's fix that cursor sync problem by shifting the smooth-scrollbar target from body to your .content container. Here's the step-by-step adjustment plus the full working code:

Key Modifications Needed

1. Update Smooth-Scrollbar Initialization

Change the target from document.body to your .content container when initializing Scrollbar.

2. Adjust ScrollTrigger Proxy & Defaults

Update the ScrollTrigger scroller proxy to point to the .content container, and set it as the default scroller for ScrollTrigger.

3. Tweak CSS Layout

Make body fixed (so it doesn't scroll natively) and set .content as the full-viewport scrollable container.


Modified Full Code

JavaScript

const cursor = document.querySelector('#cursor');
const cursorCircle = cursor.querySelector('.cursor__circle');
const mouse = { x: -100, y: -100 }; // mouse pointer's coordinates
const pos = { x: 0, y: 0 }; // cursor's coordinates
const speed = 0.1; // between 0 and 1

const updateCoordinates = e => {
 mouse.x = e.clientX;
 mouse.y = e.clientY;
}

window.addEventListener('mousemove', updateCoordinates);

function getAngle(diffX, diffY) {
 return Math.atan2(diffY, diffX) * 180 / Math.PI;
}

function getSqueeze(diffX, diffY) {
 const distance = Math.sqrt(
 Math.pow(diffX, 2) + Math.pow(diffY, 2)
 );
 const maxSqueeze = 0.15;
 const accelerator = 1500;
 return Math.min(distance / accelerator, maxSqueeze);
}

const updateCursor = () => {
 const diffX = Math.round(mouse.x - pos.x);
 const diffY = Math.round(mouse.y - pos.y);

 pos.x += diffX * speed;
 pos.y += diffY * speed;

 const angle = getAngle(diffX, diffY);
 const squeeze = getSqueeze(diffX, diffY);

 const scale = 'scale(' + (1 + squeeze) + ', ' + (1 - squeeze) +')';
 const rotate = 'rotate(' + angle +'deg)';
 const translate = 'translate3d(' + pos.x + 'px ,' + pos.y + 'px, 0)';

 cursor.style.transform = translate;
 cursorCircle.style.transform = rotate + scale;
};

function loop() {
 updateCursor();
 requestAnimationFrame(loop);
}

requestAnimationFrame(loop);

const cursorModifiers = document.querySelectorAll('[cursor-class]');

cursorModifiers.forEach(curosrModifier => {
 curosrModifier.addEventListener('mouseenter', function() {
 const className = this.getAttribute('cursor-class');
 cursor.classList.add(className);
 });
 curosrModifier.addEventListener('mouseleave', function() {
 const className = this.getAttribute('cursor-class');
 cursor.classList.remove(className);
 });
});

gsap.registerPlugin(ScrollTrigger);
ScrollTrigger.defaults({ markers: false });

// --- Modified Part ---
// Initialize smooth-scrollbar on .content container instead of body
const scrollContainer = document.querySelector('.content');
var scrollbar = Scrollbar.init(scrollContainer, {
 delegateTo: document,
 alwaysShowTracks: false,
 speed: 0.7,
 damping:0.1
});

// Update ScrollTrigger proxy to use the content container
ScrollTrigger.scrollerProxy(scrollContainer, {
 scrollTop(value) {
 if (arguments.length) {
 scrollbar.scrollTop = value;
 }
 return scrollbar.scrollTop;
 }
});

scrollbar.addListener(ScrollTrigger.update);
// Set default scroller to the content container
ScrollTrigger.defaults({ scroller: scrollContainer });
// --- End Modified Part ---

CSS

#cursor {
 position: fixed;
 z-index: 99;
 left: 0;
 top: 0;
 pointer-events: none;
 will-change: transform;
 mix-blend-mode: difference;
}

@media (hover: hover) and (pointer: fine) {
 .cursor__circle {
 width: 64px;
 height: 64px;
 margin-top: -50%;
 margin-left: -50%;
 border-radius: 50%;
 border: solid 1px rgba(227, 222, 193, 0.64);
 transition: opacity 0.3s cubic-bezier(0.25, 1, 0.5, 1), background-color 0.3s cubic-bezier(0.25, 1, 0.5, 1), border-color 0.3s cubic-bezier(0.25, 1, 0.5, 1), width 0.3s cubic-bezier(0.25, 1, 0.5, 1), height 0.3s cubic-bezier(0.25, 1, 0.5, 1);
 }
 #cursor.arrow .cursor__circle{
 width: 128px;
 height: 128px;
 background-color: #073099;
 border-color: #073099;
 }
 #cursor.arrow::after{
 content: '';
 position: absolute;
 left: -50%;
 top: -50%;
 width: 100%;
 height: 100%;
 background-image: url('https://svgshare.com/i/MzQ.svg');
 background-repeat: no-repeat;
 background-position: center;
 }
 #cursor.subtle .cursor__circle{
 opacity: 0.16;
 }
 #cursor.overlay .cursor__circle{
 width: 48px;
 height: 48px;
 background-color: rgba(227, 222, 193, 0.08);
 border-color: transparent;
 }
}

* {
 margin: 0;
 padding: 0;
 border: none;
 outline: none;
 text-decoration: none;
}

/* --- Modified Part --- */
html, body {
 width: 100%;
 height: 100%;
 overflow: hidden; /* Prevent native body scroll */
}

.content {
 width: 100%;
 height: 100vh; /* Fill viewport height */
 overflow: hidden; /* Let smooth-scrollbar handle scrolling */
}
/* --- End Modified Part --- */

section{
 position: relative;
 display: flex;
 align-items: center;
 justify-content: center;
 background-color: #f7f7f7;
 height: 100%; /* Ensure sections fill content container */
}

section::after{
 content: 'Only for laptop or desktop 🙅‍♂️';
 position: fixed;
 display: flex;
 align-items: center;
 justify-content: center;
 width: 100%;
 height: 100%;
 background-color: rgba(255, 255, 255, 0.7);
 font-family: 'Poppins', sans-serif;
 font-size: 1rem;
 color: #1c213e;
 line-height: 1.7;
}

.container{
 width: 33vw;
}

.image-container{
 overflow: hidden;
 cursor: pointer;
 width: 100%;
 height: 75%;
 /* margin-bottom: 0.5vw; */
 margin-top: 10vw;
}

.image-container img{
 width: 100%;
 height: 100%;
 object-fit: cover;
 filter: brightness(95%);
 transition: transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
}

.text{
 font-family: 'Poppins', sans-serif;
 font-size: 1rem;
 color: #1c213e;
 line-height: 1.7;
}

.underline{
 position: relative;
 display: inline-block;
 cursor: pointer;
}

.underline::after{
 content: '';
 position: absolute;
 left: 0;
 bottom: 0;
 width: 100%;
 height: 1px;
 background-color: #1c213e;
 opacity: 0.32;
 transition: opacity 0.3s cubic-bezier(0.25, 1, 0.5, 1);
}

.button{
 position: relative;
 display: flex;
 align-items: center;
 justify-content: center;
 cursor: pointer;
 font-family: 'Poppins', sans-serif;
 color: #1c213e;
}

.button.icon-button{
 background-color: transparent;
 width: 40px;
 height: 40px;
 margin: -8px;
}

.info{
 display: flex;
 align-items: center;
 justify-content: space-between;
}

@media (hover: hover) and (pointer: fine) {
 .image-container:hover img{
 transform: scale(1.1);
 }
 .underline:hover::after{
 opacity: 1;
 }
 section::after{
 display: none;
 }
}

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/smooth-scrollbar/8.7.4/smooth-scrollbar.js"></script>
<script src="https://unpkg.com/gsap@3/dist/ScrollTrigger.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js"></script>

<div id="cursor">
 <div class="cursor__circle"></div>
</div>

<div class="content">
 <section>
 <div class="container">
 <div class="image-container" cursor-class="arrow">
 <img src="https://i.ibb.co/HDvyzVW/vase-2.jpg" alt="minimalist vase">
 </div>
 </div>
 </section>
 <section>
 <div class="container">
 <div class="image-container" cursor-class="arrow">
 <img src="https://i.ibb.co/HDvyzVW/vase-2.jpg" alt="minimalist vase">
 </div>
 </div>
 </section>
</div>

Why This Works

When smooth-scrollbar was bound to body, it was replacing the native scroll behavior, which caused your fixed-position cursor to lose sync because the page's scroll offset wasn't being tracked correctly. By moving the scroll context to the .content container:

  • The body stays fixed, so your cursor (positioned fixed) remains anchored to the viewport correctly.
  • Smooth-scrollbar handles scrolling inside the .content container, which doesn't interfere with the cursor's position tracking.
  • ScrollTrigger is properly linked to the new scroll container, ensuring any scroll-based animations still work as expected.

内容的提问来源于stack exchange,提问作者gjjr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 21:07:48