DEV Community

Cover image for CSS Smooth Scrolling

CSS Smooth Scrolling

Rik Schennink on February 14, 2019

Last year, while building the FilePond product page I stumbled upon the scrollIntoView API. It's a handy method to instruct the browser to scroll a...
Collapse
 
jonaskuske profile image
Jonas • Edited

To those concerned about browser support:

  1. Consider if it's actually that important.
  2. If your answer is yes...

Add these polyfills to your HTML:

<script src="https://unpkg.com/smoothscroll-polyfill/dist/smoothscroll.min.js"></script>
<script src="https://unpkg.com/smoothscroll-anchor-polyfill"></script>
Enter fullscreen mode Exit fullscreen mode

and use a custom property on html in addition to the normal CSS property:

html {
  --scroll-behavior: smooth;
  scroll-behavior: smooth;
}
Enter fullscreen mode Exit fullscreen mode



The first polyfill is for polyfilling the JavaScript methods window.scroll({ behavior: 'smooth') and Element.scrollIntoView(), the second one (disclosure: written by me) syncs it up with the CSS. There are also ways to use it with IE, and the awesome stuff described here like respecting (prefers-reduced-motion: reduce) will still work πŸ‘πŸ»




Full docs: jonaskuske.github.io/smoothscroll-... βš“
Collapse
 
rikschennink profile image
Rik Schennink

Thanks! Interesting approach to use font-family to pass data to JS. Maybe it’s an idea to also (or instead) allow use of a CSS custom property? The font-family trick feels a bit hacky, it might stand in the way of people using your library.

Collapse
 
jonaskuske profile image
Jonas • Edited

Yep, it's definitely hacky (but totally works)! πŸ˜…

But afaik it's the only reliable way to detect CSS unknown to the browser without having to collect/fetch every single stylesheet on a page (with something like getElementsByTagName), parse through all of them with a Regex and repeat that every time some styles change. There's actually a library that helps with that so implementation isn't a problem, but it's quite the added runtime cost for such a small feature, so I decided against it.

Custom properties are a good idea
(thanks!) and I'll add them, but the use case there is basically just "I need smooth scroll in Edge but don't care about older browsers" as older browsers without scrollBehavior most likely lack support for custom properties as well 😐

Edit: And yup, the approach is interesting for sure, but I can't really take "credit" for it: took the idea from a quite popular object-fit polyfill – which is why my PostCSS plugin is just a fork of theirs with a few adjustments :D

Thread Thread
 
rikschennink profile image
Rik Schennink

Don’t forget about Safari ;-)

Might be a good idea to just not have it on IE11 as the performance impact might not be worth it.

Thread Thread
 
jonaskuske profile image
Jonas

Oh, Safari, you're right!
I think you convinced me, I'll go with --scroll-behavior as default and only offer the font-family detection as option to support legacy browsers like IE 🀞🏻

...and I don't think running getComputedStyle(el).fontFamily when an anchor with a local href is clicked is so bad for performance that it justifies dropping IE support, do you? Or do you mean the performance impact of polyfilling smooth scroll in general?

Thread Thread
 
rikschennink profile image
Rik Schennink

Awesome.

I haven’t tested it but the scroll behavior itself might be too much.

getComputedStyle returns a live object so you’ll only have to request it once, but even if you requested it multiple times I don’t think it would be problematic.

Thread Thread
 
jonaskuske profile image
Jonas

I'm using it on the documentation site and it works smoothly, even on IE9 with requestAnimationFrame substituted as setTimeout(fn, 0) πŸ˜…
Also used it just fine on a production site that's very heavy on smooth scrolling (while at the same time running a position: sticky polyfill runtime), so I'm not too concerned about performance. :)

And didn't know getComputedStyle returns a live binding, thanks for the info! Will take this into account next time I update the package πŸ‘πŸ»

So, current strategy:

  • Have custom property --scroll-behavior as default/recommended way of adjusting the behavior
  • Keep supporting fontFamily and inline styles for legacy support/convenience
  • Do you think it's worth it having the custom property that's used be configurable, so users can use some other property instead of --scroll-behavior if they want?

To go with these changes, the PostCSS Plugin shall compile scroll-behavior: smooth to:

scroll-behavior: smooth;
--scroll-behavior: smooth;

and if browserslist includes browsers without support for custom properties, compile to:

scroll-behavior: smooth;
--scroll-behavior: smooth;
font-family: 'scroll-behavior: smooth', /* user defined fonts */;

(while accepting { customProperty: boolean, fontFamily: boolean } config so users can overwrite this behavior)

Do you have any feedback on this?
(sorry to bother you but your input was very valuable so far πŸ™‚)

Thread Thread
 
rikschennink profile image
Rik Schennink

Looks good to me! Love the very structured approach. πŸ‘

  • Careful with wanting to support everything. Could increase library size, might introduce weird bugs (certainly on very old browsers) sometimes a simple mustard cut is a lot better for everyone.
Collapse
 
fluffy profile image
fluffy

Thank you for mentioning the accessibility thing! I am (literally) sick of websites that add smooth scrolling with no way to disable it. Personally I don't see the point because it makes everything feel laggy and swimmy and I want my scrolling to have a 1:1 correspondence with my scroll wheel/gesture/whatever, like what my brain expects.

Collapse
 
rikschennink profile image
Rik Schennink

It's often overlooked, glad to hear it's appreciated.

I hate scroll jacking. In this case, we're only animating the move towards a new part of the page, just as with carefully planned animations, it's mostly about not losing context while transitioning between two locations.

Collapse
 
thomasbnt profile image
Thomas Bnt β˜•

Nice! I use this for Smooth Scroll.

Collapse
 
qm3ster profile image
Mihail Malo • Edited

The codepen's behavior inside DEV.to embed is fascinating.
It first scrolls DEV.to down until only one line of the embed is left, then scrolls the embed until that remaining line is just after the infinity.

Collapse
 
rikschennink profile image
Rik Schennink

Oh my goodness, yes! Hadn't noticed. It's so weird :D

Collapse
 
httpjunkie profile image
Eric Bishard

Short and sweet, I love it!

Collapse
 
abdurrahmaanj profile image
Abdur-Rahmaan Janhangeer

i actually learned something from it!

Collapse
 
leejinseok profile image
dooly

Nice but cross browsing issue
caniuse.com/#search=scroll-behavior

Collapse
 
jonaskuske profile image
Jonas • Edited

Add these to your HTML:

<script src="https://unpkg.com/smoothscroll-polyfill/dist/smoothscroll.min.js"></script>
<script src="https://unpkg.com/smoothscroll-anchor-polyfill"></script>

and add font-family everywhere you set scroll-behavior:

html {
  scroll-behavior: smooth;
  font-family: 'scroll-behavior: smooth' /*, actual fonts */;
}

The first polyfill generally polyfills scroll({ behavior: 'smooth'), the second one (disclosure: written by me) syncs it up with the CSS. πŸ‘πŸ»


If you don't like the font-family stuff, you can also run your styles through PostCSS with this – or just use an inline style attribute on html:

<html style="scroll-behavior: smooth">

The workaround is not required there. :)

Full docs: jonaskuske.github.io/smoothscroll-... βš“

Collapse
 
rikschennink profile image
Rik Schennink

This link is in the article 😊

You can make the choice to only use features that are available everywhere or you follow a progressive enhancement strategy and offer users on more modern browsers a better browsing experience (in this case with little effort).