Check block visibility - javascript

We have code like:
<body>
<div class="blocks">some text here</div>
<div class="end"></div>
</body>
Text can fit in current browser visible part or not.
How to detect, does the block is in visible part of browser window?
I mean, if resoution is 1024x768 and .block height bigger than 768, then .end is invisible.
we should detect this on window.ready and also on browser window change.
if block is visible, then run some function.
Any help is appreciated.

Something like this:
$.fn.viewport = (function() {
var vp = function(el, opts){
this.el = $(el);
this.opts = opts;
this.bind(); // bind resize and scroll
this.change(); // init change
};
vp.prototype = {
bind: function(){
$(window).bind('resize scroll',
$.proxy(this.change, this));
},
change: function(e){
var p = this.el.position(),
o = this.el.offset(),
d = { w: this.el.width() +o.left, h: this.el.height()+o.top },
win = $(window),
winD = {w:win.width() + win.scrollLeft(), h:win.height()+win.scrollTop()};
if(d.w <= winD.w && d.h <= winD.h){
console.log('inview');
} else {
console.log('out of view');
this.opts.outOfView.call(this);
}
}
};
return function(opts){
return $(this).each(function(){
$(this).data('vp', new vp(this, opts));
});
};
})();
And use like this:
$('#el').viewport({
outOfView: function(){
alert('out of view');
}
});

First grab the window dimensions.
var windowSize = {width: $(window).width(), height: $(window).height() + $(window).scrollTop()};
Next grab the div position in relation to the document:
var position = $('.block').offset()
Then make your if's:
if(position.top > windowSize.height){ /* here we go */ }
You might want to also grab div dimensions in case there is a possibility it will be out of bounds on the top or left side.
You could make it into a function that returns a boolean value and then call it on the window.resize and document.ready events.
EDIT: Added scrollTop to account for scrolling.

As a quick answer you'll have to do some computation on load (psuedocode assumes jQuery).
Find the window height $(window).outerHeight(true)
Find the offset of the ".end" element $(".end").offset()
Find the scroll distance of the window $(window).scrollTop()
Calculate! It should roughly be:
if ((step1 + step3) > step2) {
//do stuff here
}
Note that that does not check if you are scrolled past the ".end" element. I didn't verify this one, so hopefully I'm not missing something big.

Get the offsetTop and offsetLeft attributes of the element
Get the width of the element in question
Get the width of screen
Do the relevant maths and see if the element is in the viewport or now.
in jQuery you can do something like
$("#element").attr("offsetTop")
EDIT:
Simple and Effective: http://jsfiddle.net/hPjbh/

Related

How to incorporate JS media Queries and Scroll listening?

