Create a Smooth Page Scroll Effect Using JavaScript

Smooth page scrolling enhances user experience by making navigation feel more natural and fluid. Instead of abrupt jumps between sections, smooth scrolling guides visitors through content in a way that feels controlled and intuitive. This subtle improvement can make a website feel more polished and professional, improving both usability and engagement.

While modern browsers support CSS-based smooth scrolling with scroll-behavior: smooth, it doesn’t offer much flexibility. JavaScript provides a more efficient and customizable way to achieve smooth page scroll effects, allowing for dynamic adjustments, easing functions, and better control over scrolling behavior.

A well-implemented smooth scroll effect improves the user experience in several ways:

  • Better Flow – It guides users through content naturally, making navigation more intuitive.
  • Improved Accessibility – Users can track their position as they move, reducing confusion.
  • Aesthetics – Smooth transitions create a polished and modern feel for a website.
  • Engagement Boost – Users are more likely to explore and stay longer when interactions feel effortless.

Smooth Scrolling with CSS

For a simple way to enable smooth scrolling, modern browsers support the scroll-behavior: smooth property in CSS. This allows users to scroll between anchor links with a gradual motion instead of an instant jump.

How to Enable Smooth Scrolling with CSS

Adding smooth scrolling with CSS is as simple as applying one line of code to the <html> element:

html {
  scroll-behavior: smooth;
}

Once applied, any internal link that points to an ID on the page will automatically scroll smoothly:

<a href="#section2">Go to Section 2</a>

<div id="section2">
  <h2>Section 2</h2>
  <p>Content here...</p>
</div>

Limitations of CSS Smooth Scrolling

CSS provides a quick solution, but it has some major drawbacks:

  • Only Works for Anchor Links
    The effect applies only when clicking <a href="#target"> links. It does not work for programmatic scrolling, such as scrolling triggered by buttons or scripts.
  • No Control Over Speed or Easing
    CSS applies a default scrolling speed, and there’s no way to adjust it or add easing effects (such as gradual acceleration or deceleration).
  • Limited Browser Support
    While most modern browsers support it, older versions (especially Internet Explorer) do not.

If you need more flexibility—such as adjusting scroll speed, animating scroll behavior, or enabling smooth scrolling for buttons and other interactions—JavaScript is a better option. 

Smooth Page Scroll with JavaScript

JavaScript provides several ways to create smooth scrolling effects, each with different levels of flexibility. 

  1. Using scrollIntoView() – A simple built-in method for scrolling elements into view.
  2. Using window.scrollTo() with behavior: smooth – Offers more control over scroll behavior.
  3. Custom Smooth Scrolling with requestAnimationFrame() – A fully customizable approach for precise control over speed and easing.

Using scrollIntoView()

The scrollIntoView() method is a built-in way to smoothly scroll an element into view. It’s easy to implement and works well for basic interactions like navigating to sections when clicking a button or link.

This method is called on a target element and brings it into view smoothly when triggered.

Example: Smooth Scrolling to a Section

<button id="scrollButton">Go to Section</button>

<div id="targetSection" style="margin-top: 1000px;">
  <h2>Target Section</h2>
</div>

<script>
document.getElementById("scrollButton").addEventListener("click", function() {
  document.getElementById("targetSection").scrollIntoView({ behavior: "smooth" });
});
</script>

Pros of scrollIntoView()

  • Easy to implement
  • Works in most modern browsers
  • Requires minimal JavaScript

Cons of scrollIntoView()

  • No control over scroll duration
  • Can be inconsistent in older browsers
  • Might not work well with fixed headers (can cause abrupt jumps)

window.scrollTo() for More Control

The window.scrollTo() method with the behavior: smooth option provides better flexibility compared to scrollIntoView(). It allows scrolling to specific pixel positions rather than elements.

Instead of scrolling to a specific element, this method scrolls the entire page to a given coordinate.

Example: Smooth Scrolling to a Specific Position

<button id="scrollToTop">Scroll to Top</button>

<script>
document.getElementById("scrollToTop").addEventListener("click", function() {
  window.scrollTo({ top: 0, behavior: "smooth" });
});
</script>

Scrolling to a Specific Element’s Position

<button id="scrollButton">Go to Section</button>

<div id="targetSection" style="margin-top: 1000px;">
  <h2>Target Section</h2>
</div>

<script>
document.getElementById("scrollButton").addEventListener("click", function() {
  let targetPosition = document.getElementById("targetSection").offsetTop;
  window.scrollTo({ top: targetPosition, behavior: "smooth" });
});
</script>

Pros of window.scrollTo()

  • More precise control over scroll position
  • Works well with dynamic elements
  • Avoids some issues with fixed headers

Cons of window.scrollTo()

  • Still lacks full control over scroll duration and easing effects.

Custom Smooth Scrolling with requestAnimationFrame()

For advanced use cases, requestAnimationFrame() allows full customization of scroll behavior, including easing functions and dynamic speed adjustments. This method gives you complete control over how the scrolling effect behaves.

  • Control over speed and acceleration (easing effects like “ease-in” and “ease-out”).
  • Works across all browsers, including older ones.
  • Can be used with various triggers, such as mouse events, buttons, or keyboard shortcuts.

