22

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.

Ricardo Rocha
  • 14,612
  • 20
  • 74
  • 130

5 Answers5

14

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: http://jsfiddle.net/3sa2L14k/

.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>
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
8

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: https://github.com/iamdustan/smoothscroll/issues/47

Mamad
  • 165
  • 2
  • 13
4

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

scrollIntoView({block: 'center'})
java-addict301
  • 3,220
  • 2
  • 25
  • 37
1

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
//React
cardRef.current.scrollIntoView(true);

worked for me

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • If you want to add an answer almost five years after the question was originally answered be sure that it adds context or further detail to the accepted answer. Saying that the OP's originally attempted code worked for you only serves to add noise. – Mike Devenney May 17 '23 at 14:38