I'm currently making an element visible when my nav is at the top of the page. I'd like the element to be hidden if the page gets to max-width: 900px;. I've tried using modernizer for JS media queries but I ca't seem to get it to work.
Code:
var a = $(".menu").offset().top;
function scrollListener(){
if($(document).scrollTop() > a)
{$('.hidden-logo').css({"opacity": "1","display": "block"});
$('.menu').css({"margin-left": "-130px"})
} else {
$('.hidden-logo').css({"opacity": "0","display": "none"});
$('.menu').css({"margin-left": "0px"})
}
};
$(document).scroll(scrollListener);
You were checking the scroll position the wrong way - I think you want the logo to disappear when the current scroll is greater than the top of the logo, not less.
I added a msgS div (for demo purposes only) that will show you the current scroll value against the top-of-menu static value. I also added a 100px fudge factor to the menu location to make it more clear in the demo when the current scroll reaches that position. I use these temporary msg divs myself when working out my code, and then remove them when I've got it all sorted and ready for production.
And this is all you need to check the media query in javascript:
var winmed = window.matchMedia("(max-width: 700px)");
if (winmed.matches){ //do something }
And that can go into a listener function exactly like your scroll listener.
var gloShowLogo = true;
var a = $(".menu").offset().top;
var fudge = 100; //100px fudge factor so can SEE div disappear
function scrollListener(){
updateScrollMsg();
var currScroll = $(document).scrollTop();
var topOfMenu = a+fudge;
if( gloShowLogo && currScroll < topOfMenu ){
$('.hidden-logo').css({"opacity": "1","display": "block"});
$('.menu').css({"margin-left": "-130px"})
} else {
$('.hidden-logo').css({"opacity": "0","display": "none"});
$('.menu').css({"margin-left": "0px"})
}
};
function resizeListener(){
updateMediaMsg();
var winmed = window.matchMedia("(max-width: 500px)");
if (winmed.matches){
$('.hidden-logo').css({"opacity": "1","display": "block"});
gloShowLogo = true;
} else {
$('.hidden-logo').css({"opacity": "0","display": "none"});
gloShowLogo = false;
}
}
$(window).scroll(scrollListener);
$(window).resize(resizeListener);
function updateScrollMsg(){
$('#msgS').html( $(document).scrollTop() +' // ' + $(".menu").offset().top );
}
function updateMediaMsg(){
var winmed = window.matchMedia("(max-width: 500px)");
var medmsg = (winmed.matches) ? '< 500' : '> 500';
console.log(medmsg);
$('#msgM').html(medmsg);
}
.menu{background:green;text-align:center;}
.content{height:200vh;background:palegreen;text-align:center;}
.hidden-logo{position:fixed;top:1vh;right:1vw;padding:15px; background:pink;z-index:2;}
#msgS{position:fixed;top:0;left:0;padding:10px;background:wheat;z-index:2;}
#msgM{position:fixed;top:40px;left:0;padding:10px;background:lightblue;z-index:2;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div class="menu">Menu Div</div>
<div class="content">Lengthy content Div..<br><br><br><br>100<br></div>
<div class="hidden-logo">LOGO</div>
<div id="msgS"></div>
<div id="msgM"></div>
Update:
Sorry, I had the media query a bit backwards myself - I think you want the logo to display when the screen-size is < 900px and to be hidden if wider than 900px, yes?
I added a msgM div so you can watch the media query kick-in -- but getting the best width for the demo was a bit of a challenge. I finally settled at 500px as a width that can be demoed (StackOverflow resizes its StackSnippets container as the browser window resizes, which throws things into confusion at each of their resize breakpoints)

add element offset to jQuery offset calculations

I am rather new to jquery and i'm trying to find the right offset for a div element inside the body. I want to make this div element sticky whenever I scroll down and pass the top offset of this element.
I followed this tutorial: https://www.youtube.com/watch?v=utonytGKodc and it works but I have a metaslider in my header and the width/height of this element is left out of the calculations to find the right offset....
the result is that my element becomes a sticky element way to soon, is there a way I can manualy add the sliders coordinates (offset) to the offset calculation of the element i want to make sticky?
var offerteOffset = jQuery(".agendawrap").offset().top //+ metaslider coordinates??;
alert(offerteOffset);
jQuery(window).scroll(function() {
var scrollPos = jQuery(window).scrollTop();
if (scrollPos >= offerteOffset) {
jQuery(".agendawrap").addClass("fixed");
} else {
jQuery(".agendawrap").removeClass("fixed");
}
});
I cant believe people make such bad tutorials.
First of all: dont write jQuery all the time. Have a look at this thread.
Basically it says: use an invoking function with an own scope:
(function($) { /* all your jQuery goes here */ })(jQuery);
So you can just type $ instead of jQuery.
To your original question:
(function($) {
$(function() { // document ready...
var scrollTolerance = 50,
agendawrap = $(".agendawrap"),
offerteOffset = agendawrap.offset().top;
$(window).on('scroll', function() {
var scrollPos = $(window).scrollTop();
// OR: if (scrollPos - scrollTolerance >= offerteOffset) {
if (scrollPos + scrollTolerance >= offerteOffset) {
agendawrap.addClass("fixed");
}
else {
agendawrap.removeClass("fixed");
}
});
});
})(jQuery);

Do not execute jQuery script if CSS is of particular value

On my website, I have a sidebar DIV on the left and a text DIV on the right. I wanted to make the sidebar follow the reader as he or she scrolls down so I DuckDuckGo'ed a bit and found this then modified it slightly to my needs:
<script type='text/javascript'>//<![CDATA[
$(window).load(function(){
$(function(){
var $sidebar = $('#sidebar'),
sidebarOffset = $sidebar.offset(),
$window = $(window),
gap = $('#header').css('marginBottom').replace(/[^-\d\.]/g, ''),
distance = ($window.scrollTop()) - (sidebarOffset.top - gap),
footerHeight = $('#footer').outerHeight();
$window.scroll(function(){
distance = ($window.scrollTop()) - (sidebarOffset.top - gap);
if ( distance > 0 ) {
$sidebar.css({'top': gap + 'px', 'position' : 'fixed'});
} else {
$sidebar.css({'top': '0', 'position': 'relative'});
}
})
});
});//]]>
</script>
And it works just like I want it to. However, my website uses Skeleton framework to handle responsive design. I've designed it so that when it goes down to mobile devices (horizontal then vertical), sidebar moves from being to the left of the text to being above it so that text DIV can take 100% width. As you can probably imagine, this script causes the sidebar to cover parts of text as you scroll down.
I am completely new to jQuery and I am doing my best through trial-and-error but I've given up. What I need help with is to make this script not execute if a certain DIV has a certain CSS value (i.e. #header-logo is display: none).
Ideally, the script should check for this when user resizes the browser, not on website load, in case user resizes the browser window from normal size to mobile size.
I imagine it should be enough to wrap it in some IF-ELSE statement but I am starting to pull the hair out of my head by now. And since I don't have too much hair anyway, I need help!
Thanks a lot in advance!
This function will execute on window resize and will check if #header-logo is visible.
$(window).resize(function() {
if ($('#header-logo').is(':visible')) {
// Your code
}
});
I think you need to check this on load to, because you don't know if the user will start with mobile view or not. You could do something like this:
$(window).resize(function() {
if ($('#header-logo').is(':visible')) {
// Your code
}
}).resize();
This will get executed on load and on resize.
EDIT: You will probably need to turn off the scroll function if #header-logo is not visible. So, instead of create the function inside the scroll event, you need to create it outside:
$(window).resize(function() {
if ($('#header-logo').is(':visible')) {
var $sidebar = $('#sidebar'),
sidebarOffset = $sidebar.offset(),
$window = $(window),
gap = $('#header').css('marginBottom').replace(/[^-\d\.]/g, ''),
distance = ($window.scrollTop()) - (sidebarOffset.top - gap),
footerHeight = $('#footer').outerHeight();
function myScroll() {
distance = ($window.scrollTop()) - (sidebarOffset.top - gap);
if ( distance > 0 ) {
$sidebar.css({'top': gap + 'px', 'position' : 'fixed'});
} else {
$sidebar.css({'top': '0', 'position': 'relative'});
}
}
$window.on('scroll', myScroll);
} else {
$(window).off('scroll', myScroll);
}
});
Didn't test it, but you get the idea.
$("#headerLogo").css("display") will get you the value.
http://api.jquery.com/css/
I also see you only want this to happen on resize, so wrap it in jquery's resize() function:
https://api.jquery.com/resize/

Getting Coordinates of an element on page scroll

I am having this problem where i have a set of 6 UL's having a common class x.Each of them consist of a specific section of the page.Now i have 6 menus that are related to each of the section.What i have to do is highlight the menu when its related section is in users view.
For this i thought that may be jQuery position(); or offset(); could have helped but they give the top and left of the element.I also tried using jQuery viewport plugin but apparently view port is big it can show more than one UL at a time hence i cant apply element specific logic here.I am not familliar to this but does anything changes of an element on scrolling?If yes then how to access it?
Please share your views.
Regards
Himanshu Sharma.
Is very easy to do it using jQuery and a dummy fixed HTML block that helps you find the current position of the viewport.
$(window).on("scroll load",function(){
var once = true;
$(".title").each(function(ele, index){
if($(this).offset().top > $("#viewport_helper").offset().top && once){
var index = $(this).index(".title");
$(".current").removeClass('current')
$("#menu li").eq(index).addClass('current')
once = false;
}
});
})
Check out a working example: http://jsfiddle.net/6c8Az/1/
You could also do something similar with the jQuery plugin, together with the :first selector:
$(window).on("scroll load",function(){
$(".title:in-viewport:first").each(function(){
var index = $(this).index(".title");
$(".current").removeClass('current')
$("#menu li").eq(index).addClass('current')
});
})
You can get the viewport's width and height via $(document).width() and $(document).height()
You can get how many pixels user scrolls via $(document).scrollTop() and $(document).scrollLeft
Combining 1 and 2, you can calculate where the viewport rectangle is
You can get the rectangle of an element using $(element).offset(), $(element).width() and $(element).height()
So the only thing left to you is to determine whether the viewport's rectangle contains (or interacts) the elements's rectangle
So the whole code may look like:
/**
* Check wether outer contains inner
* You can change this logic to matches what you need
*/
function rectContains(outer, inner) {
return outer.top <= inner.top &&
outer.bottom >= inner.bottom &&
outer.left <= inner.left &&
outer.right >= inner.right;
}
/**
* Use this function to find the menu related to <ul> element
*/
function findRelatedMenu(element) {
return $('#menu-' + element.attr('id'));
}
function whenScroll() {
var doc = $(document);
var elem = $(element);
var viewportRect = {
top: doc.scrollTop(),
left: doc.scrollLeft(),
width: doc.width(),
height: doc.height()
};
viewportRect.bottom = viewportRect.top + viewportRect.height;
viewportRect.right = viewportRect.left + viewportRect.width;
var elements = $('ul.your-class');
for (var i = 0; i < elements.length; i++) {
var elem = $(elements[i]);
var elementRect = {
top: elem.offset().top,
left: elem.offset().left,
width: elem.width(),
height: elem.height()
};
elementRect.bottom = elementRect.top + elementRect.height;
elementRect.right = elementRect.left + elementRect.width;
if (rectContains(viewportRect, elementRect)) {
findRelatedMenu(elem).addClass('highlight');
}
}
}
$(window).on('scroll', whenScroll);
Let's see if i understood well. You have a page long enough to scroll, and there is an element that when it appears in the viewport, you wanna do something with it. So the only event that's is triggered for sure on the time the element gets in the viewport is the 'scroll'. So if the element is on the page and the scroll is on the viewport, what you need to do is bind an action to the scroll event to check if the element is in the view each time the event is trigger. Pretty much like this:
$(window).scroll(function() {
check_element_position();
});
Now, in order for you to know if the element is in the viewport, you need 3 things. The offset top of that element, the size of the viewport and the scroll top of the window. Should pretty much look like this:
function check_element_position() {
var win = $(window);
var window_height = win.height();
var element = $(your_element);
var elem_offset_top = element.offset().top;
var elem_height = element.height();
var win_scroll = win.scrollTop();
var pseudo_offset = (elem_offset_top - win_scroll);
if (pseudo_offset < window_height && pseudo_offset >= 0) {
// element in view
}
else {
// elem not in view
}
}
Here, (elem_offset_top - win_scroll) represent the element position if there was no scroll. Like this, you just have to check if the element offset top is higher then the window viewport to see if it's in view or not.
Finally, you could be more precise on you calculations by adding the element height (variable already in there) because the code i just did will fire the event even if the element is visible by only 1 pixels.
Note: I just did that in five minutes so you might have to fix some of this, but this gives you a pretty darn good idea of what's going on ;)
Feel free to comment and ask questions

infinite-scroll jquery plugin

I am trying to set up infinite-scroll on a site I am developing with Coldfusion, I am new to javascript and jquery so I am having some issues wrapping my head around all of this. Do I need to have pagination on my site in order to use the infinite-scroll plugin, or is there a way to do it with out it?
You do not need infinite scroll plug-in for this. To detect when scroll reaches end of page, with jQuery you can do
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 10) {
//Add something at the end of the page
}
});
Demo on JsFiddle
I'm using Hussein's answer with AJAX requests. I modified the code to trigger at 300px instead of 10px, but it started causing my appends to multiply before the AJAX request was finished since the scroll call triggers much more frequently in a 300px range than a 10px range.
To fix this, I added a trigger that would be flipped on successful AJAX load. My code looks more like this:
var scrollLoad = true;
$(window).scroll(function () {
if (scrollLoad && $(window).scrollTop() >= $(document).height() - $(window).height() - 300) {
scrollLoad = false;
//Add something at the end of the page
}
});
then in my AJAX response, I set scrollLoad to true.
I built on top of Hussein's little example here to make a jQuery widget. It supports localStorage to temporarily save appended results and it has pause functionality to stop the appending every so often, requiring a click to continue.
Give it a try:
http://www.hawkee.com/snippet/9445/
$(function(){
$(window).scroll(function(){
if($(document).height()<=$(window).scrollTop()+$(window).height()+100){
alert('end of page');
}
});
});
Some one asked for explanation so here is the explanation
here $(document).height()-->is the height of the entire document.In most cases, this is equal to the element of the current document.
$(window).height()-->is the height of the window (browser) means height of whatever you are seeing on browser.
$(window).scrollTop()-->The Element.scrollTop property gets or sets the number of pixels that the content of an element is scrolled upward. An element's scrollTop is a measurement of the distance of an element's top to its topmost visible content. When an element content does not generate a vertical scrollbar, then its scrollTop value defaults to 0.
$(document).height()<=$(window).scrollTop()+$(window).height()+100
add $(window).scrollTop() with $(window).height() now check whether the result is equal to your documnet height or not. if it is equal means you reached at the end.we are adding 100 too because i want to check before the 100 pixels from the bottom of document(note <= in condition)
please correct me if i am wrong
I had same problem but didn't find suitable plugin for my need. so I wrote following code. this code appends template to element by getting data with ajax and pagination.
for detecting when user scrolls to bottom of div I used this condition:
var t = $("#infiniteContent").offset().top;
var h = $("#infiniteContent").height();
var ws = $(window).scrollTop();
var dh = $(document).height();
var wh = $(window).height();
if (dh - (wh + ws) < dh - (h + t)) {
//now you are at bottom of #infiniteContent element
}
$(document).ready(function(){
$.getJSON("https://jsonplaceholder.typicode.com/comments", { _page: 1, _limit:3 }, function (jsonre) {
appendTemplate(jsonre,1);
});
});
function appendTemplate(jsonre, pageNumber){
//instead of this code you can use a templating plugin like "Mustache"
for(var i =0; i<jsonre.length; i++){
$("#infiniteContent").append("<div class='item'><h2>"+jsonre[i].name+"</h2><p>"+jsonre[i].body+"</p></div>");
}
if (jsonre.length) {
$("#infiniteContent").attr("data-page", parseInt(pageNumber)+1);
$(window).on("scroll", initScroll);
//scroll event will not trigger if window size is greater than or equal to document size
var dh = $(document).height() , wh = $(window).height();
if(wh>=dh){
initScroll();
}
}
else {
$("#infiniteContent").attr("data-page", "");
}
}
function initScroll() {
var t = $("#infiniteContent").offset().top;
var h = $("#infiniteContent").height();
var ws = $(window).scrollTop();
var dh = $(document).height();
var wh = $(window).height();
if (dh - (wh + ws) < dh - (h + t)) {
$(window).off('scroll');
var p = $("#infiniteContent").attr("data-page");
if (p) {
$.getJSON("https://jsonplaceholder.typicode.com/comments", { _page: p, _limit:3 }, function (jsonre) {
appendTemplate(jsonre, p);
});
}
}
}
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<div id="infiniteContent"></div>
If you have a scrollable element, like a div with scroll overflow, but no scrollable document/page, you can take this way.
$(function () {
var s = $(".your-scrollable-element");
var list = $("#your-table-list");
/* On element scroll */
s.scroll(function () {
/* The scroll top plus element height equals to table height */
if ((s.scrollTop() + s.height()) == list.height()) {
/* you code */
}
});
});
I wrote this function using Hussein and Nick's ideas, but I wanted it to use promises for the callback. I also wanted the infinite scrolling area to be on a fixed div and not just the window if the div is sent into the options object. There is an example of that in my second link below. I suggest using a promise library like Q if you want to support older browsers. The cb method may or may not be a promise and it will work regardless.
It is used like so:
html
<div id="feed"></div>
js
var infScroll = infiniteScroll({
cb: function () {
return doSomethingPossiblyAnAJAXPromise();
}
});
If you want the feed to temporarily stop you can return false in the cb method. Useful if you have hit the end of the feed. It can be be started again by calling the infiniteScroll's returned object method 'setShouldLoad' and passing in true and example to go along with the above code.
infScroll.setShouldLoad(true);
The function for infinite scrolling is this
function infiniteScroll (options) {
// these options can be overwritten by the sent in options
var defaultOptions = {
binder: $(window), // parent scrollable element
loadSpot: 300, //
feedContainer: $("#feed"), // container
cb: function () { },
}
options = $.extend(defaultOptions, options);
options.shouldLoad = true;
var returnedOptions = {
setShouldLoad: function (bool) { options.shouldLoad = bool; if(bool) { scrollHandler(); } },
};
function scrollHandler () {
var scrollTop = options.binder.scrollTop();
var height = options.binder[0].innerHeight || options.binder.height();
if (options.shouldLoad && scrollTop >= (options.binder[0].scrollHeight || $(document).height()) - height - options.loadSpot) {
options.shouldLoad = false;
if(typeof options.cb === "function") {
new Promise(function (resolve) {resolve();}).then(function() { return options.cb(); }).then(function (isNotFinished) {
if(typeof isNotFinished === "boolean") {
options.shouldLoad = isNotFinished;
}
});
}
}
}
options.binder.scroll(scrollHandler);
scrollHandler();
return returnedOptions;
}
1 feed example with window as scroller
2 feed example with feed as scroller

Categories

Resources