Custom Smooth Scroll Implementation

<button id="scrollButton">Go to Section</button>

<div id="targetSection" style="margin-top: 1000px;">
  <h2>Target Section</h2>
</div>

<script>
function smoothScrollTo(targetPosition, duration = 500) {
  let startPosition = window.scrollY;
  let distance = targetPosition - startPosition;
  let startTime = null;

  function animation(currentTime) {
    if (startTime === null) startTime = currentTime;
    let timeElapsed = currentTime - startTime;
    let progress = Math.min(timeElapsed / duration, 1);

    // Apply easing (ease-in-out)
    let easedProgress = progress < 0.5 
      ? 2 * progress * progress 
      : -1 + (4 - 2 * progress) * progress;

    window.scrollTo(0, startPosition + distance * easedProgress);

    if (timeElapsed < duration) {
      requestAnimationFrame(animation);
    }
  }

  requestAnimationFrame(animation);
}

document.getElementById("scrollButton").addEventListener("click", function() {
  let targetPosition = document.getElementById("targetSection").offsetTop;
  smoothScrollTo(targetPosition);
});
</script>

Pros of Custom Smooth Scrolling

  • Full control over scrolling behavior
  • Allows custom easing for smoother transitions
  • Works across all browsers, even older ones

Cons of Custom Smooth Scrolling

  • Requires more code than built-in methods.

Choosing the Right Smooth Scrolling Method

Method Pros Cons
scrollIntoView() Simple, minimal JavaScript No control over speed or easing
window.scrollTo() More precise than scrollIntoView(), good for fixed headers No easing control
Custom requestAnimationFrame() Full control over duration and easing Requires more code

If you need a quick solution, use scrollIntoView() or window.scrollTo().

For a fully customizable experience, use a custom JavaScript function with requestAnimationFrame().

Advanced Scrolling Features

Implementing smooth page scrolling is just the beginning. To create a truly seamless and user-friendly experience, you can enhance it by:

  • Making anchor links scroll smoothly to their targets.
  • Adjusting scroll speed and easing functions for a more natural feel.
  • Handling browser compatibility to ensure smooth scrolling works across different environments.

Adding Smooth Scrolling for Anchor Links

Anchor links (<a href="#section">) are a common way to navigate within a page, but by default, they jump instantly to the target section. Using JavaScript, we can override this behavior and apply smooth scrolling instead.

JavaScript for Smooth Anchor Link Scrolling

<a href="#section2" class="smooth-scroll">Go to Section 2</a>

<div id="section2" style="margin-top: 1000px;">
  <h2>Section 2</h2>
  <p>Content here...</p>
</div>

<script>
document.querySelectorAll('.smooth-scroll').forEach(anchor => {
  anchor.addEventListener('click', function(e) {
    e.preventDefault(); // Prevent default jump
    let targetId = this.getAttribute('href').substring(1);
    let targetElement = document.getElementById(targetId);

    if (targetElement) {
      window.scrollTo({ top: targetElement.offsetTop, behavior: 'smooth' });
    }
  });
});
</script>

Why This Works Well

  • Applies smooth scrolling to all anchor links with class="smooth-scroll"
  • Prevents default instant jumping behavior
  • Works on all modern browsers that support behavior: smooth

Adjusting Scroll Speed and Easing Functions

By default, behavior: smooth applies a basic scrolling effect, but it lacks control over speed and easing. For a better user experience, we can create custom scrolling with requestAnimationFrame(), allowing us to fine-tune how the scrolling behaves.

Custom Smooth Scrolling with Adjustable Speed and Easing

<a href="#section3" class="smooth-scroll">Scroll to Section 3</a>

<div id="section3" style="margin-top: 1200px;">
  <h2>Section 3</h2>
</div>

<script>
function smoothScroll(targetPosition, duration = 800) {
  let startPosition = window.scrollY;
  let distance = targetPosition - startPosition;
  let startTime = null;

  function easeInOutQuad(t) {
    return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
  }

  function animation(currentTime) {
    if (startTime === null) startTime = currentTime;
    let timeElapsed = currentTime - startTime;
    let progress = Math.min(timeElapsed / duration, 1);
    let easingEffect = easeInOutQuad(progress);

    window.scrollTo(0, startPosition + distance * easingEffect);

    if (timeElapsed < duration) {
      requestAnimationFrame(animation);
    }
  }

  requestAnimationFrame(animation);
}

document.querySelectorAll('.smooth-scroll').forEach(anchor => {
  anchor.addEventListener('click', function(e) {
    e.preventDefault();
    let targetId = this.getAttribute('href').substring(1);
    let targetElement = document.getElementById(targetId);
    
    if (targetElement) {
      smoothScroll(targetElement.offsetTop, 1000); // Adjust duration here
    }
  });
});
</script>

Why Use Custom Easing?

  • Creates a smoother and more natural feel than default scrolling
  • Allows adjusting duration and speed dynamically
  • Works in all browsers that support requestAnimationFrame()

Handling Browser Compatibility

