ScrollIntoView() Is Not Working: Does Not Taking in Account Fixed Element

I'm trying to use scrollIntoView() in my application, but because I have a top fixed bar, when I use the scrollIntoView(), the elements will be scroll to the fixed bar back.

This means that when I try to put some element visible to the user, by scrolling the element to a visible area, it will be scrolled, but to another invisible ate that is were this fixed bar is.

Follows an example of what I'm trying to do:

let element = document.getElementsByClassName('second-element')[0];
element.scrollIntoView();
.fixed-element{
  height: 30px;
  width: 100%;
  background-color:black;
  position:fixed;
}

.parent-element {
   width: 100%;
   height: 40000px;
   background-color:blue;
}

.element {
   width: 100%;
   height:100px;
   background-color: yellow;
   margin-top:10px;
}

.second-element{
   width: 100%;
   background-color: red;
   height:200px;
}
<div class="fixed-element"></div>
<div class='parent-element'>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='second-element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
  <div class='element'></div>
</div>

There is any way that I could use this function in a way that the scroll elements not became invisible because of the fixed bar?

I would like a vanilla JavaScript solution. Also, and only if it is possible, a solution that doesn't need to know the existent of any fixed elements.

5 Answers

You can make the window scrollTo x position 0 and y position the element's offsetTop subtracted by the fixed element's offsetHeight.

JSFiddle with your code:

.header{
  position: fixed;
  background-color: green;
  width: 100%;
  top: 0;
  left: 0;
  right: 0;
}
html, body{
  height: 1000px;
}

#toBeScrolledTo{
  position: relative;
  top: 500px;
}
<div class="header">
Header
</div>
<div id="toBeScrolledTo">
Text Text Text
</div>
<script>
window.scrollTo(0, document.getElementById('toBeScrolledTo').offsetTop - document.getElementsByClassName('header')[0].offsetHeight);
</script>

Your question is answered in this link.

var node = 'select your element';
var yourHeight = 'height of your fixed header';

// scroll to your element
node.scrollIntoView(true);

// now account for fixed header
var scrolledY = window.scrollY;

if(scrolledY){
  window.scroll(0, scrolledY - yourHeight);
}

Also you can use this way:

let item = // what we want to scroll to
let wrapper = // the wrapper we will scroll inside
let count = item.offsetTop - wrapper.scrollTop - xx // xx = any extra distance from top ex. 60
wrapper.scrollBy({top: count, left: 0, behavior: 'smooth'})

Source:

2

Try scroll padding. It is not a JavaScript solution (it is a CSS property) but it can be helpful with your problem.

MDN
CSS Tricks

2

A great simple solution (inspired by Sanyam Jain's comment in this link) is to use {block: 'center'} to vertically center the selection like this:

scrollIntoView({block: 'center'})

Edit - I sadly found on MDN page that this features is 'experimental - should not be used in production'. Also, IE doesn't support it (if that's a need).

This is 2021, so you could solve this by just using scroll-margin-top. It exists for this express purpose!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Elena Rostova

Elena Rostova

Lead Health, Wellness & Medical Journalist

Elena Rostova holds a Master's degree in Public Health Journalism. She covers groundbreaking medical research, holistic wellness trends, mental health awareness, and nutritional science.

Share this article
Twitter Facebook Pinterest