I'm using the following pen by Bramus to animate(FadeInUp) divs when entering the viewport. However currently the div only starts fading in when the div is completely in the viewport. What I need is the flexibility to start the animation when a div is a certain pixels inside the viewport. For example it will start the animation FadeInUp when the div is 100 pixels in the viewport. How can I do this with the current code/pen I'm using (see code below)?
Is this also possible with percentages? F.e. when a div is 20% in viewport the animation starts?
Thanks.
jQuery(function($) {
// Function which adds the 'animated' class to any '.animatable' in view
var doAnimations = function() {
// Calc current offset and get all animatables
var offset = $(window).scrollTop() + $(window).height(),
$animatables = $('.animatable');
// Check all animatables and animate them if necessary
$animatables.each(function(i) {
var $animatable = $(this);
if (($animatable.offset().top + $animatable.height() - 20) < offset) {
$animatable.removeClass('animatable').addClass('animated');
}
});
};
// Hook doAnimations on scroll, and trigger a scroll
$(window).on('scroll', doAnimations);
$(window).trigger('scroll');
});
Offsetting is already foreseen in the code. Tweak the value of 20 in this line:
if (($animatable.offset().top + $animatable.height() - 20) < offset) {
You might also need to change the - sign to a + to suit your needs.
I have a HTML class navigation with the initial height of 100px and min-height is 40px. I want to change the height of the class, based on the scroll (if scroll down than size will decrease and if scroll up than size will increase). I use the following code and it's working perfectly.
$(window).scroll( function() {
if( $('.navigation').offset().top > 50 )
{
$('.navigation').css({
'height' : '40px',
'background' : 'rgba(37, 37, 37, 0.9)'
});
} else {
$('.navigation').css({
'height' : '100px',
'background' : '#b24926'
});
}
});
If I press the keyboard down arrow key two times than navigation class moved from original height to minimum height and if the up arrow key press two times than navigation class moved from minimum height to original height.
But I want to make the scroll more smooth (like 4-5 up or down key presses to reach from one height to another).
For example: initial height is: 100px and minimum height is 30px. Now:
if down arrow key is pressed/mouse wheel is move down one time than height will be 85px, if again down arrow is pressed height will be 70px and so on. That means for each down arrow key is pressed/mouse wheel is move down than height will decrease by 15-20px and for each up arrow key is pressed/mouse wheel is move up, height will increase by 15-20px.
Can anyone tell me how can I do that (without using third party api).
Thanks
You can use simple percent calculation to update height
var limitForMinimalHeight = 400; //after this distance navigation will be minimal height
var maxHeight = 100;
var minHeight = 40;
$(window).scroll( function() {
var screenTop = $(document).scrollTop();
var achievedDistancePercent = Math.min(screenTop*100/limitForMinimalHeight, 100);
var amounToAdd = ((maxHeight - minHeight) * (100 - achievedDistancePercent))/100;
var newHeight = minHeight + amounToAdd;
$('.navigation').height(newHeight);
});
You can test it on JSFiddle
$(document).scroll(function() {
if($(this).scrollTop()>100) {
$('.selector').addClass('scrolled');
}
if($(this).scrollTop()<40) {
$('.selector').removeClass('scrolled');
}
});
I am using a absolute positioned layout (a bit similar to pinterest)
So I need to recalculate positions also on window.resize: And as this event is not fired on dom ready, I do it manually.
$(document).ready(function(){
$(window).resize();
});
$(window).resize(setupBlocks);
Now, this function setupBlocks checks for the sizes of the HTML elements to calculate its new position
function setupBlocks() {
if ($('.fancyContent').length > 0) {
if ($('.rightFixed').length > 0) $('.fancyContent').width($(window).width() - 320)
windowWidth = $('.fancyContent').width();
//colWidth = $('.fancyContent .widgetHelp').outerWidth();
blocks = [];
//console.log(blocks);
colCount = Math.floor(windowWidth / (colWidth + margin * 2));
for (var i = 0; i < colCount; i++) {
blocks.push(margin);
}
$('.fancyContent .widgetHelp').css({
'position': 'absolute',
'width': colWidth
});
positionBlocks();
var topFooter = $('.fancyContent .widgetHelp:last').offset().top + 350;
$('footer').css({
'position': 'absolute',
'top': topFooter
});
//console.log(topFooter);
$('.fancyContent').css('visibility', 'visible');
$('#load').remove();
//console.log($('#load').length);
}
}
function positionBlocks() {
$('.fancyContent .widgetHelp').each(function () {
var min = Array.min(blocks);
var index = $.inArray(min, blocks);
var leftPos = margin + (index * (colWidth + margin));
$(this).css({
'left': leftPos + 'px',
'top': min + 'px'
});
blocks[index] = min + $(this).outerHeight(true) + margin;
});
}
The unexpected thing is that this is executed as expected. But the positions are not very well calculated untill the window is resized. Then the positions become exact.
I know it's a long shot. but any idea why it could be behaving differently?
Its better if you test yourself: http://209.51.221.243/integracion/login.php
When the page is load, the divs are almost fine (some of them are vertically touching), but if you resize the div the divs get well positioned. any thougths?
When you write:
$(document).ready(function(){
$(window).resize();
});
setupBlocks function isn't called, this way it is:
$(document).ready(function(){
$(window).on('resize', setupBlocks); // window listens for resize events
$(window).resize(); // fire window resize
});
Now you are sure your setup is run at page load [fiddle].
Rather than running the $(window).resize() on document ready, run it on window load. In other words change
$(document).ready(function(){
$(window).resize();
});
to
$(window).load(function(){
$(window).resize();
});
Since document ready just waits until all the DOM elements are in place, jQuery can't detect the proper block sizes and positions, because the images aren't loaded. Once the images load, dimensions change. If you want to get things positioned ASAP, try specifying heights and widths for the images, so when the document is ready (rather than the window loaded), jQuery can pick up on all the image sizes.
Greeting's
I'am still relatively new to JavaScript and Jquery and I know there has got to be a better method than the one I'am using.
I'am working on a serialScroll implementation. There is a master scrollTo that controls the left/right movement of a number of slides. Each slide contains it's own implementation of a vertical serialScroll. I have the resize on the scrollTo working great and the resize on the vertical works but I can't figure an elegant method for ensuring that on resize the current position remains centered, My current method works but is very inefficient.
$(function(){
var $up = $('#sec1_nav a.up').hide();//up button -- each slide needs it's own unique nav buttons
var $down = $('#sec1_nav a.down');//down button -- each slide needs it's own unique nav buttons
$('#screen1').serialScroll({
target:'#section1',
items:'.item',
prev:'#sec1_nav a.up',
next:'#sec1_nav a.down',
axis:'y',
duration:1000,
force:true,
cylce: false,
onBefore:function( e, elem, $pane, $items, pos ){
$up.add($down).show();
if( pos == 0 )$up.hide();
else if( pos == $items.length -1 )
$down.hide();
// Here's where it get ugly, I'am adding a unique class for each slide to the item's
$('.item').removeClass('pos1'); //Each slides need's it's own class i.e. slide1 = pos1, slide2 = pos2 etc.
$(elem).addClass('pos1');
}
});
$(window).bind("resize", function(){
resize1(); // Same goes for the resize function, each slide need's it's own function.
});
});
function resize1() {
height = $(window).height();
width = $(window).width();
mask_height = height * $('.item').length; // sets the new mask height
// Resize Height of the area
$('.sections').css({height: height, width : width});
$('.item').css({height: height, width : width});
$('#mask').css({height : mask_height, width : width});
$('.sections').scrollTo('.pos1', 0 ); // This issue is where it all fall apart, instead of using serialScroll, i'am stuck using scrollTo to maintain the current slide position.
}
I have an HTML document with images in a grid format using <ul><li><img.... The browser window has both vertical & horizontal scrolling.
Question:
When I click on an image <img>, how then do I get the whole document to scroll to a position where the image I just clicked on is top:20px; left:20px ?
I've had a browse on here for similar posts...although I'm quite new to JavaScript, and want to understand how this is achieved for myself.
There's a DOM method called scrollIntoView, which is supported by all major browsers, that will align an element with the top/left of the viewport (or as close as possible).
$("#myImage")[0].scrollIntoView();
On supported browsers, you can provide options:
$("#myImage")[0].scrollIntoView({
behavior: "smooth", // or "auto" or "instant"
block: "start" // or "end"
});
Alternatively, if all the elements have unique IDs, you can just change the hash property of the location object for back/forward button support:
$(document).delegate("img", function (e) {
if (e.target.id)
window.location.hash = e.target.id;
});
After that, just adjust the scrollTop/scrollLeft properties by -20:
document.body.scrollLeft -= 20;
document.body.scrollTop -= 20;
Since you want to know how it works, I'll explain it step-by-step.
First you want to bind a function as the image's click handler:
$('#someImage').click(function () {
// Code to do scrolling happens here
});
That will apply the click handler to an image with id="someImage". If you want to do this to all images, replace '#someImage' with 'img'.
Now for the actual scrolling code:
Get the image offsets (relative to the document):
var offset = $(this).offset(); // Contains .top and .left
Subtract 20 from top and left:
offset.left -= 20;
offset.top -= 20;
Now animate the scroll-top and scroll-left CSS properties of <body> and <html>:
$('html, body').animate({
scrollTop: offset.top,
scrollLeft: offset.left
});
Simplest solution I have seen
var offset = $("#target-element").offset();
$('html, body').animate({
scrollTop: offset.top,
scrollLeft: offset.left
}, 1000);
Tutorial Here
There are methods to scroll element directly into the view, but if you want to scroll to a point relative from an element, you have to do it manually:
Inside the click handler, get the position of the element relative to the document, subtract 20 and use window.scrollTo:
var pos = $(this).offset();
var top = pos.top - 20;
var left = pos.left - 20;
window.scrollTo((left < 0 ? 0 : left), (top < 0 ? 0 : top));
Have a look at the jQuery.scrollTo plugin. Here's a demo.
This plugin has a lot of options that go beyond what native scrollIntoView offers you. For instance, you can set the scrolling to be smooth, and then set a callback for when the scrolling finishes.
You can also have a look at all the JQuery plugins tagged with "scroll".
Here's a quick jQuery plugin to map the built in browser functionality nicely:
$.fn.ensureVisible = function () { $(this).each(function () { $(this)[0].scrollIntoView(); }); };
...
$('.my-elements').ensureVisible();
After trial and error I came up with this function, works with iframe too.
function bringElIntoView(el) {
var elOffset = el.offset();
var $window = $(window);
var windowScrollBottom = $window.scrollTop() + $window.height();
var scrollToPos = -1;
if (elOffset.top < $window.scrollTop()) // element is hidden in the top
scrollToPos = elOffset.top;
else if (elOffset.top + el.height() > windowScrollBottom) // element is hidden in the bottom
scrollToPos = $window.scrollTop() + (elOffset.top + el.height() - windowScrollBottom);
if (scrollToPos !== -1)
$('html, body').animate({ scrollTop: scrollToPos });
}
My UI has a vertical scrolling list of thumbs within a thumbbar
The goal was to make the current thumb right in the center of the thumbbar.
I started from the approved answer, but found that there were a few tweaks to truly center the current thumb. hope this helps someone else.
markup:
<ul id='thumbbar'>
<li id='thumbbar-123'></li>
<li id='thumbbar-124'></li>
<li id='thumbbar-125'></li>
</ul>
jquery:
// scroll the current thumb bar thumb into view
heightbar = $('#thumbbar').height();
heightthumb = $('#thumbbar-' + pageid).height();
offsetbar = $('#thumbbar').scrollTop();
$('#thumbbar').animate({
scrollTop: offsetthumb.top - heightbar / 2 - offsetbar - 20
});
Just a tip. Works on firefox only
Element.scrollIntoView();
Simple 2 steps for scrolling down to end or bottom.
Step1: get the full height of scrollable(conversation) div.
Step2: apply scrollTop on that scrollable(conversation) div using the value
obtained in step1.
var fullHeight = $('#conversation')[0].scrollHeight;
$('#conversation').scrollTop(fullHeight);
Above steps must be applied for every append on the conversation div.
After trying to find a solution that handled every circumstance (options for animating the scroll, padding around the object once it scrolls into view, works even in obscure circumstances such as in an iframe), I finally ended up writing my own solution to this. Since it seems to work when many other solutions failed, I thought I'd share it:
function scrollIntoViewIfNeeded($target, options) {
var options = options ? options : {},
$win = $($target[0].ownerDocument.defaultView), //get the window object of the $target, don't use "window" because the element could possibly be in a different iframe than the one calling the function
$container = options.$container ? options.$container : $win,
padding = options.padding ? options.padding : 20,
elemTop = $target.offset().top,
elemHeight = $target.outerHeight(),
containerTop = $container.scrollTop(),
//Everything past this point is used only to get the container's visible height, which is needed to do this accurately
containerHeight = $container.outerHeight(),
winTop = $win.scrollTop(),
winBot = winTop + $win.height(),
containerVisibleTop = containerTop < winTop ? winTop : containerTop,
containerVisibleBottom = containerTop + containerHeight > winBot ? winBot : containerTop + containerHeight,
containerVisibleHeight = containerVisibleBottom - containerVisibleTop;
if (elemTop < containerTop) {
//scroll up
if (options.instant) {
$container.scrollTop(elemTop - padding);
} else {
$container.animate({scrollTop: elemTop - padding}, options.animationOptions);
}
} else if (elemTop + elemHeight > containerTop + containerVisibleHeight) {
//scroll down
if (options.instant) {
$container.scrollTop(elemTop + elemHeight - containerVisibleHeight + padding);
} else {
$container.animate({scrollTop: elemTop + elemHeight - containerVisibleHeight + padding}, options.animationOptions);
}
}
}
$target is a jQuery object containing the object you wish to scroll into view if needed.
options (optional) can contain the following options passed in an object:
options.$container - a jQuery object pointing to the containing element of $target (in other words, the element in the dom with the scrollbars). Defaults to the window that contains the $target element and is smart enough to select an iframe window. Remember to include the $ in the property name.
options.padding - the padding in pixels to add above or below the object when it is scrolled into view. This way it is not right against the edge of the window. Defaults to 20.
options.instant - if set to true, jQuery animate will not be used and the scroll will instantly pop to the correct location. Defaults to false.
options.animationOptions - any jQuery options you wish to pass to the jQuery animate function (see http://api.jquery.com/animate/). With this, you can change the duration of the animation or have a callback function executed when the scrolling is complete. This only works if options.instant is set to false. If you need to have an instant animation but with a callback, set options.animationOptions.duration = 0 instead of using options.instant = true.