There is new html5 API that can be used to trigger a callback when element change visibility. That api is called IntersectionObserver it’s supported by Chrome, Edge and Opera, its similar to MutationObserver.
The code look like this:
var element = document.querySelector('selector'); if (window.IntersectionObserver) { var observer = new IntersectionObserver(function(entries) { if (entries[0].intersectionRatio) { console.log('visible'); } else { console.log('hidden'); } }, { root: document.body }); observer.observe(element); }
NOTE: intersectionRatio will not work if the element have position: fixed
so if you can use jQuery you can check $(element).is(':visible');
.
If you don’t use jQuery you can take :visible code from jQuery which look like this:
elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length;
To remove the observer you need to call:
observer.unobserve(element);
The element will intersect with body only when it’s visible, and the observer is fired when intersection is changed, so it will fire when element will become visible or not visible. You can read about IntersectionObserver on MDN.
If you’re are using jQuery you can wrap this using special event:
if (window.IntersectionObserver) { $.event.special.visibility = { setup: function() { function event(visibility) { var e = $.Event("visibility"); e.visible = visibility; return e; } var element = this; var $element = $(this); var observer = new IntersectionObserver(function(entries) { var e = event($element.is(':visible')); ($.event.dispatch || $.event.handle).call(element, e); }, { root: document.body }); observer.observe(this); $.data(this, 'observer', observer); }, teardown: function() { var observer = $.data(this, 'observer'); if (observer) { observer.unobserve(this); $.removeData(this, 'observer'); } } }; }
and call it like this:
$('div').on('visibility', function(e) { $('pre').html(e.visible ? 'visible' : 'hidden'); });
Here is Codepen DEMO.
The event will fire when intersection observer is added, if you don’t want that you may want to disable first check.
var first_time = true; var observer = new IntersectionObserver(function(entries) { if (!first_time) { var e = event(!!entries[0].intersectionRatio); ($.event.dispatch || $.event.handle).call(element, e); } first_time = false; }, { root: document.body });