---
url: 'https://simonerescio.it/en/2017/03/chrome-changes-its-center-of-gravity-reference-is-not-the-document-but-the-viewport'
title: 'Chrome changes its center of gravity, reference is not the document but the viewport'
author:
  name: Simone Rescio
  url: 'https://simonerescio.it/en/about-me/'
date: '2017-03-01T00:13:58+01:00'
modified: '2026-04-25T00:54:43+02:00'
type: post
summary: 'Since Chrome 56, the browser natively handles above-the-fold content changes by adjusting the scroll position on its own. Learn how to detect this behaviour and adapt your JavaScript accordingly.'
categories:
  - JavaScript
tags:
  - Chrome
  - cross browser
  - javascript
  - user experience
  - viewport
image: 'https://simonerescio.it/wp-content/uploads/2017/02/chrome-above-the-fold-scroll-fix.png'
published: true
---

# Chrome changes its center of gravity, reference is not the document but the viewport

[![Cartesian system](https://simonerescio.it/wp-content/uploads/2017/02/xy-150x150.png)](https://simonerescio.it/en/2017/03/chrome-changes-its-center-of-gravity-reference-is-not-the-document-but-the-viewport/xy-2)Each system needs coordinate and reference rules; when speaking of two dimensional systems we have for the Cartesian one a source point starting from which the elements grow positively to the right and upward, if you remove height units you move down.

![Tetris: row cleared causing blocks above to shift down](https://simonerescio.it/wp-content/uploads/2017/02/tetris_scoring.gif)Take for example the famous puzzle game [Tetris](https://en.wikipedia.org/wiki/Tetris), as the blocks pile up, when a row is completed and totals a score, that row being removed will cause a shift of the above elements downward, let’s say that its *gravity system* is facing downward, is that the case as well in a web page in your browser?

- [1. Gravity in the browser is facing upward](#gravity-in-the-browser-is-facing-upward)
- [2. Adjusting the scroll position with page’s height delta](#adjusting-the-scroll-position-with-page8217s-heightdelta)
- [3. Chrome natively manages changes over the viewport](#chrome-natively-manages-changes-over-the-viewport)

## Gravity in the browser is facing upward

![Animation: upward shift of page elements when content is removed](https://simonerescio.it/wp-content/uploads/2017/02/standard-move-up.gif)The origin-point of reference in the browser is the top-left corner from which the page starts growing down, it follows that if you scroll a big *document*, or better known by the more contemporary term *webapp,* such as a social timeline on *Facebook* or *Twitter*, anything that is removed or added on top of the currently “*framed*” content will cause a sudden change of the on-screen displayed content because everything shifts accordingly.

It is not the best from the UX point of view, and indeed becomes particularly annoying on mobile.

## Adjusting the scroll position with page’s height delta

If the elements that are modified above visible area of the *viewport* are not subject to animations or transitions on their height, it is possible to “compensate” for this displacement by calculating the visual difference with the size change that occurred in the overall page’s height and applying the difference to the scroll position:

```
function isInViewportOrAbove($element, className) {
    var domNode = $element.get(0),
        nodeCoordinates;

    // Node must be rendered on page to get its coordinates
    if (!$element.is(":visible")) {
        $element.removeClass(className);
        nodeCoordinates = domNode.getBoundingClientRect();
        $element.addClass(className);
    } else {
        nodeCoordinates = domNode.getBoundingClientRect();
    }

    return nodeCoordinates.top < $(window).height();
}

function compensateScrollDifference(previousDocumentHeight) {
    var currentDocumentHeight  = $(document).height(),
        documentHeightDelta    = previousDocumentHeight - currentDocumentHeight,
        currentScrollPosition  = $(document).scrollTop(),
        newScrollPosition      = currentScrollPosition - documentHeightDelta;

    $('html, body').scrollTop(newScrollPosition);
}

function toggleVisibilityWithScrollAdjustment($element, className) {
    var previousDocumentHeight = $(document).height();

    $element.toggleClass(className);

    if (isInViewportOrAbove($element, className)) {
        compensateScrollDifference(previousDocumentHeight);
    }
}
```

## Chrome natively manages changes over the viewport

![Chrome: native scroll correction for changes above the viewport](https://simonerescio.it/wp-content/uploads/2017/02/chrome-scroll-fix.gif)Thanks to having supplemented the above functionality with numerous Jasmine unit tests, I found that this feature started malfunctioning in Chrome on February 8th, in connection with the release of version **56**.

The test asserts that *given* a page 3000px tall with the scroll position set to 1800px, *when* toggling an upper element with height of 100px using the above function *then* the page scroll position would become 1700px, yet on Chrome after the update position started being reported as 1600px, as if applied twice.

By setting a breakpoint in conjunction with the toggle of the class and before calling the function to correct the scroll offset we can observe that while all other browsers after applying the visibility change will keep the scroll position unchanged,

			
				[![Other browsers: scroll position unchanged immediately after class toggle](https://simonerescio.it/wp-content/uploads/2017/02/Schermata-2017-02-26-alle-15.47.40-300x75.png)](https://simonerescio.it/en/schermata-2017-02-26-alle-15-47-40-2)
			
				*
				safari (webkit) before executing the toggle
				*

			
				[![Other browsers: stable scroll position after visibility change](https://simonerescio.it/wp-content/uploads/2017/02/Schermata-2017-02-26-alle-15.48.31-300x75.png)](https://simonerescio.it/en/schermata-2017-02-26-alle-15-48-31-2)
			
				*
				safari (webkit) after the toggle as kept unchanged the $.scrollTop() value
				*

		

Chrome instead immediately after the toggle has already corrected the scroll position by itself, so running our own function would be harmful.

			
				[![Chrome: scroll position already self-corrected after toggle](https://simonerescio.it/wp-content/uploads/2017/02/Schermata-2017-02-26-alle-15.30.05-300x58.png)](https://simonerescio.it/en/schermata-2017-02-26-alle-15-30-05-2)
			
				*
				chrome v56 (blink) before executing the toggle
				*

			
				[![Chrome: automatic above-the-fold scroll compensation](https://simonerescio.it/wp-content/uploads/2017/02/Schermata-2017-02-26-alle-15.30.31-300x58.png)](https://simonerescio.it/en/schermata-2017-02-26-alle-15-30-31-2)
			
				*
				chrome v56 (blink) after the toggle has already updated the $.scrollTop() value
				*

		

So we need to check if the browser has already made changes on the scroll position to compensate for changes that occurred in the page, to decide whether to act or not:

```
function toggleVisibilityWithScrollAdjustment($element, className) {
    var previousDocumentHeight = $(document).height(),
        preToggleScrollPosition = $(document).scrollTop(),
        postToggleScrollPosition,
        isScrollPositionUnchanged;

    $element.toggleClass(className);

    postToggleScrollPosition  = $(document).scrollTop();
    isScrollPositionUnchanged = preToggleScrollPosition === postToggleScrollPosition;

    if (isScrollPositionUnchanged && isInViewportOrAbove($element, className)) {
        compensateScrollDifference(previousDocumentHeight);
    }
}
```

Chrome’s native mechanism is particularly advanced as it works for animated items, just select an image for example in the tag inspector and scroll down to make it disappear high above the viewport, then changing in any way its height will not affect the position of contents in the current viewport.

This is just yet another reminder that *cross-browser* issues are far from extinct in front-end development.

 [](https://mastodon.social/share?text=http%3A%2F%2Fsresc.io%2FtLh&title=Chrome%20changes%20its%20center%20of%20gravity%2C%20reference%20is%20not%20the%20document%20but%20the%20viewport)[](https://www.linkedin.com/sharing/share-offsite/?url=http%3A%2F%2Fsresc.io%2FtLh)[](https://simonerescio.it/en/2017/03/chrome-changes-its-center-of-gravity-reference-is-not-the-document-but-the-viewport)[](https://reddit.com/submit?url=http%3A%2F%2Fsresc.io%2FtLh&title=Chrome%20changes%20its%20center%20of%20gravity%2C%20reference%20is%20not%20the%20document%20but%20the%20viewport)[](https://api.whatsapp.com/send?text=Chrome%20changes%20its%20center%20of%20gravity%2C%20reference%20is%20not%20the%20document%20but%20the%20viewport http%3A%2F%2Fsresc.io%2FtLh)[](https://bsky.app/intent/compose?text=Chrome%20changes%20its%20center%20of%20gravity%2C%20reference%20is%20not%20the%20document%20but%20the%20viewport%20http%3A%2F%2Fsresc.io%2FtLh)[](https://telegram.me/share/url?url=http%3A%2F%2Fsresc.io%2FtLh&text=Chrome%20changes%20its%20center%20of%20gravity%2C%20reference%20is%20not%20the%20document%20but%20the%20viewport)[](https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fsresc.io%2FtLh)

