Jquery Cycle + Firefox Squishing Images
Asked Answered
S

7

6

I am running jQuery Cycle for an image gallery. View the link: Here

My problem is that the images are getting squished when viewed in firefox. The problem disappears when I re-load the page. This leads me to believe that the Javascript is triggering before all the images are loaded (usually the first image works fine and the rest are squished.)

A hard re-fresh reproduces the problem.

I've wrapped everything in a $(document).ready(function(){ }); but it still happens.

Additional Info: If I specify the width and height of the image, everything works fine. However there are hundreds of images all at different sizes..

I'm pretty frustrated with this problem. Any ideas/help is greatly appreciated!

Here is my code:

$(document).ready(function(){
//function onBefore(curr,next,opts) {
//    var $slide = jQuery(next);
//    var w = $slide.outerWidth();
//    var h = $slide.outerHeight();
//    $slide.css({
//        marginTop: (482 - h) / 2,
//        marginLeft: (560 - w) / 2
//    });
//};

// Decare the function that center the images...
function onBefore(curr,next,opts) {
    var $slide = jQuery(next);
    var w = $slide.outerWidth();
    var h = $slide.outerHeight();
    $slide.css({
        marginTop: (480 - h) / 2,
        marginLeft: (560 - w) / 2
    });
};


$(document).ready(function() {
    $('#slideshow').cycle({
     fx:     'fade', 
    next:   '#next', 
    pause: 0,
    speed: 500,
    before: onBefore,
    prev:   '#prev',
    pause:  '#pause',
    pager:  '.thumbs',
    pagerClick:function(zeroBasedSlideIndex, slideElement) {$(slideElement).find('div.cover').hide();},
    pagerAnchorBuilder: function(idx, slide) {
                        var src = $('img',slide).attr('src');
                        //Change height of thumbnail here
                         return '<li><a href="#"><img src="' + slide.src + '" height="90" /></a></li>'; 
                    
                } 
    });});});
Selfdiscipline answered 12/11, 2009 at 2:13 Comment(0)
R
12

There is a much simpler and cleaner solution that I used to solve this problem than what has already been proposed:

Using jQuery, you need to use $(window).load instead of $(document).ready for your particular situation. To fix the issue, change this:

$(document).ready(function() {
  $('#slideshow').cycle({
    /* ... */
  });
});

To this:

$(window).load(function() {
  $('#slideshow').cycle({
    /* ... */
  });
});

Why does this work? Because window.onload fires after all referenced images on the page are loaded (See https://developer.mozilla.org/en/DOM/window.onload, and .load() - jQuery API), which is the desired behavior in your situation. $(document).ready, better known as "DOM Ready", will fire before images have loaded. This is typically the desired behavior, but in your situation it's too early.

Rhodia answered 9/2, 2012 at 20:15 Comment(0)
H
4

I had the same problem when working on a site several months ago (linked below). If you're starting cycle in $(document).ready(), here's what happens when a client browses to your page:

1) The client's browser sends a request for each img element. Those requests take variable amounts of time to fulfill.

2) Before the image requests are completed, cycle starts. Cycle works by hiding all but the first image in the slide show: it sets visibility:hidden and display:none on each of its images.

The problem is that Firefox fixes the img element's size once and for all at the point the display style is set to none. So if the image hasn't finished loading, its height and width style attributes are small (I'm not sure exactly what they correspond to - perhaps the size of Firefox's image placeholder). When cycle shows the image by setting its style attribute to display:block, it uses whatever dimensions it had at the time it was hidden.

I solved this by changing my code so that it doesn't start the cycle plugin until all the images are finished loading. To do that, I initialize a counter variable to the number of images I'm cycling, then bind a load event to each image like this:

var imagesRemaining = 12; // 12 is just the number of images in the slideshow div

$(document).ready(function() {
    $('#slideshow > img').bind('load', function(e) {
        imagesRemaining = imagesRemaining - 1;
        if (imagesRemaining == 0) {
            // I'm doing some other stuff when initializing cycle
            startCycle();
            // My images all start with visibility:hidden so they don't show
            // before cycle hides them in a 'stack', so ...
            $('#slideshow > img').css('visibility', 'visible');
        }
    });
});

function onBefore(curr, next, opts) { // Your code here ... }

function startCycle() {
    $('#slideshow').cycle({ ... // your initialization here });
}

You can see it in action by viewing the galleries on this site in Firefox. I'm building the gallery pages dynamically, so it's structured a bit differently than your page, but you can see more details if you poke around with Firebug.

Hangchow answered 12/11, 2009 at 2:28 Comment(1)
I'm somewhat new to Jquery, how would I implement this?Selfdiscipline
O
2

I'd also like to add that it seems adding a width and height attribute solves this problem.

Overrun answered 10/12, 2009 at 7:11 Comment(0)
N
1

Ok i know its probably an awfull way of calling load but i just coulnd bind my cycle code to .load for some reason it just don't work so i called the whole Cycle initializer inside the ...

i couldn't force the sizes since i'm cycling through li containing dynamic images and data

its probably flawed at some extend but for those as desperated as me...

Nickola answered 5/12, 2010 at 14:46 Comment(0)
C
0

If you're using a database to populate the slideshow you could try accessing the image dimensions from the image itself.

For example, using django you can use

 width="{{ xxx.image.width }}px"  height="{{ xxx.image.height }}px" 

in your img tag.

Caraway answered 11/2, 2010 at 13:24 Comment(0)
C
0

Josh, your solution has just saved me a headache, thank you very much!

I think i've amended it slightly in order to handle pages where you don't know the total number of images. It seems to be working fine for me, if anyone can see any flaws, please point them out - i'm still learning.

$(document).ready(function () {
    $('#slideshow > img').each(
        function go() {
            $(this).bind('load', function (e) {
                projects();
                $('#slideshow > img').css('visibility', 'visible');
            });
         });
    });

function projects() {
    $('#slideshow').cycle({
        fx: 'scrollHorz',
        speed: 300,
        timeout: 0,
        next: '#next ',
        prev: '#prev ',
        after: onAfter,
        nowrap: 1,
        autostop: 1 
    });
}
Colly answered 4/7, 2011 at 9:26 Comment(0)
T
0

You can use a solution similar to making youtube videos responsive. You need to know the ratio of your width to height, and add that as padding-bottom to the cycling div. For my 1024X680 photos, I used 680/1024 = 66.4%

In your case, I believe

#slideshow{ padding-bottom:66.4%; } will show the image unshrunk. I have no idea what the actual height and width values you are working with, so substitute your own. I had to use this solution when the $(window).load solution proved maddeningly ineffective -- so now I use both.

This is better than setting the dimensions of the image, because it's slides into a fluid, responsive enviroment.

Toxoid answered 18/2, 2015 at 1:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.