jcubic
jcubic

Reputation: 66560

How to detect which element body or html need to be scrolled

In Fireofx and IE to get the scrollTop you need to get it from html and in chrome from body element.

Is there a way to detect that without browser sniffing?

var html = document.querySelector('html');
var body = document.querySelector('body');
var input = document.querySelector('input');
window.addEventListener('scroll', function() {
  input.value = html.scrollTop + ' ' + body.scrollTop;
});
body {
  height: 1000px;
}
input {
  position: fixed;
  top: 10px;
}
<input/>

I need to detect which element to scroll because I need to change scrollTop from my code.

Upvotes: 1

Views: 90

Answers (4)

jcubic
jcubic

Reputation: 66560

I came up with this hack, it add pre tag that trigger scrollbar, set scrollTop and check which element have it changed:

var html = $('html');
var body = $('body');
var scrollTop = body.scrollTop() || html.scrollTop();
var pre = $('<pre/>').appendTo('body');
pre.html(new Array(1000).join('\n'));
$('body,html').scrollTop(10);
var scrollObject;
if (body.scrollTop() == 10) {
  console.log('body');
  scrollObject = body;
  body.scrollTop(scrollTop);
} else if ($('html').scrollTop() == 10) {
  console.log('html');
  scrollObject = html;
  html.scrollTop(scrollTop);
}
pre.remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Upvotes: 0

nem035
nem035

Reputation: 35491

Can you just test either for truthiness (assuming 0 means not there)?

function getScrollTop() {
  return html.scrollTop || body.scrollTop || 0;
}

var html = document.querySelector('html');
var body = document.querySelector('body');
var input = document.querySelector('input');
window.addEventListener('scroll', function() {
  input.value = getScrollTop();
});
body {
  height: 1000px;
}
input {
  position: fixed;
  top: 10px;
}
<input/>

As far as updating the scroll top, you can create a setter function that sets the appropriate browser property. The way you build this setter is by manually triggering a scroll when the page loads and determining which property changed.

function setScrollTopUpdater(cb) {
  var html = document.querySelector('html');
  var body = document.querySelector('body');

  // temporary listener to determine which scroll property updated
  // and create an appropriate scroll top setter
  window.addEventListener('scroll', function temp() {
    if (html.scrollTop > 0) {
      // return a function that updates the firefox prop
      cb(function(x) {
        html.scrollTop = x;
      });
    } else {
      // return a function that updates the chrome prop
      cb(function(x) {
        body.scrollTop = x;
      });
    }
    window.removeEventListener('scroll', temp);
  });

  // trigger scroll by 1 pixel
  window.scrollTo(window.scrollX, window.scrollY + 1);
}

var updateScrollTop = null;
setScrollTopUpdater(function(updater) {
  updateScrollTop = updater;
});

setTimeout(() => {
  window.addEventListener('scroll', function demo() {
    document.querySelector('input').value = window.scrollY;
  });
  updateScrollTop(200);
}, 2000)
body {
  height: 1000px;
  background: #018bbc;
}
input {
  position: fixed;
  top: 10px;
}
<input placeholder="Will set scrollTop to 200"/>

Upvotes: 1

Maher Fattouh
Maher Fattouh

Reputation: 1860

you can simply check for both values of html.scrollTop and body.scrollTop:

  • if they're both 0 than the scrolltop is 0

using !html.scrollTop will return true if it's value is equals to zero or undefined

  • else if html.scrollTop is bigger than 0 (exist) than scrolltop is html.scrollTop
  • else if body.scrollTop is bigger than 0 (chrome) than scrolltop is body.scrollTop

in this example I'm storing scrolltop value in a var called myScrollTop

var myScrollTop

if (!html.scrollTop && !body.scrollTop) {
    myScrollTop = 0
} else if (html.scrollTop) {
    myScrollTop = html.scrollTop
} else if (body.scrollTop) {
    myScrollTop = body.scrollTop
}

you can also wrap the code in a function and return the value to the caller

function myScrollTop() {
    if (!html.scrollTop && !body.scrollTop) {
        return 0
    } else if (html.scrollTop) {
        return html.scrollTop
    } else if (body.scrollTop) {
        return body.scrollTop
    }
}

or the shorter version

function myScrollTop() {
    return html.scrollTop || body.scrollTop || 0
}

now you can get the value of scroll top by calling myScrollTop()

console.log(myScrollTop())

Upvotes: 0

Squiggs.
Squiggs.

Reputation: 4474

If life was simple, you could use this event handler property. But I.E throws a spanner in the works with no browser support for it. You could of course always write some code to step around IE if this isn't available.

if (!('scrollingElement' in document)) (function() {
   alert('IE is a pain in the arse');
}


window.addEventListener('scroll', function(event) {
   alert(event.scrollingElement);
});

Upvotes: 1

Related Questions