how can i make javasript keep a div in the viewport without overflowing?
ex:
User resizes the screen (lets say go to landscape mode without refresh) and now the div is getting cut off due to the viewport getting bigger.
The div is like a tooltip. basically popper without the extra features.
I have tried setting a timeout every 500 ms, to attach the div to the side of the page (which doesnt work at its like a dropdown, needs to be under the button)
ive been using this function to get the out of viewport
var isOutOfViewport = function (elem) {
// Get element's bounding
var bounding = elem.getBoundingClientRect();
// Check if it's out of the viewport on each side
var out = {};
out.top = bounding.top < 0;
out.left = bounding.left < 0;
out.bottom = bounding.bottom > (window.innerHeight || document.documentElement.clientHeight);
out.right = bounding.right > (window.innerWidth || document.documentElement.clientWidth);
out.any = out.top || out.left || out.bottom || out.right;
return out;
};var logViewport = function () {
var isOut = isOutOfViewport(document.querySelector('#in-viewport'));
if (isOut.any) {
console.log('Not in the viewport! =(');
} else {
console.log('In the viewport! =)');
}
};
window.addEventListener('scroll', logViewport, false);
window.addEventListener('resize', logViewport, false);
My end goal:
Make the div always on screen, without overflowing (like popper js)
I'm having trouble with some Javascript I used for a site.
The aim was to have a header elements css changes based on the appearance on screen of a specific div.
Actually it works just perfectly on desktop ! But not on Iphones...
I can't figure out what's wrong with it...
Can you help me understand this ?
Thanks alotlotlot !
var isInViewport = function (elem) {
var bounding = elem.getBoundingClientRect();
return (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
var section_clouds = document.querySelector('#section_intro_clouds');
window.addEventListener('transitionend', function (event) {
if (isInViewport(section_clouds)) {
document.getElementById('header_blanc').classList.add('colorer_bleu');}
else {document.getElementById('header_blanc').classList.remove('colorer_bleu');}
}, false);
I'm creating a parallax effect and I've made it so that (almost) every element has a different scroll speed.
I've also made it so that elements down the page don't trigger their scroll speed until they've reached the viewport.
Here's the JS for trigger commands on reveal:
function isElementInViewport (el) {
if (typeof jQuery === "function" && el instanceof jQuery) {
el = el[0];
}
var rect = el.getBoundingClientRect();
return (
rect.bottom >= 0 &&
rect.left >= 0 &&
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
My scroll speed code is:
$(window).scroll(function(){
var wScroll = $(this).scrollTop();
if (isElementInViewport($('#computer'))) {
$('#computer').css({
transform' : 'translate(0px, '+ wScroll /12 +'%)'
});
}
OR for elements already at the top of page:
$(window).scroll(function(){
var wScroll = $(this).scrollTop();
$('#shape-2').css({
'transform' : 'translate(0px, -'+ wScroll /8 +'%)'
});
The issue here is that when I add function isElementInViewport to the scroll speed.
It makes the element jump out of view when revealed, THEN it scrolls how I want it.
So, then it's out of place with the layout of the page.
I've tried compensating it by changing the position of the element so that when it's revealed it jumps to its original spot then starts scrolling, but this didn't prove helpful since the position varied from different screen sizes and resolutions.
Any way I can make it so it doesn't jump when revealed?
Make sure your base CSS declares a translation transform of zero, or add it from script before the element is in view; adding the attribute later may be causing the jump.
I'm using this lazy loading code.
JS CODE:
$(window).on('scroll touchmove', function(){
if( $('.touch').length) {
var images = $('.theme-slider img[data-lazy]');
images.each(function(index){
if(isElementVisible(this)) {
$(this).attr('src', $(this).attr('data-lazy'));
$(this).removeAttr('data-lazy');
}
})
if(images.length == 0) {
$(window).off('scroll touchmove');
}
}
});
// Checking if an image is within the viewport
function isElementVisible(el){
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight) &&
rect.right <= (window.innerWidth)
);
}
My problem is on iPhone when I'm scrolling horizontal if the image has entered the viewport it doesn't load, I have to scroll back and forward until it works.
Any ideas how I can solve it?
I have a very big draggable div in my window. This div has a smaller window.
<div id="draggable-area" style="width:500px;height:500px;overflow:hidden">
<div id="draggable" style="width:5000px;height:5000px">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
....
</ul>
</div>
</div>
How can I know if the li element is visible in the user viewport (I mean really visible, not in the overflow area)?
To check if an element is in the current veiwport:
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top >= window.pageYOffset &&
left >= window.pageXOffset &&
(top + height) <= (window.pageYOffset + window.innerHeight) &&
(left + width) <= (window.pageXOffset + window.innerWidth)
);
}
(Source)
For a more robust method, I'd recommend Viewport Selectors, which allow you to just do:
$("#elem:in-viewport")
have a look at this plugin
It give's you the option to do the following selectors
$(":in-viewport")
$(":below-the-fold")
$(":above-the-top")
$(":left-of-screen")
$(":right-of-screen")
https://github.com/sakabako/scrollMonitor
var scrollMonitor = require("./scrollMonitor"); // if you're not using require, you can use the scrollMonitor global.
var myElement = document.getElementById("itemToWatch");
var elementWatcher = scrollMonitor.create( myElement );
elementWatcher.enterViewport(function() {
console.log( 'I have entered the viewport' );
});
elementWatcher.exitViewport(function() {
console.log( 'I have left the viewport' );
});
elementWatcher.isInViewport - true if any part of the element is visible, false if not.
elementWatcher.isFullyInViewport - true if the entire element is visible [1].
elementWatcher.isAboveViewport - true if any part of the element is above the viewport.
elementWatcher.isBelowViewport - true if any part of the element is below the viewport.
For a more up-to-date way using getBoundingClientRect():
var isInViewport = function (elem) {
var bounding = elem.getBoundingClientRect();
return (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
Returns true if the element in completely in the viewport, and false if it’s not.
var myElem = document.querySelector('#draggable');
if (isInViewport(myElem)) {
// Do something...
}
Complete explanation found here.
My solution is using the given code example, and it will show you an overall idea of how to determine whether the li element is visible. Check out the jsFiddle which contains code from your question.
The jQuery .offset() method allows us to retrieve the current position of an element relative to the document. If you click on an li element inside the draggable, your offset from the top will be between 0 and 500 and the offset from the left should be between 0 and 500. If you call the offset function of an item that is not currently visible, the offset will either be less than 0 or greater than 500 from either the top or left offset.
If its not a daunting task I always like to code what I need from 'scrath' it gives me more flexibility when having to modify or debug, hence why I would recommend looking into using jQuery's offset function instead of using a plugin. If what you are trying to accomplish is fairly simple, using your own function will give you one less library to load.
I m using (checks whether an element is at least partially in the view) following code:
var winSize;
function getWindowSize() {
var winW,WinH = 0;
if (document.body && document.body.offsetWidth) {
winW = document.body.offsetWidth;
winH = document.body.offsetHeight;
}
if (document.compatMode == 'CSS1Compat' &&
document.documentElement &&
document.documentElement.offsetWidth) {
winW = document.documentElement.offsetWidth;
winH = document.documentElement.offsetHeight;
}
if (window.innerWidth && window.innerHeight) {
winW = window.innerWidth;
winH = window.innerHeight;
}
return {w:winW, h:winH};
}
winSize = getWindowSize();
function inView(element) {
var box = element.getBoundingClientRect();
if ((box.bottom < 0) || (box.top > winSize.h)){
return false;
}
return true;
}