I've been searching on many posts but almost all of them are confusing.
I'm working with animate.css into a which is at the middle of my page.
For default the animation is played when the page is loaded, but i want that it play when i reach the (when i'm scrolling).
Please, don't say about JS Reveal, i'd like to use the animation from animate.css
What i was trying:
HTML
<!-- Others div above -->
<div class="row sf-medida" id="sf-medida" onscroll="Animar();">
<!-- Others div below -->
JS
function Animar() {
setTimeout(function(){
document.getElementById("sf-medida").style.visibility = "visible";
$("#titulo-general").addClass("animated fadeInLeft");
$(".sub-titulo").addClass("animated bounceInRight");
$(".titulo-izquierda").addClass("animated swing");
$(".texto-1").addClass("animated fadeIn");
$(".texto-2").addClass("animated fadeIn");
},1000)
}
But it doesn't work, however, i've tried adding
window.addEventListener("scroll", Animar);
But what it does is that the animation is played whenever i scroll on the page,
This can be very easily done using little jquery. All you need to do is listen to the scroll event, then check if user have scrolled to the target element. If the user did, then add animation class from your animate.css. Adjust your if condition according to your desires. Check the below code and fiddle https://jsfiddle.net/15z6x5ko/ for reference
$(document).ready(function(){
$(document).scroll(function(evt){
var v2 = Math.abs($('.box').position().top - $(window).height()/2);
var v1 = $(this).scrollTop();
if( v1 > v2 ){
console.log('in');
$('.box').addClass('animated flip')
}
});
});
So as per your request, let me try to explain the code line by line
$(document).ready(function(){
This is easy to understand. It just waits for browser to load all HTML & CSS first and when everything is loaded, the javascript code inside this function will run.
$(document).scroll(function(evt){
This is an event handler, our callback function will run whenever user scrolls on document. Remember change $(document) according whatever the parent is of your target element. So if your target div is inside another div whose class is .parent then use $('.parent').scroll . As for my code I am listening the event on document. When my document scrolls, my event will trigger.
var v1 = $(this).scrollTop();
This code will get the amount of scrolling user had done in pixels.
var v2 = Math.abs($('.box').position().top - $(window).height()/2);
This is a simple math that checks the position of my target div from its parent element subtracting the half of the size of window from it. This will return the pixel positing of your target div. So when user reaches this pixel positing while scrolling, your animation will start.
$('.box').addClass('animated flip')
Now this code simply adds the animation css classes into the target div as soon as user scrolls to the target div.
I'm using "WoW.js" for my scroll reveal library. It's pretty easy to use, like for real. One line of code
<div class="wow fadeIn">content</div>
Here, take a look: http://mynameismatthieu.com/WOW/docs.html
Here's an example using Jquery.
In it we use .scrollTop and .height to measure the videos container from the top of the page so that we know when it comes into view when scrolling. (it's actually set to load when it reaches 100px below the bottom of the viewable area, a sort of preload. you can adjust it to whatever you like.)
The video load is done by copying the url from data-src= into src= when the video container is at the desired spot on the page. (in this case, 100px below the viewable area)
fiddle
note, the video won't load on stack so be sure to view the fiddle
https://jsfiddle.net/Hastig/xszu6b1p/
I scraped it together from these two answers..
Youtube Autoplay
Ladyload Images
$(window).scroll(function() {
$.each($('iframe'), function() {
if ( $(this).attr('data-src') && $(this).offset().top < ($(window).scrollTop() + $(window).height() + 100) ) {
var source = $(this).data('src');
$(this).attr('src', source);
$(this).removeAttr('data-src');
}
})
})
body {
margin: 0;
}
.filler {
display: flex;
justify-content: center;
align-items: center;
height: 800px;
}
.filler-top { background-color: blue }
.filler-btm { background-color: green; }
.video-container {
/* css tricks - responsive iframe video */
/* https://css-tricks.com/NetMag/FluidWidthVideo/Article-FluidWidthVideo.php */
position: relative;
padding-bottom: 56.25%; /* 16:9 */
padding-top: 25px;
height: 0;
display: flex;
justify-content: center;
background-color: red;
}
.video-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="filler filler-top">filler top</div>
<div class="video-container">
<iframe data-src="https://www.youtube.com/embed/f0JDs4FY8cQ?rel=0&autoplay=1"></iframe>
</div>
<div class="filler filler-btm">filler bottom</div>
I have the following code that is adding the class "sticky" on scroll and removing the class "sticky" when the element reaches the anchor "#search-anchor".
However, I'm unable to scroll all the way down to see the full footer. Any ideas why?
https://jsfiddle.net/coldfusion/6z6q3kxm/2/
<style>
header,footer {height:50px;background-color:red;}
section {height: 50px; background-color: yellow;}
#search-anchor {background-color:blue;}
.body {height:1600px;background-color:black;}
.sticky {
position: fixed;
bottom: 0px;
width: 1000px;
margin-right: auto !important;
margin-left: auto !important;
z-index: 999;
}
</style>
<script>
jQuery(document).ready(function() {
var a = jQuery(".inline-search").offset().top,
n = function() {
var n = jQuery(window).scrollTop(),
n = n + 10;
n > a ? jQuery(".inline-search").addClass("sticky") : jQuery(".inline-search").removeClass("sticky")
};
n(), jQuery(window).scroll(function() {
n()
})
}),
jQuery(document).ready(function() {
var search = $(".inline-search");
$(window).scroll(function() {
var anchorPosition = $("#search-anchor").offset().top;
var navHeight = $(".inline-search").height();
var navPosition = $(".inline-search").offset().top;
if ((navPosition + navHeight) >= anchorPosition) {
search.removeClass('sticky');
}
})
});
</script>
<header>HEADER</header>
<section class="inline-search">
</section>
<div class="body"></div>
<section id="search-anchor">
</section>
<footer>FOOTER</footer>
If you use the instruction debugger to pause the execution of JavaScript in the console, you get exactly what #mike-mccaughan is explaining.
You script adds and removes the element .inline-searchfrom the document flow because of the CSS position:fixed;.
If you scroll down and re-add .inline-search to the document flow, the document height changes again and the scrollbar has some space, so your code that detects if we're at the bottom of the page doesn't work anymore. What happens is an infinite and very fast loop of adding and re-adding your fixed positioning: because of that, it seems as if the page "stops" scrolling before getting to the footer.
In order to create such an effect (fixed positioning upon scroll), I'd recommend using Bootstrap's affix jQuery plugin. Even further: Bootstrap recently announced that they're dropping Affix because of sticky positioning coming to CSS, so the real "future-proof" recommendation here would be to use sticky positioning with a polyfill to allow older browsers to have the same effect.
Bootstrap affix : https://github.com/twbs/bootstrap/blob/master/js/affix.js,
http://getbootstrap.com/javascript/#affix
Bootstrap drops affix : https://github.com/twbs/bootstrap/blob/87751da48232ac4ca1964c819aaf89e78a3f9e64/docs/migration.md
Sticky positioning : http://html5please.com/#sticky
Sticky positioning demo : http://html5-demos.appspot.com/static/css/sticky.html - Sticky positioning availability accross browsers : http://caniuse.com/#feat=css sticky
And a sticky positioning polyfill for older browsers : https://github.com/filamentgroup/fixed-sticky
I have a web page with a top horizontal navigation bar – it is Twitter's Bootstrap Fixed Top Navbar to be more precise – with a bottom-fixed position (actually it's not really fixed by CSS; see JavaScript below) so the navigation bar will first be visible at the bottom of the page and later displayed at the top of the page when scrolling (position: fixed; top: 0).
I have the navigation links set up with anchor tags to take the viewer to various places in the body of the page. Unfortunately, sometimes it takes the user a bit too far down (especially if the user is at the top of the page and the navigation bar has not yet became fixed).
Take a look at my HTML structure:
<div id="landing"></div>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li>Home</li>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
</ul>
</div>
</div>
</nav>
<div id="section1"></div>
<div id="section2"></div>
<div id="section3"></div>
I'm using the following JavaScript to ensure that the navbar sticks to the top of the page after scrolling down:
function init() {
nh = 50; // navbar height
sh = $(window).height();
ih = sh-nh;
$("#landing").css('height', ih+'px');
}
function navbarState() {
if ($(window).scrollTop() > ih) {
$('.navbar').addClass('navbar-fixed-top');
} else {
$('.navbar').removeClass('navbar-fixed-top');
}
}
init();
navbarState();
$(window).on('load scroll resize orientationchange', function () {
init();
navbarState();
});
One can observe that repeatedly pressing the first anchor link causes a bouncing effect. How can I prevent that?
My goal is to have the navigation scroll to the proper anchors, no matter whether the user is at the landing page or not.
Why not using navbar-fixed-bottom as well?
See here: https://jsfiddle.net/y7soL4ej/
I added the mentioned class as default to nav. And modified minor things:
CSS
html, body, div#landing {
height: 100%
}
section, [id*=section] {
padding-top: 52px;
}
JS
function init() {
nh = 50 + 2; // navbar height + 2x border width (top + bottom)
sh = $(window).height();
ih = sh-nh;
//$("#landing").css('height', ih+'px');
}
function navbarState() {
if ($(window).scrollTop() > ih) {
$('.navbar').removeClass('navbar-fixed-bottom').addClass('navbar-fixed-top');
} else {
$('.navbar').removeClass('navbar-fixed-top').addClass('navbar-fixed-bottom');
}
}
init();
navbarState();
$(window).on('load scroll resize orientationchange', function () {
init();
navbarState();
});
The jumpy behaviour: When the navbar is at the bottom in your example it is part of the dom flow - it seperates the landing div and the section1 div by its height. As soon as it is clicked the browser jumps to the location, the navbar is then set as fixed at the top - and is no longer part of the flow (the both divs are no longer seperated by it). The section divs are therefore moved accordingly up to the landing div closing the gap. So clicking the same section anchor again will result in an additional jump, because the section was repositioned due to the landing div went from position:static to position:fixed.
That's an additional reason why I recommend to use navbar-fixed-bottom.
Update
new fiddle: https://jsfiddle.net/y7soL4ej/2/
I removed .navbar-fixed-bottom from HTML and JS as the navbar should not jump from bottom to top.
To make it smooth and avoid the earlier mentioned jumpy behaviour, I had to set it to absolute position.
some CSS needed to be added:
div#landing {
padding-bottom: 72px;
margin-bottom: -72px;
}
nav.navbar {
position: absolute;
left: 0; right: 0;
}
nav.navbar.navbar-fixed-top {
position: fixed;
}
I have purchased a template for my shopify store that scrolls a site wide absolutely positioned background image at a slower speed than what the user scrolls for a neato perspective effect.
I have found the script used in the template that animated the scrolling effect for the background image. It is as follows:
<script type="text/javascript">
(function($) {
if(device.desktop()){
// PARALLAX INIT
$(window).bind('scroll',function(e){
parallaxScroll1();
});
function parallaxScroll1(){
var scrolled = $(window).scrollTop();
$('#wrapper .wrapper_bg').css('top',(0+(scrolled*.75))+'px');
}
// SMOOTHSCROLL 4 WEBKIT
var platform = navigator.platform.toLowerCase();
if (platform.indexOf('win') == 0 || platform.indexOf('linux') == 0) {
if ($.browser.webkit) {
/* jquery.simplr.smoothscroll - https://github.com/simov/simplr-smoothscroll */
;(function(e){"use strict";e.srSmoothscroll=function(t){var n=e.extend({step:85,speed:600,ease:"linear"},t||{});var r=e(window),i=e(document),s=0,o=n.step,u=n.speed,a=r.height(),f=navigator.userAgent.indexOf("AppleWebKit")!==-1?e("body"):e("html"),l=false;e("body").mousewheel(function(e,t){l=true;if(t<0)s=s+a>=i.height()?s:s+=o;else s=s<=0?0:s-=o;f.stop().animate({scrollTop:s},u,n.ease,function(){l=false});return false});r.on("resize",function(e){a=r.height()}).on("scroll",function(e){if(!l)s=r.scrollTop()})}})(jQuery);
/* jquery.mousewheel - https://github.com/jquery/jquery-mousewheel */
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});
$.srSmoothscroll({
step: 55,
speed: 100,
ease: 'swing'
});
}
};
};
})(jQuery);
</script>
The issue that I am having is that the scrolling effect moves to quickly, and by the time the user has reached the bottom of the page they are viewing, the background image has prematurely cut off.
I have been fidling around with the values in this script, trying to slow down the effect, with no success. Any insights?
Thanks! You can view this script in action on our site at:
http://ts8276eb.myshopify.com/
the password is: yandasmusic
That code is way too complicated for me to even consider trying to debug.
So I made a much simpler version.
var wrapper = document.getElementById('wrapper'),
checkbox = document.getElementById('scrolleffect');
function parallax() {
if( checkbox.checked) {
wrapper.style.backgroundPosition = "center " + (this.scrollTop / (this.scrollHeight - window.innerHeight) * 100) + "%";
}
else {
wrapper.style.backgroundPosition = "";
}
}
document.body.onscroll = function() {parallax.call(document.body);};
document.documentElement.onscroll = function() {parallax.call(document.documentElement);};
#wrapper {
background: #333 url('http://cdn.shopify.com/s/files/1/0810/2125/t/21/assets/body_bg_img.png?677044079657970527') no-repeat scroll center top;
color: white;
padding: 8px;
}
.spacer {
height: 800px;
}
body {
margin: 0;
}
<div id="wrapper">
<p>Content!</p>
<p style="position: fixed;"><label><input type="checkbox" id="scrolleffect" /> Toggle background scroll effect</label></p>
<div class="spacer"></div>
<p>More content!</p>
<div class="spacer"></div>
<p>Content ends</p>
</div>
The important part here is that the background position is updated according to how far down the page we've scrolled. It ranges from center 0% to center 100%. The convenient thing about background image positioning is that 0% means "align top of image with top of element", and 100% means "align bottom of image with bottom of element". Values are interpolated in-between, so 25% would be "align the top quarter mark of the image with the top quarter mark of the element".
Much simpler.
The numbers appear to be crunched here:
$('#wrapper .wrapper_bg').css('top',(0+(scrolled*.75))+'px');
So it currently scrolls 25% slower than the page. If you lower this number, it will go more slowly...
$('#wrapper .wrapper_bg').css('top',(0+(scrolled*.25))+'px');
I've got a left nav div that hides via media query at < 768 and a filter button that displays at < 768. When you click the filter button it uses JQuery to toggle the display of the left nav via show()/hide(). When the window is resized >= 768 I use JQuery to set the display of the left nav back to show.
As I said, my media query handles hiding the left nav when the window width goes below 768, but the problem is it only fires if I have not clicked the filter button. Once I size it under 768 and then click the filter button to turn it on and then click it again to turn it off and then size up over 768 and then back down the left nav is still there. It's like the media query no longer works for the display:none attribute. There are other css properties I change in the media query like width and color and those still work, but it's no longer hiding the div.
I've simplified the code to illustrates the problem.
HTML
Button
<div id="navLeft">NavLeft</div>
CSS
#navLeft {
background-color:orange;
}
#filterButton {
background-color:silver;
display: none;
}
#media only screen and (max-width: 300px) {
#navLeft {
display: none;
}
#filterButton {
display: inline;
}
}
JS
$(window).resize(function()
{
var $theWindowSize = $(this).width();
if($theWindowSize > 300)
{
$('#navLeft').show();
}
});
// Filters
$('#filterButton').bind('click',function(event)
{
event.preventDefault();
if ($('#filterButton').hasClass('filtersActive'))
{
$('#navLeft').hide();
$('#filterButton').removeClass('filtersActive');
}
else
{
$('#navLeft').show();
$('#filterButton').addClass('filtersActive');
}
});
Here's the fiddle. To replicate the behavior follow the steps below.
https://jsfiddle.net/athcy8fL/
1) Resize the width of the Result viewport several times under and above 300px before clicking anything and you'll see everything works as planned. Under 300px the button comes on and the NavLeft div hides. Over 300px and the Button hides and the NavLeft shows
2) Size the Result viewport below 300px and click the Button link. The NavLeft div should appear. Good.
3) Size the Result viewport above 300px and the Button hides. Good.
4) Size the Result viewport below 300px, the NavLeft should hide but it does not. Not Good.
Why doesn't the media query work after using Javascript to alter its display property?
The problem is that when you call .show() in an element that is not already visible, jquery will add an inline style to show the element and override your css, causing the media-query not to work.
I modified your code a little bit to take the inline-style priority into account
http://jsfiddle.net/yjs3fou7/
basically I changed the resize function:
$(window).resize(function()
{
var $theWindowSize = $(this).width();
if($theWindowSize > 300)
{
$('#navLeft').show();
$('#filterButton').removeClass('filtersActive')
} else {
if (!$('#filterButton').hasClass('filtersActive'))
$('#navLeft').hide();
}
});
inline styles have more priority than id or class styles according to css specificity rules so once you start manipulating things from javascript you must remember it may cause your css to stop being applied
The problem is the use of inline styles which has more specificity than the css rules.
$(window).resize(function() {
var $theWindowSize = $(this).width();
if ($theWindowSize > 300) {
$('#navLeft').removeClass('show');
$('#filterButton').removeClass('filtersActive');
}
});
// Filters
$('#filterButton').bind('click', function(event) {
event.preventDefault();
$('#filterButton').toggleClass('filtersActive');
$('#navLeft').toggleClass('show', $('#filterButton').hasClass('filtersActive'));
});
#navLeft {
background-color: orange;
}
#filterButton {
background-color: silver;
display: none;
}
#media only screen and (max-width: 300px) {
#navLeft {
display: none;
}
#filterButton {
display: inline;
}
#navLeft.show {
display: block;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Button
<div id="navLeft">NavLeft</div>
Demo: Fiddle