Scroll an element into the center of the viewport

Say your page displays a list of names and you want a certain person to be highlighted and scrolled into view. There’s a browser API for that: Element.scrollIntoView(), which scrolls an element into view.

Element.scrollIntoView() can take two types of elements: a boolean or an object. The object argument gives developers more control over how elements ‘in view’ are aligned, but has slightly less browser support. Let’s look at what we can do with both.

The boolean argument

Say, you have a couple of people in a list:

<ul>
  <li id="alice">Alice Cruz</li>
  <li id="daniel">Daniel Ho</li><li id="julie">Julie Howard</li></ul>

(Example on Codepen)

If you want Julie to be scrolled into view, find the relevant element, then call scrollIntoView():

const julie = document.getElementById('julie');

julie.scrollIntoView();

This scrolls the element into view. With a boolean argument, you can have some control over alignment. If you pass true (default), the browser will scroll so that the element is at the top of your viewport or other scrollable element. With false, it scrolls so the element is at the bottom of the viewport:

julie.scrollIntoView(true) // align top
julie.scrollIntoView(false) // align bottom

Note that the underlying terminology is not ‘top’ or ‘bottom‘, I’ll get into that in the next section.

For most use cases, this boolean argument may be all you need. It lets you choose if you want the element to align top or bottom.

This isn’t always ideal, sometimes you may have a sticky header, so scrollling an element to the top of the document would not actually get it into view. If something like that is the case in your project, the object argument comes in handy. It gives more control over alignment and allows for smooth scroll.

The object argument

In the latest version, you can also pass Element.scrollIntoView() an object, which lets you set two things:

  • should it scroll smoothly or jump instantly?
  • how should the element align along the block and inline axes?
julie.scrollIntoView({
  behavior: "smooth" | "auto";
  block: "start" | "center" | "end" | "nearest";
  inline: "start" | "center" | "end" | "nearest";
});

Smooth scroll

With the behavior parameter, you can set whether scrolling should be instant, so the page just jumps to the element, or smoothly, over a number of seconds (to be decided by the browser).

Unsurprisingly, the "smooth" value triggers smooth scroll. The "auto" value triggers instant scroll, as long as the element’s computed value for the scroll-behavior in CSS is not "smooth".

Alignment

Where I’ve been saying ‘top’ and ‘bottom’, I should have said ‘start‘ or ‘end’. They are the logical properties that you might recognise from other recent CSS specs like Grid Layout and flexbox.

As a quick reminder, the inline direction is the direction in which your text runs: it is the direction in which the words of this article are added. The block direction is the opposite of that, it is where block level elements are stacked, or where paragraphs of this text are added.

In a page with a vertical scrollbar, on the block axis, start means top, end means bottom. That’s the case on this page, for instance. But if your page uses vertical writing mode, you’d scroll horizontally, like in Hui-Jing Chen’s example of Chinese typography; in those cases, start means right, end means left on the block axis.

Fallbacks can be tricky

All browsers that understand element.scrollIntoView() accept the boolean argument. But only some accept the object argument. The good thing is, browsers will fallback for you. The default for the boolean argument is true, which sets the equivalent to block: start. If you use the object argument to use block: center or block: end, browsers that don’t do the object argument, will regard the argument to be true (because objects are truthy). So you’ll end up with block: start in those browsers. That’s often great, except when it is the opposite of what you’re fallbacking for.

If your interface requires precisely control over scroll alignment, fallbacks can be tricky. As an alternative you can also roll your own alignment with element.scrollTo(), as Jan Hoogeveen pointed out (thanks Jan!). If you end up going for that, I would recommend using coordinates as an argument, as the object argument does not work in some recent browsers, including Edge. See also window.scrollTo on MDN.

In the works: scroll snap

If you find scrollIntoView interesting, you may be interested in Scroll Snap, too. This is new CSS, currently being worked on, which lets you define things like a padding for the scroll container. Rachel Andrew has written a guide on the basic concepts of Scroll Snap on MDN. Some of the properties are already available in some browsers.

Comments, likes & shares (3)