I have seen a few websites where their home page is too big and when user scroll down to read the content at the end of the page then a few areas of that page load dynamically. How do they design their page?
As an example the site is http://blog.rainbird.me/ where you can see the effect. How can it be achieved it via jQuery and Ajax?
You do it like this:
1: figure out the maximum browser height for your users (it's probably safe to assume 1920px as very few users have larger than 2560x1920 displays)
2: render your list so it is slightly longer than the 1920px, you can even double it to have a safe margin
3: hook into the scroll event on the document $(document.body).scroll(myScrollHandler)
4: when document.body.scrollTop gets close enough to document.body.scrollHeight you append more data on your page
$.get(urlToGetMoreDataFrom,function(data){ $(document.body).append(data)});
Lazy load of content: http://www.appelsiini.net/projects/lazyload
Load content while scrolling: http://www.webresourcesdepot.com/load-content-while-scrolling-with-jquery/
function CheckIfElementIsInsideViewport(element)
{
var jElement = jQuery(element);
var jElementTop = jElement.position().top;
var jElementBottom = jElement.height() + jElementTop;
var jElementLeft = jElement.position().left;
var jElementRight = jElement.width() + jElementLeft;
var windowTop = jQuery(window).scrollTop();
var windowBottom = jQuery(window).height() + windowTop;
var windowLeft = jQuery(window).scrollLeft();
var windowRight = jQuery(window).width() + windowLeft;
var topVisible = jElementTop > windowTop && jElementTop < windowBottom;
var bottomVisible = jElementBottom > windowTop && jElementBottom < windowBottom;
var leftVisible = jElementLeft > windowLeft && jElementLeft < windowRight;
var rightVisible = jElementRight > windowLeft && jElementRight < windowRight;
return (topVisible && (leftVisible || rightVisible)) || (bottomVisible && (leftVisible || rightVisible));
}
/* Magazine sneakpeak loader (Only loads content when visible in viewport!) */
var magazineSneakPeakHtml = "<p>Loaded!</p>";
jQuery(function()
{
var sneakPeak = jQuery(".box-newestmagazinepeek");
jQuery(window).bind("scroll", function() { SneakPeakMaybe(sneakPeak); });
SneakPeakMaybe(sneakPeak);
});
function SneakPeakMaybe(jElement)
{
if (CheckIfElementIsInsideViewport(jElement))
{
jQuery(".box-newestmagazinepeek .box-content").html(magazineSneakPeakHtml);
jQuery(window).unbind("scroll");
}
}
/**/
How to do it without jQuery:
How to tell if a DOM element is visible in the current viewport?
This will check if the element is entirely visible in the current viewport:
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)
);
}
You could modify this simply to determine if any part of the element is visible in the viewport:
function elementInViewport2(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 + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
You can place elements on your page that note the end of content, when this element then enters the viewport you can load and append new content below it using jQuery ajax (get): http://api.jquery.com/jQuery.get/
Please note that this method is very cpu intensive, since it check if the element is inside the viewport everytime the client scroll!
Related
I am attempting to adapt this JS solution to keep a floating element above the footer of my site.
The adaption I am attempting is instead of changing the element position to absolute, I would have a dynamic bottom px value based on the position of the top of the footer, relevant to the client window.
function checkOffset() {
var onlineFloat = document.querySelector('#online-ceo');
var footer = document.querySelector('.site-footer');
function getRectTop(el){
var rect = el.getBoundingClientRect();
return rect.top;
}
if((getRectTop(onlineFloat) + document.body.scrollTop) + onlineFloat.offsetHeight >= (getRectTop(footer) + document.body.scrollTop) - 20)
var newBottom = ((getRectTop(footer) + document.body.scrollTop) - 40).toString().concat('px');
onlineFloat.style.bottom = newBottom;
if(document.body.scrollTop + window.innerHeight < (getRectTop(footer) + document.body.scrollTop))
onlineFloat.style.bottom = '20px';// restore when you scroll up
}
document.addEventListener("scroll", function(){
checkOffset();
});
The output of newBottom is currently a px value which changes on scroll, however, I am having issues setting this position to the element.
Where am I going wrong? Thanks.
With your approach (changing the bottom property), you can just calculate where the "float" should be if the footer's top position is in view (as in window.innerHeight) on scroll.
function checkOffset() {
var onlineFloat = document.querySelector('#online-ceo');
var footer = document.querySelector('.site-footer');
function getRectTop(el) {
var rect = el.getBoundingClientRect();
return rect.top;
}
var newBottom = 10 + (getRectTop(footer) < window.innerHeight ? window.innerHeight - getRectTop(footer) : 0) + 'px';
onlineFloat.style.bottom = newBottom;
}
document.addEventListener("scroll", function () {
checkOffset();
});
I have a one-page website with several anchors (signifying div positions). After the page is resized (change in height only), I want to refresh the page. Then I want to scroll to the anchor the page was previously at, making the window.top position equal to the anchor position. I have javascript for the resize and refresh portion of this (below), but I'm at a loss regarding the scroll portion. Any ideas? How would I check which div the page was on before resizing? "#markerAbout" is one of the anchors.
var height = $(window).height();
var resizeTimer;
$(window).resize(function(){
if($(this).height() != height){
height = $(this).height();
window.location.reload();
//$(window).scrollTop()=$('#markerAbout').offset().top;
}
});
You can find out which of your elements are currently visible on the view port by following the advice in this question:
How to tell if a DOM element is visible in the current viewport?
You will have to do this on each element in the order you expect them to appear until you find one that is visible. That should be the current element at the top of the viewport.
function elementInViewport2(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 + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
Once you know which of your divs are showing and which are not, you can choose which one you want to scroll too.
Once you know which div to scroll to for example Div1, you can call scrollIntoView() on that element.
Div1.scrollIntoView();
Since you refresh the page, setting a variable is out of the table. My suggestion is to reload the page with a reference of the anchor as hash at the end plus add a function which is fired first thing after page load that check if there's a hash in the url and if so scrolls the page to the anchor wrote in the hash. I added also a function that starts the reloading process after the end of the resizing process only and also another one that iterates through all the anchors (you have to add a class="anchors" to each anchor) and defines which is the one visible.
That's the code, hope it helps:
$(document).ready(function(){
if(window.location.hash){
//Scroll to $(window.location.hash)
}
var height = $(window).height();
var resizeTimer;
$.fn.isOnScreen = function(){
var win = $(window);
var viewport = {
top : win.scrollTop(),
left : win.scrollLeft()
};
viewport.right = viewport.left + win.width();
viewport.bottom = viewport.top + win.height();
var bounds = this.offset();
bounds.right = bounds.left + this.outerWidth();
bounds.bottom = bounds.top + this.outerHeight();
return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));
};
$(window).resize(function() {
if(this.resizeTO) clearTimeout(this.resizeTO);
this.resizeTO = setTimeout(function() {
$(this).trigger('resizeEnd');
}, 500);
});
$(window).bind('resizeEnd', function() {
if($(this).height() != height){
height = $(this).height();
anchor = false;
$('.anchors').each(function(){
if($(this).isOnScreen()){
anchor = $(this).attr('id')
return
}
});
window.location.href = window.location.href + anchor;
window.location.reload(true);
}
});});
I have a tooltip element which is displayed when hovering over certain elements.
I would like the tooltip to be positioned above the normal element as expected but in the case where the tooltip is too large and escapes the window, I need this to NOT happen.
How can I have an element which is absolutely positioned and also never displays out of view?
Edit: Preferably using CSS...
Following the idea presented here: How to tell if a DOM element is visible in the current viewport?
I'd got with:
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)
);
}
var tooltip = $(".tooltip");
tooltip.show(); //we must make it visible in order to perform the test on the next line
if(!elementInViewport(tooltip)) {
tooltip.hide();
}
I'm using jquery.parallax-1.1.3.js for a parallax effect. (site: http://ianlunn.co.uk/plugins/jquery-parallax/)
Problem: it works with css background-position. This works for background images but not for text in my html.
What I want: add some code to this js file that allows me to use the parallax effect on html text (H1, H2). I prefer with an ID. So a H1 would have a div around it with an ID that is connected with the parallax effect.
This is the js:
(function( $ ){
var $window = $(window);
var windowHeight = $window.height();
$window.resize(function () {
windowHeight = $window.height();
});
$.fn.parallax = function(xpos, speedFactor, outerHeight) {
var $this = $(this);
var getHeight;
var firstTop;
var paddingTop = 0;
//get the starting position of each element to have parallax applied to it
$this.each(function(){
firstTop = $this.offset().top;
});
if (outerHeight) {
getHeight = function(jqo) {
return jqo.outerHeight(true);
};
} else {
getHeight = function(jqo) {
return jqo.height();
};
}
// setup defaults if arguments aren't specified
if (arguments.length < 1 || xpos === null) xpos = "50%";
if (arguments.length < 2 || speedFactor === null) speedFactor = 0.1;
if (arguments.length < 3 || outerHeight === null) outerHeight = true;
// function to be called whenever the window is scrolled or resized
function update(){
var pos = $window.scrollTop();
$this.each(function(){
var $element = $(this);
var top = $element.offset().top;
var height = getHeight($element);
// Check if totally above or totally below viewport
if (top + height < pos || top > pos + windowHeight) {
return;
}
$this.css('backgroundPosition', xpos + " " + Math.round((firstTop - pos) * speedFactor) + "px");
});
}
$window.bind('scroll', update).resize(update);
update();
};
})(jQuery);
This is how to call the js from html:
<script type="text/javascript" src="js/jquery.parallax-1.1.3.js"></script>
<script type="text/javascript">
$(document).ready(function(){
//.parallax(xPosition, speedFactor, outerHeight) options:
//xPosition - Horizontal position of the element
//inertia - speed to move relative to vertical scroll. Example: 0.1 is one tenth the speed of scrolling, 2 is twice the speed of scrolling
//outerHeight (true/false) - Whether or not jQuery should use it's outerHeight option to determine when a section is in the viewport
$('#third').parallax("50%", 0.5);
})
</script>
You give a div an ID. You give this Div a background-image. You connect the ID to the parallax effect above. I want to do the same, but then with an H1.
I'm trying to figure out a way to select elements that are overlapped (and contained, completely covered up) within an absolutely positioned div.
I basically need to select elements within a certain pixel boundary. How can this be done using jQuery?
Here's the basic idea:
var left = 100,
top = 200,
right = 300,
bottom = 500;
$('#main-div').children().filter(){
var $this = $(this),
offset = $this.offset(),
rightEdge = $this.width() + offset.left,
bottomEdge = $this.height() + offset.top;
if (offset.top > top && offset.left > left && right > rightEdge && bottom > bottomEdge) {
return true;
}
return false;
});
Change the coordinates at the top to whatever you need.
Suppose your html is something like:
<div id="thediv"></div>
<div id="one">one</div><br />
<div id="two">two</div><br />
<div id="three">three</div><br />
You could have this jQuery:
$('div:not(#thediv)').filter(function() {
var offset = $(this).offset();
var left = offset.top;
var top = offset.top;
var right = left + $(this).width();
var bottom = top + $(this).height();
var offset2 = $('#thediv').offset();
var left2 = offset2.top;
var top2 = offset2.top;
var right2 = left2 + $('#thediv').width();
var bottom2 = top2 + $('#thediv').height();
if (
(
(left < left2 && right > left2)
|| (left > left2 && right < right2)
|| (left < right2 && right > right2)
)
&&
(
(top < top2 && bottom > top2)
|| (top > top2 && bottom < bottom2)
|| (top < bottom2 && bottom > bottom2)
)
)
return true;
else
return false;
}).css('background-color', 'red');
And the divs that overlap with the main div would turn red. You can test it here.
The idea is to get the offset(), width() and height() of the elements, and see if they overlap. The code is probably not very efficient, I wrote it like this to make it clear.