CSS Tutorial menu

CSS Scroll Snap and Smooth Scrolling

CSS can control how a page scrolls: it can glide smoothly to a section, and it can stop neatly on each item of a carousel.

Smooth Scrolling

When a link points to a part of the same page, like href="#contact", the browser normally jumps there instantly. One line makes it glide instead:

Example

css
html {
  scroll-behavior: smooth;
}
ValueEffect
autoJumps straight to the place (the default)
smoothScrolls smoothly to the place

Fixing the Sticky Header Problem

If your page has a sticky header, a jump link puts the section heading under the header, where nobody can see it. scroll-margin-top leaves room above the target.

Example

html
<!DOCTYPE html>
<html>
<head>
<style>
html { scroll-behavior: smooth; }
body { margin: 0; font-family: Arial, sans-serif; }
header {
  position: sticky;
  top: 0;
  background-color: #264de4;
  padding: 12px;
}
header a { color: white; margin-right: 12px; }
section {
  min-height: 500px;
  padding: 16px;
  scroll-margin-top: 50px;
}
#about { background-color: #eef2ff; }
#courses { background-color: #fef3c7; }
#contact { background-color: #dcfce7; }
</style>
</head>
<body>

<header>
  <a href="#about">About</a>
  <a href="#courses">Courses</a>
  <a href="#contact">Contact</a>
</header>
<section id="about"><h2>About Us</h2></section>
<section id="courses"><h2>Our Courses</h2></section>
<section id="contact"><h2>Contact</h2><p>Orangi Town, Karachi</p></section>

</body>
</html>
Try it Yourself »

Click the links. The page glides, and each heading stops just below the blue header.

Smooth scrolling can bother people who get dizzy from motion. Turn it on only for users who have not asked for less motion: put the rule inside @media (prefers-reduced-motion: no-preference) { ... }. See the CSS Accessibility chapter.

Scroll Snap

Scroll snap makes a scroll area stop exactly on an item, like swiping photos on a phone. You need two properties:

  1. On the scroll container: scroll-snap-type
  2. On each child: scroll-snap-align
PropertyCommon valuesMeaning
scroll-snap-typex mandatory, y proximityWhich direction snaps, and how strongly
scroll-snap-alignstart, center, endWhich part of the child lines up with the container
scroll-snap-stopalwaysDo not skip past this item on a fast swipe
scroll-padding16pxSpace kept inside the container's edge when snapping
  • mandatory always snaps to an item when scrolling stops.
  • proximity only snaps if you stop close to an item.

Example

html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial, sans-serif; }
.carousel {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding: 0 16px;
  padding: 0 16px 12px;
}
.slide {
  flex: 0 0 80%;
  scroll-snap-align: start;
  aspect-ratio: 16 / 9;
  border-radius: 10px;
  display: grid;
  place-items: center;
  color: white;
  font-size: 1.5rem;
}
.slide:nth-child(1) { background-color: #264de4; }
.slide:nth-child(2) { background-color: crimson; }
.slide:nth-child(3) { background-color: seagreen; }
.slide:nth-child(4) { background-color: #f97316; }
</style>
</head>
<body>

<h2>Student Projects</h2>
<div class="carousel">
  <div class="slide">Restaurant website</div>
  <div class="slide">Online shop</div>
  <div class="slide">Portfolio</div>
  <div class="slide">School app</div>
</div>

</body>
</html>
Try it Yourself »

Scroll the row sideways (or swipe on a phone). It always stops with a slide lined up at the start. Each slide is 80% wide, so a part of the next slide peeks out, which tells users there is more to see.

Full-Page Vertical Sections

The same idea works up and down. Each section fills the screen, and the page snaps from one to the next.

Example

css
.page {
  height: 100dvh;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
}
.page section {
  height: 100dvh;
  scroll-snap-align: start;
}

Use vertical mandatory snapping with care. If a section is taller than the screen, users may not be able to read its bottom part. proximity is safer for long content.

Hiding the Scroll Bar

Carousels often look cleaner without a scroll bar. Users can still swipe or use the arrow keys.

Example

css
.carousel {
  scrollbar-width: none;
}

Use scrollbar-width: thin if you want a smaller bar instead of none, and scrollbar-color to colour it.

Exercise

Exercise

Which pair of properties creates scroll snapping?

Learn CSS with a teacher

Join the Web Development course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp