1

I need to scroll into div inside other div.

I'm using scrollIntoView, the problem is that even if div is fully visible scrollIntoView still scrolls into element so element is align to the top of parent div.

This is causing "jumping" effect each time I focus, even if element is fully visible. See below example: pressing C should not scroll at all only pressing G ;) should.

https://codepen.io/kheim/pen/gWmwKj

I was wondering if there is a way to scroll into element only if it's not fully visible.

Trying this on Chrome 55+.

Thanks!

Chanda Korat
  • 2,453
  • 2
  • 19
  • 23
pankleks
  • 693
  • 6
  • 14

4 Answers4

1

This solution is based on the visibility calculation. You will calculate if the border-box of the element is inside of the viewport or not. If is not then scroll to the element.

function setFocus(id) {
    var el = document.getElementById(id);
    if(!isVisible(el)) {
        el.scrollIntoView();
    }    
}

function isVisible(element) {
    var borderBox  = element.getBoundingClientRect();
    var viewWidth = window.innerWidth || doc.documentElement.clientWidth;
    var viewHeight = window.innerHeight || doc.documentElement.clientHeight;
    var efp = function (x, y) { return document.elementFromPoint(x, y) };     

    // Returns false if it is not in the viewport
    if (borderBox.left > viewWidth || borderBox.top > viewHeight ||
      borderBox.right < 0 || borderBox.bottom < 0)
        return false;

    // Returns true if any of its four corners are visible
    return (
          element.contains(efp(borderBox.left,  borderBox.top))
      ||  element.contains(efp(borderBox.right, borderBox.top))
      ||  element.contains(efp(borderBox.right, borderBox.bottom))
      ||  element.contains(efp(borderBox.left,  borderBox.bottom))
    );
}
.container {
  height: 4cm;
  overflow: auto;
}

.item {
  height: 1cm;
  border: 1px solid #000;
}
<div class="container">
  <div class="item">A</div>
  <div class="item">B</div>
  <div class="item" id="c">C</div>
  <div class="item">D</div>
  <div class="item">E</div>
  <div class="item">F</div>
  <div class="item" id="g">G</div>
</div>
<button type="button" onclick="setFocus('c');">focus on C</button>
<button type="button" onclick="setFocus('g');">focus on G</button>
Teocci
  • 7,189
  • 1
  • 50
  • 48
  • Thanks, I just thought there might be css selector doing that, but apparently not. – pankleks Apr 28 '17 at 10:17
  • Mhm nop you need to create a custom function to handle the detection. The `scrollIntoView` also can receive a boolean to alaign top (`true`) or bottom (`false`) – Teocci Apr 28 '17 at 10:21
0

Try following example......to scroll into div... just provide your DIV id or class...

HTML Code:

<div id="myDIV" onscroll="myFunction()">
  <div id="content">Scroll inside me!</div>
</div>
<p id="demo"></p>

JS Code:

<script>
function myFunction() {
    var elmnt = document.getElementById("myDIV");
    var x = elmnt.scrollLeft;
    var y = elmnt.scrollTop;
}
</script>
1990rk4
  • 728
  • 11
  • 21
0

You could check first if the element is in view within the parent and simply return if it is. Check out this answer for some ideas on how to check if something is in view: https://stackoverflow.com/a/15203639/5172918

Then do something like this:

function setFocus(id) {
    var el = document.getElementById(id);

    if(isElementVisible(el) === true) {
        return;
    }

    el.scrollIntoView();
}

Note: The only problem here is that if G is only even 1px in view then it will not scroll to it. The better solution is to do a check and see if it is "fully" in view... that is for you to figure out ;)

Community
  • 1
  • 1
Bruffstar
  • 1,249
  • 1
  • 10
  • 18
0

You can compare top&bottom of current page with the element like this :

var el = document.getElementById(id);

var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();

var elemTop = el.offsetTop;
var elemBottom = elemTop + el.offsetHeight;

if ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)){
   return false;       
}
else{
   el.scrollIntoView();
} 
Emad Dehnavi
  • 3,262
  • 4
  • 19
  • 44