Although behavior: smooth works well in modern browsers, some older ones don’t support it. A custom JavaScript solution ensures smooth scrolling works universally.

Feature Modern Browsers Older Browsers (IE, Legacy Edge)
scroll-behavior: smooth Supported Not supported
window.scrollTo({ behavior: "smooth" }) Supported Not supported
requestAnimationFrame() custom scroll Supported Works in all browsers

To ensure compatibility across all browsers, use a fallback:

Fallback for Browsers That Don’t Support behavior: smooth

function smoothScrollFallback(targetPosition, duration = 800) {
  if ('scrollBehavior' in document.documentElement.style) {
    window.scrollTo({ top: targetPosition, behavior: 'smooth' });
  } else {
    smoothScroll(targetPosition, duration); // Custom function as fallback
  }
}

This checks if scrollBehavior is supported—if not, it falls back to the custom smooth scroll function.

Testing and Debugging for Smooth Scrolling

Once you’ve implemented smooth page scrolling, it’s important to test and debug it to ensure it works across different devices and browsers. Smooth scrolling should feel natural, respond correctly to user interactions, and function consistently without glitches.

To provide the best user experience, test smooth scrolling on:

  • Desktops & Laptops
    Test on both Windows and macOS browsers (Chrome, Firefox, Edge, Safari).
  • Mobile Devices
    Ensure scrolling works smoothly on both Android (Chrome, Samsung Internet) and iOS (Safari, Chrome).
  • Touch vs. Mouse Navigation
    Check if the scrolling behaves properly when using touch gestures, a trackpad, and a mouse wheel.

To ensure smooth scrolling works as expected, it's important to test it across different devices and scenarios:

  • Use Developer Tools
    Open Chrome DevTools (F12 or right-click → Inspect) and simulate mobile devices in the responsive design mode.
  • Check Scroll Behavior on Different Screens
    Scroll through different sections manually and ensure smooth transitions.
  • Test at Different Speeds
    Scroll slowly and quickly to see if any lag or abrupt jumps occur.
  • Use Browser Console for Errors
    Open the console (F12 → Console) to check for JavaScript errors that might be affecting smooth scrolling.

Troubleshooting Common Smooth Scrolling Issues

If smooth scrolling isn’t working as expected, there are several common issues that may be causing the problem, along with solutions to fix them.

Smooth Scrolling Doesn't Work on Some Browsers

  • Issue: Older browsers (like Internet Explorer) don’t support scroll-behavior: smooth or behavior: smooth in scrollTo().
  • Solution: Use a custom requestAnimationFrame() scrolling function as a fallback for full compatibility
function isSmoothScrollSupported() {
  return 'scrollBehavior' in document.documentElement.style;
}

function smoothScrollFallback(targetPosition, duration = 800) {
  if (isSmoothScrollSupported()) {
    window.scrollTo({ top: targetPosition, behavior: 'smooth' });
  } else {
    smoothScroll(targetPosition, duration); // Custom JavaScript fallback
  }
}

Smooth Scrolling Feels Too Fast or Too Slow

  • Issue: Default behavior: smooth scrolling may feel too quick or sluggish, depending on content length.
  • Solution: Adjust the scroll duration using a custom easing function with requestAnimationFrame().
smoothScroll(targetPosition, 1200); // Increase the duration for slower scrolling

Fixed Headers Overlap the Target Section

  • Issue: When scrolling to a section, part of the content is hidden behind a fixed header.
  • Solution: Offset the scroll position by the height of the header.
let headerHeight = document.querySelector('header').offsetHeight;
let targetPosition = document.getElementById('targetSection').offsetTop - headerHeight;

window.scrollTo({ top: targetPosition, behavior: 'smooth' });

Scroll Jumps or Stutters on Some Devices

  • Issue: Some devices or browsers (especially older mobile browsers) may cause stuttering during smooth scrolling.
  • Solution: Use GPU acceleration by applying will-change: transform in CSS to optimize rendering.
html {
  will-change: scroll-position;
}

Scrolling Stops Unexpectedly Before Reaching Target

  • Issue: scrollIntoView() may cause abrupt stops if elements dynamically load after the page renders.
  • Solution: Ensure the element exists before scrolling. Use setTimeout() for delayed scrolling if needed.
setTimeout(() => {
  document.getElementById("targetSection").scrollIntoView({ behavior: "smooth" });
}, 100);

By carefully testing and debugging, you ensure a consistent, smooth scrolling experience across all platforms, making your website more polished and user-friendly.

Every project is unique, and the best approach depends on your needs. If you want a quick fix, CSS or built-in JavaScript methods may be enough. If you need more flexibility and control, a custom scrolling function can fine-tune the experience.

Experiment with different techniques, test how they feel on your site, and optimize for the best user experience. A well-implemented smooth scroll effect makes your website more engaging, accessible, and enjoyable to navigate.

Need a Helping Hand with Your Project?

Whether you need continuous support through our Flexible Retainer Plans or a custom quote, we're dedicated to delivering services that align perfectly with your business goals.

Please enter your name

Please enter your email address

Contact by email or phone?

Please enter your company name.

Please enter your phone number

What is your deadline?

Please tell us a little about your project