I have a piece of code, that's changing my div background on mousescroll and it's working fine in Chrome and Opera, but it doesn't in Firefox and IE/Edge.
I have two divs, the inner one has a background image that is changing on scroll down, the outer one is simply bigger so there is space to scroll.
In Firefox and IE/Edge, the scroll or doesn't work either skips an image, sometimes even doesn't purceed to scrolling the rest of the content on the website.
http://jsfiddle.net/s6qrfo9n/1/
Any ideas why?
Here it is (and I know it's poorly written, but I'm new to javascript and it does the job):
$(document).ready(function(){
var numberofscroll = 0;
var lastScrollTop = 0;
$("#home").scroll(function(){
var st = $(this).scrollTop();
(st > lastScrollTop) ? numberofscroll++ : numberofscroll--;
console.log(numberofscroll);
console.log(lastScrollTop);
console.log(st);
if (numberofscroll<2){
change_background2(numberofscroll);
}
else if (numberofscroll<3){
change_background3(numberofscroll);
}
else if (numberofscroll<4){
change_background4(numberofscroll);
}
lastScrollTop = st;
});
function change_background2(numberofscroll){
var i;
for (i = 2; i <= 2; i++) {
$("#home").css("background-image","url('images/movie_" + i + ".jpg')");
}
}
function change_background3(numberofscroll){
var i;
for (i = 3; i <= 3; i++) {
$("#home").css("background-image","url('images/movie_" + i + ".jpg')");
}
}
function change_background4(numberofscroll){
var i;
for (i = 4; i <= 4; i++) {
$("#home").css("background-image","url('images/movie_" + i + ".jpg')");
}
}
});
The problem lies in the smooth scrolling feature of firefox and ie (see this question). This causes the jQuery scroll event to fire multiple times every time you scroll, thus the 'missing' images--they are being put in, but then they're replaced so fast you can't see them.
Unfortunately, since you can't disable the smooth scrolling feature on people's browsers, there isn't really a perfect solution to this. The best solution is to debounce your scroll event handler. There are many ways to implement a debounce (google it for some ideas). A simple one would be just toggling a boolean after a timeout and checking it every time you run the function:
var dontHandle = false;
$("#home").scroll(function () {
if (dontHandle) return; // Debounce this function.
dontHandle = true;
window.setTimeout(function() {
dontHandle = false;
}, 400); // Debounce!--don't let this function run again for 400 milliseconds.
});
Here's your updated JSFiddle. You may need to play with the debounce time. Best of luck.
I'd say your code is working as intended but I have a couple thoughts about the scroll event.
The scroll event will only be fired if scrolling actually takes place. Nothing will happen if your div doesn't scroll. You could get around that by using another library, check out this stackoverflow answer for some suggested libraries. Also, keep in mind that the scroll event is extremely sensitive, so the "skipping" of images may simply be a result of scrolling too fast.
I cleaned up your code to make better use of the change_background function.
var numberofscroll = 0;
var lastScrollTop = 0;
$(document).ready(function(){
$("#home").scroll(function(e) {
var st = $(this).scrollTop();
console.log(numberofscroll, lastScrollTop, st);
(st > lastScrollTop) ? numberofscroll++ : numberofscroll--;
//make sure numberofscroll stays in range
if(numberofscroll <= 0) {
numberofscroll = 1;
} else if(numberofscroll > 4) {
numberofscroll = 4;
}
change_background(numberofscroll);
lastScrollTop = st;
});
function change_background(numberofscroll) {
$("#home").css("background-image","url('http://coverjunction.s3.amazonaws.com/manual/low/colorful" + numberofscroll + ".jpg')");
}
});
Your change_background functions have been rolled into one function and numberofscroll will stay within a certain range to ensure the image you want actually exists.
Hope that helps!
Related
I am trying to mess around with some JS and using snippets trying to get them to work on clean WP installs so that I understand how to add them Wordpress properly.
I am working with JSFiddle
This is the link that im testing it on
(function() {
var delay = false;
$(document).on('mousewheel DOMMouseScroll', function(event) {
event.preventDefault();
if(delay) return;
delay = true;
setTimeout(function(){delay = false},200)
var wd = event.originalEvent.wheelDelta || -event.originalEvent.detail;
var a= document.getElementsByTagName('a');
if(wd < 0) {
for(var i = 0 ; i < a.length ; i++) {
var t = a[i].getClientRects()[0].top;
if(t >= 40) break;
}
}
else {
for(var i = a.length-1 ; i >= 0 ; i--) {
var t = a[i].getClientRects()[0].top;
if(t < -20) break;
}
}
$('html,body').animate({
scrollTop: a[i].offsetTop
});
});
})();
Here is the fiddle I am trying to implement.
It seems to be trying to do something on scroll and gets stuck.
Steps I have taken:
Added HTML to page
Added CSS to style.css
Added link to Jquery in header
Added the JS snippet in a tag before
I'm thinking maybe it has something to do with the fact that its got more elements on the page than just a and tag maybe? Seems to be getting caught on the header. This JS is just kind of hard for me to reverse engineer with the little that I know unfortunately.
Thanks.
The javascript listens to your mouse wheel event. If you mouse wheel up or down, it will first check if you're currently "wheeling" too fast. If you are, it will delay you. If you're not, then it will scroll (animate) to your next anchor tag and that anchor tag will be up top.
EDIT: I see you're getting a js error on your site. Remove the $ from the
$(function() {
var delay = false;
//blah blah
}
$myWindow.on('resize', function(){
var $width = $myWindow.width();
if ($width > 870) {
console.log('hey im 870');
$('#the-team-wrapper .flex-content').empty();
ajax_results.done(function(data) {
// console.log(data.job_titles[3]);
var employee_job_titles;
function job_titles_display(jobtitle,ind){
if (jobtitle.job_titles[ind].length>1) {
var my_array = [];
for (var i = 0; i < jobtitle.job_titles[ind].length; i++){
my_array.push(jobtitle.job_titles[ind][i][0]['title']);
employee_job_titles = my_array.join(' | ');
}
}else {
var employee_job_titles;
employee_job_titles = jobtitle.job_titles[ind][0]['title'];
}
return employee_job_titles;
}
for (var i = 0; i < data.employee_info.length; i++) {
if(i%2 == 0){
$('#the-team-wrapper .flex-content').append('<div class="profile-parent"><div class="employee-profile-pic flex-item" data-id="'+data.employee_info[i]['id']+'"></div><div class="employee-bio-wrapper flex-item"><h2 data-id="'+data.employee_info[i]['id']+'">'+data.employee_info[i]['firstname']+" "+data.employee_info[i]['lastname']+'</h2><h3 data-id="'+data.employee_info[i]['id']+'">'+job_titles_display(data,i)+
'</h3><p class="employee-bio-text employee-bio-text-not-active">'+data.employee_info[i]['bio']+'</p></div><button type="button" class="bio-prev-butt-left">View '+data.employee_info[i]['firstname']+'\'s'+' Bio</button><div class="hide-bio-close-button-left">x</div></div>');
}else {
$('#the-team-wrapper .flex-content').append('<div class="profile-parent"><div class="employee-bio-wrapper flex-item"><h2 data-id="'+data.employee_info[i]['id']+'">'+data.employee_info[i]['firstname']+" "+data.employee_info[i]['lastname']+'</h2><h3 data-id="'+data.employee_info[i]['id']+'">'+job_titles_display(data,i)+'</h3 data-id="'+data.employee_info[i]['id']+
'"><p class="employee-bio-text employee-bio-text-not-active">'+data.employee_info[i]['bio']+'</p></div><div class="employee-profile-pic flex-item" data-id="'+data.employee_info[i]['id']+'"></div><button type="button" class="bio-prev-butt-right">View '+data.employee_info[i]['firstname']+'\'s'+' Bio</button><div class="hide-bio-close-button-right">x</div></div>');
}
var profile_pic_path = data.employee_info[i]['profile_pic'].split('\\').join('\\\\');
$("#the-team-wrapper .flex-content-wrapper .flex-content .employee-profile-pic:eq("+i+")").css({'background': 'url(_employee_pics/'+profile_pic_path+')','background-repeat': 'no-repeat','background-position': 'center', 'background-size': 'cover'});
}
});
}
I have this code, and it should fire when width is greater than 870, but instead it fires when width is greater than 970 on Opera, and when width is about 890 on Chrome. How can I fix this and get consistent results across browsers. Thanks in advance.
Are you using a CSS reset to neutralize the browser's default margin or padding on the <body> element?
Different browsers add different amounts of either padding or margin to the <body> of the page, which could explain why the function is triggered at different points in different browsers.
The problem is, the resize event fires at different times and rates depending on browser, CPU load, and how fast you actually do the resizing.
Test the following code in your browsers. When I do this in a clean browser at a reasonable rate of coverage the difference usually comes in within around 2px of the target.
(BTW, you'll see I am caching the jQuery selectors into variables. Not strictly necessary for this test, but you might be surprised to find out how many bugs I've fixed because coders have invoked uncached jQuery selectors willy-nilly in loops and other repetitive places throughout their code).
var $window = $(window);
$window.on('resize',function(){
var w = $window.width();
if (w > 1000) {
console.log( w );
} else {
console.log('nope: ' + w)
}
});
I am seeing that if a user scrolls too fast, the below jQuery function does not fire. Is this a performance issue/bug within jQuery detection of the event or do I need to do something with my code?
...Or, is there a better way [at least performance reliability wise] to call it with pure JavaScript? If so, how do I code it?
$(window).scroll(function() {
var st = $(this).scrollTop();
if(st < 50){
$('.header_wrapper').css({'marginTop':-50});
} if(st < 40){
$('.header_wrapper').css({'marginTop':0});
}
});
You can see it in action here: http://www.walkingfish-grainboards.com/privacy-policy/
Thnx for your help - it would be greatly appreciated.
Since you are considering performance:
$(window).on('scroll',function(){
var st = $(this).scrollTop(),
mTop = ((st < 40) ? 0 : -50);
$('.header-wrapper').css({marginTop:mTop});
});
Rather than put the assignment in the if you can just put the value, then do the assignment once based on the value. With your current statement, the -50px value you remain no matter how far down you go (as you never clear this value), and would only return to 0 when you scrolled back to the top. Hence, you do not need to have the nested if statement.
If you really wanna kick it up a notch, include caching:
var scrollStuff = {
headerWrapper:$('.header-wrapper'),
onScroll:function(){
var self = this,
st = $(self).scrollTop(),
mTop = ((st < 40) ? 0 : -50);
self.headerWrapper.css({marginTop:mTop});
}
};
$(window).on('scroll',function(){
scrollStuff.onScroll();
});
By caching everything including the function, you won't need to requery the DOM every time for the element you are applying the marginTop to.
Well, I over thought it originally. This works great:
$(window).scroll(function(){
yos = (window.pageYOffset > 48);
$('.headerwrap').toggleClass('stick', yos);
$('.pagetitlewrap').toggleClass('headerwrap_stuck', yos);
});
I am making a responsive site in which I add event listeners to blocks to slide down. If I resize my browser window to become wider I want to execute a slideUp to this blocks so that they're all neatly slided up. Does anyone know how to achieve this?
My jquery function:
function mobileFunctions(){
if($(window).width() < 600){
$(".replace-url").attr('href', '#');
$(".list-categories li").removeClass('click');
categoryActive();
}
}
function categoryActive(){
$(".title-click").click(function(){
var e = $(this).parent("li");
var i = ".list-categories li";
var c = "active";
var d = ".content-category";
if(!$(e).hasClass(c)){
$(i).removeClass(c);
$(i).children(d).slideUp("slow");
}
$(e).children(d).slideDown("slow");
$(e).addClass(c);
});
I believe you are looking for this?
$('window').resize(function() {
var someValue = 1024;
if ($('window').width() > someValue) {
// function here...
}
});
I want to be able to do a cross fade transition on large images whose width is set to 100% of the screen. I have a working example of what I want to accomplish. However, when I test it out on various browsers and various computers I don't get a buttery-smooth transition everywhere.
See demo on jsFiddle: http://jsfiddle.net/vrD2C/
See on Amazon S3: http://imagefader.s3.amazonaws.com/index.htm
I want to know how to improve the performance. Here's the function that actually does the image swap:
function swapImage(oldImg, newImg) {
newImg.css({
"display": "block",
"z-index": 2,
"opacity": 0
})
.removeClass("shadow")
.animate({ "opacity": 1 }, 500, function () {
if (oldImg) {
oldImg.hide();
}
newImg.addClass("shadow").css("z-index", 1);
});
}
Is using jQuery animate() to change the opacity a bad way to go?
You might want to look into CSS3 Transitions, as the browser might be able to optimize that better than Javascript directly setting the attributes in a loop. This seems to be a pretty good start for it:
http://robertnyman.com/2010/04/27/using-css3-transitions-to-create-rich-effects/
I'm not sure if this will help optimize your performance as I am currently using IE9 on an amped up machine and even if I put the browser into IE7 or 8 document mode, the JavaScript doesn't falter with your current code. However, you might consider making the following optimizations to the code.
Unclutter the contents of the main photo stage by placing all your photos in a hidden container you could give an id of "queue" or something similar, making the DOM do the work of storing and ordering the images you are not currently displaying for you. This will also leave the browser only working with two visible images at any given time, giving it less to consider as far as stacking context, positioning, and so on.
Rewrite the code to use an event trigger and bind the fade-in handling to the event, calling the first image in the queue's event once the current transition is complete. I find this method is more well-behaved for cycling animation than some timeout-managed scripts. An example of how to do this follows:
// Bind a custom event to each image called "transition"
$("#queue img").bind("transition", function() {
$(this)
// Hide the image
.hide()
// Move it to the visible stage
.appendTo("#photos")
// Delay the upcoming animation by the desired value
.delay(2500)
// Slowly fade the image in
.fadeIn("slow", function() {
// Animation callback
$(this)
// Add a shadow class to this image
.addClass("shadow")
// Select the replaced image
.siblings("img")
// Remove its shadow class
.removeClass("shadow")
// Move it to the back of the image queue container
.appendTo("#queue");
// Trigger the transition event on the next image in the queue
$("#queue img:first").trigger("transition");
});
}).first().addClass("shadow").trigger("transition"); // Fire the initial event
Try this working demo in your problem browsers and let me know if the performance is still poor.
I had the same problem too. I just preloaded my images and the transitions became smooth again.
The point is that IE is not W3C compliant, but +1 with ctcherry as using css is the most efficient way for smooth transitions.
Then there are the javascript coded solutions, either using js straight (but need some efforts are needed to comply with W3C Vs browsers), or using libs like JQuery or Mootools.
Here is a good javascript coded example (See demo online) compliant to your needs :
var Fondu = function(classe_img){
this.classe_img = classe_img;
this.courant = 0;
this.coeff = 100;
this.collection = this.getImages();
this.collection[0].style.zIndex = 100;
this.total = this.collection.length - 1;
this.encours = false;
}
Fondu.prototype.getImages = function(){
var tmp = [];
if(document.getElementsByClassName){
tmp = document.getElementsByClassName(this.classe_img);
}
else{
var i=0;
while(document.getElementsByTagName('*')[i]){
if(document.getElementsByTagName('*')[i].className.indexOf(this.classe_img) > -1){
tmp.push(document.getElementsByTagName('*')[i]);
}
i++;
}
}
var j=tmp.length;
while(j--){
if(tmp[j].filters){
tmp[j].style.width = tmp[j].style.width || tmp[j].offsetWidth+'px';
tmp[j].style.filter = 'alpha(opacity=100)';
tmp[j].opaque = tmp[j].filters[0];
this.coeff = 1;
}
else{
tmp[j].opaque = tmp[j].style;
}
}
return tmp;
}
Fondu.prototype.change = function(sens){
if(this.encours){
return false;
}
var prevObj = this.collection[this.courant];
this.encours = true;
if(sens){
this.courant++;
if(this.courant>this.total){
this.courant = 0;
}
}
else{
this.courant--;
if(this.courant<0){
this.courant = this.total;
}
}
var nextObj = this.collection[this.courant];
nextObj.style.zIndex = 50;
var tmpOp = 100;
var that = this;
var timer = setInterval(function(){
if(tmpOp<0){
clearInterval(timer);
timer = null;
prevObj.opaque.opacity = 0;
nextObj.style.zIndex = 100;
prevObj.style.zIndex = 0;
prevObj.opaque.opacity = 100 / that.coeff;
that.encours = false;
}
else{
prevObj.opaque.opacity = tmpOp / that.coeff;
tmpOp -= 5;
}
}, 25);
}