metafizzy / isotope

:revolving_hearts: Filter & sort magical layouts
https://isotope.metafizzy.co
11.05k stars 1.41k forks source link

Layout problem when resizing window on a responsive design. #271

Closed gablabelle closed 12 years ago

gablabelle commented 12 years ago

I'm using isotope at http://www.gablabelle.com but I can't figure out what's wrong after reviewing my script file or maybe it's a bug?

When resizing the window the layout is not good. But if I make a relayout using the top right button, the layout gets in order. What's wrong?

Please take a look at this video: http://www.visualise.ca/files/videos/isotope02.mov

jQuery

$(window).smartresize(function(){       
        var $windowSize = $(window).width();
        if ($windowSize > 1199) {
            $container.imagesLoaded( function(){
                $container.isotope({
                    animationEngine: "best-available",
                    itemSelector : "article.post",
                    masonry: {
                        columnWidth: 300,
                        gutterWidth: 30
                    },
                    onLayout: function(){
                        setTimeout(function(){
                            html_height = $container.height();
                            $("#sidebar").height(html_height - 30);
                        }, 500);
                    }       
                });
            });
        } else if ($windowSize < 1200 && $windowSize > 979) {
            $container.imagesLoaded( function(){
                $container.isotope({
                    animationEngine: "best-available",
                    itemSelector : "article.post",
                    masonry: {
                        columnWidth: 240,
                        gutterWidth: 20
                    },
                    onLayout: function(){
                        setTimeout(function(){
                            html_height = $container.height();
                            $("#sidebar").height(html_height - 20);
                        }, 500);
                    }       
                });
            });
        } else if ($windowSize < 768) {
            $container.imagesLoaded( function(){
                $container.isotope({
                    animationEngine: "best-available",
                    itemSelector : "article.post",
                    resizable: false,
                    masonry: {
                        columnWidth: $windowSize / 2,
                        gutterWidth: 1
                    },
                    onLayout: function(){
                        setTimeout(function(){
                            html_height = $container.height();
                            $("#sidebar").height(html_height - 30);
                        }, 500);
                    }   
                });
            });
        } else {
            $container.imagesLoaded( function(){
                $container.isotope({
                    animationEngine: "best-available",
                    itemSelector : "article.post",
                    masonry: {
                        columnWidth: 186,
                        gutterWidth: 20
                    },
                    onLayout: function(){
                        setTimeout(function(){
                            html_height = $container.height();
                            $("#sidebar").height(html_height - 20);
                        }, 500);
                    }   
                });
            });
        };  
    }).smartresize();

CSS

@media (max-width: 767px) {
    article.post {
        margin: 0 0 1px;
    }
    article.small img,
    article.articles img,
    article.long img,
    article.tall img ,
    article.big img {
        width: 100%;
        border-left: solid 1px #161616;
        border-right: solid 1px #161616;
    }
    article.small,
    article.articles,
    article.long,
    article.tall,
    article.big {
        width: 50%;
    }
}
@media (min-width: 768px) and (max-width: 979px) {
    article.post {
        margin: 0 0 20px 20px;
    }
    article.small,
    article.small img,
    article.articles,
    article.articles img {
        width: 166px;
        height: 166px;
    }
    article.long,
    article.long img {
        width: 352px;
        height: 166px;
    }
    article.tall,
    article.tall img {
        width: 166px;
        height: 352px;
    }
    article.big,
    article.big img {
        width: 352px;
        height: 352px;
    }
}
@media (min-width: 980px) and (max-width: 1199px) {
    article.post {
        margin: 0 0 20px 20px;
    }
    article.small,
    article.small img,
    article.articles,
    article.articles img {
        width: 220px;
        height: 220px;
    }
    article.long,
    article.long img {
        width: 460px;
        height: 220px;
    }
    article.tall,
    article.tall img {
        width: 220px;
        height: 460px;
    }
    article.big,
    article.big img {
        width: 460px;
        height: 460px;
    }
}
@media (min-width: 1200px) {
    article.post {
        margin: 0 0 30px 30px;
    }
    article.small,
    article.small img,
    article.articles,
    article.articles img {
        width: 270px;
        height: 270px;
    }
    article.long,
    article.long img {
        width: 570px;
        height: 270px;
    }
    article.tall,
    article.tall img {
        width: 270px;
        height: 570px;
    }
    article.big,
    article.big img {
        width: 570px;
        height: 570px;
    }
}
/**** Start: Recommended Isotope styles ****/
/**** Isotope Filtering ****/
.isotope-item {
  z-index: 2;
}
.isotope-hidden.isotope-item {
  pointer-events: none;
  z-index: 1;
}
/**** Isotope CSS3 transitions ****/
.isotope,
.isotope .isotope-item {
  -webkit-transition-duration: 0.8s;
  -moz-transition-duration: 0.8s;
  -ms-transition-duration: 0.8s;
  -o-transition-duration: 0.8s;
  transition-duration: 0.8s;
}
.isotope {
  -webkit-transition-property: height, width;
  -moz-transition-property: height, width;
  -ms-transition-property: height, width;
  -o-transition-property: height, width;
  transition-property: height, width;
}
.isotope .isotope-item {
  -webkit-transition-property: -webkit-transform, opacity;
  -moz-transition-property: -moz-transform, opacity;
  -ms-transition-property: -ms-transform, opacity;
  -o-transition-property: top, left, opacity;
  transition-property: transform, opacity;
  -webkit-transition-delay: 0s, 0.8s, 0s;
  -moz-transition-delay: 0s, 0.8s, 0s;
  -ms-transition-delay: 0s, 0.8s, 0s;
  -o-transition-delay: 0s, 0.8s, 0s;
  transition-delay: 0s, 0.8s, 0s;
}
/**** disabling Isotope CSS3 transitions ****/
.isotope.no-transition,
.isotope.no-transition .isotope-item,
.isotope .isotope-item.no-transition {
  -webkit-transition-duration: 0s;
  -moz-transition-duration: 0s;
  -ms-transition-duration: 0s;
  -o-transition-duration: 0s;
  transition-duration: 0s;
}
desandro commented 12 years ago

Closing as a personal support request. See https://github.com/desandro/issues-agreement/#readme

Looks like all you're really doing is updating the masonry sizing options on smartresize. We can refactor all of that into something like this:

  var $container = $("#stream");

  // cache jQuery window
  var $window = $(window);

  // start up isotope with default settings
  $container.imagesLoaded( function(){
    $container.isotope({
      animationEngine: "best-available",
      itemSelector : "article.post",
      masonry: {
        columnWidth: 300,
        gutterWidth: 30
      },
      onLayout: function(){
        forceLoad();
        setTimeout(function(){
          html_height = $container.height();
          $("#sidebar").height(html_height - 30);
        }, 500);
      }    
    });
  });

  $window.smartresize(function(){
    var windowSize = $window.width();
    var masonryOpts;
    // update sizing options 
    if (windowSize > 1199) {
      masonryOpts = {
        columnWidth: 300,
        gutterWidth: 30,
      };
    } else if ($windowSize < 1200 && $windowSize > 979) {
      masonryOpts = {
        columnWidth: 240,
        gutterWidth: 20
      };
    } else if ($windowSize < 768) {
      masonryOpts = {
        columnWidth: windowSize / 2,
        gutterWidth: 1
      };
    } else {
      masonryOpts = {
        columnWidth: 186,
        gutterWidth: 20
      };
    }
    $container.isotope({
      masonry: masonryOptions
    }).isotope('reLayout');

  }).smartresize();
gablabelle commented 12 years ago

@desandro ... I'm sorry for the support request... But to me, it's really hard to make the difference between a bug and an implementation problem. Even with your code, the problem still persists. The items do not get into place like they should. :-(

I thought buying a commercial license would allow support. I misread. Is there someway to pay for support?

gablabelle commented 12 years ago

@desandro I'm really sorry to insist but it seems a lot like bug #145 and #171 ... I set up a jsfiddle at http://jsfiddle.net/CNb7r/ to show that when resizing the window (the result panel) you get random or somehow unpredictable result for the layout where a simple refresh or relayout puts everything into place.

1st video of bug #145 and #171 ) http://www.visualise.ca/files/videos/isotope01.mov 2nd video of #271 ) http://www.visualise.ca/files/videos/isotope02.mov

http://jsfiddle.net/CNb7r/ or http://www.gablabelle.com

desandro commented 12 years ago

Hi there!

I'm sorry to hear you're having trouble with Isotope.

You're running into a problem with combining media queries and Isotope. The good news is that this can be mostly resolved. But it will take an honest effort to completely resolve this.

Here's my best try http://jsfiddle.net/desandro/CNb7r/21/ full screen See it with out the images on http://jsfiddle.net/desandro/CNb7r/20/show/light

  1. You need to implement the gutterWidth modification
  2. gutterWidth is added on to columnWidth, so if your image is 270px wide, and you have 30px gutters, then it would be { columnWidth: 270, gutterWidth: 30 }
  3. The gutter mode for Masonry works by adding in the gutters which means you need to take them out of your CSS. This can be done with styles like .isotope article.post { margin: 0 0 20px; }. I also removed the !important just in case
  4. I found that removing the transition styles from the .isotope container helped improve performance, so I removed them.
  5. I implemented Jeremy Keith's Conditional CSS technique to better detect what media query is active.
  6. When the window is in the smallest size, we start running into problems with #222. My hack is just to set the .post width to 49.5%
  7. In the small size, I set columnWidth: $container.width() / 2, using the width of $container not $window.
  8. I set resizable: false, since we trigger it manually on .smartresize.
  9. You'll find that the performance is better in the image-less demo. This is a browser issue. One way to address it is use smaller images.

Hopefully my answer is comprehensive enough to put you on the right track.


Moreover, this issue is an edge case. I don't believe that actual users are constantly resizing their web browsers. Only web designers do that.

gablabelle commented 12 years ago

@desandro I would never got out of this alive by myself! Thank you soooo much! Now the layout works out perfectly at http://www.gablabelle.com/ and I thank you for that!

I know it's not of a big deal but I've added a line to thank you at the top of http://www.gablabelle.com/wp-content/themes/gablabelle/js/script.js

P.S.: 49.9% seems to work also for point number 6 of bug #222.

adoumas commented 12 years ago

Hello,

A solution that i found for responsive-fluid layouts with css animation is to remove the css rules for .isotope and leave the .isotop-item animation.

With JS animation i dont have problem at all.

i use percentage values 16.666%, 25%, 33.333%, 50% or 100% for 6,4,5,2,1 columns

gablabelle commented 12 years ago

@desandro sorry to disturb again... But the layout at http://jsfiddle.net/desandro/CNb7r/21/show/light/ doesn't work in Firefox... Back to square 1 ? :-(

hugolepetit commented 12 years ago

@desandro " I don't believe that actual users are constantly resizing their web browsers". I thought it was true until i ran into users resizing their browser to be able to click on another window of any application so they can switch easily between apps or see a chat window at the same time. Yes they ignore the dock and Yes they ignore Alt+Tab. I don't have numbers to confirm if there are a lot of them though.

desandro commented 12 years ago

See http://jsfiddle.net/desandro/CNb7r/22/show/light/

Turned out to be a problem with the Conditional CSS method. Added:

// fix for firefox, remove double quotes "
mediaQueryId = mediaQueryId.replace( /"/g, '' );
gablabelle commented 12 years ago

@desandro thank you!

@giglemad I resize my browser all the time for web design and as a user also! And I wouldn't be able to see my website break in front of me like that all the time. I'm really really really happy @desandro provided us with a solution! ;-)

gablabelle commented 11 years ago

@desandro we have a problem! the following code ...

var mediaQueryId = getComputedStyle( document.body, ':after' ).getPropertyValue('content');

wont work in IE8 and - because they do not support getComputedStyle. I found a fix but I don't understand how to apply it in your code.

http://jsfiddle.net/desandro/CNb7r/22/ (Your code) http://snipplr.com/view/13523/getcomputedstyle-for-ie/ (The fix)

This is what I tried without success ...

$(document).ready(function(){
    var layoutI = 0;
    var $container = $("#stream");
    var $window = $(window);
    if (!window.getComputedStyle) {
        window.getComputedStyle = function(el, pseudo) {
            this.el = el;
            this.getPropertyValue = function(prop) {
                var re = /(\-([a-z]){1})/g;
                if (prop == 'float') prop = 'styleFloat';
                if (re.test(prop)) {
                    prop = prop.replace(re, function () {
                        return arguments[2].toUpperCase();
                    });
                }
                return el.currentStyle[prop] ? el.currentStyle[prop] : null;
            }
            return this;
        }
    };
    function reLayout(){
        var mediaQueryId = getComputedStyle( document.body, ':after' ).getPropertyValue('content');
        // fix for firefox, remove double quotes
        var mediaQueryId = mediaQueryId.replace( /"/g, '' );
        // console.log( mediaQueryId );
        var windowSize = $window.width();
        var masonryOpts;
        // update sizing options 
        switch ( mediaQueryId ) {
            case 'bigger' :
                masonryOpts = {
                    columnWidth: 270,
                    gutterWidth: 30
                };
            break;
            case 'big' :
                masonryOpts = {
                    columnWidth: 220,
                    gutterWidth: 20
                };
            break;
            case 'medium' :
                masonryOpts = {
                    columnWidth: 166,
                    gutterWidth: 20
                };
            break;
            case 'small' :
                masonryOpts = {
                    columnWidth: $container.width() / 2,
                    gutterWidth: 0
                };  
            break;
        };
        $container.isotope({
            resizable: false, // disable resizing by default, we'll trigger it manually
            itemSelector : "article.post",
            animationEngine: "best-available",
            masonry: masonryOpts,
            onLayout: function() {
            //  console.log('layout!' + (layoutI++) )
                forceLoad();
                setTimeout(function(){
                    html_height = $container.height();
                    $("#sidebar").height(html_height - masonryOpts.gutterWidth);
                }, 500);
            }
        });
    };
    // start up isotope with default settings
    $container.imagesLoaded( function(){
        reLayout();
        $window.smartresize( reLayout );
    });
Pixelous commented 11 years ago

Thanks for the solution, David, really helpfull.

Pixelous commented 11 years ago

gablabelle, just place a code from your link before David's code, nothing more. Works fine for me in IE 9 now.

// Fix for IE, adds getComputedStyle method for the object window and getPropertyValue method for the object, which returns getComputedStyle
    if (!window.getComputedStyle) {
    window.getComputedStyle = function(el, pseudo) {
        this.el = el;
        this.getPropertyValue = function(prop) {
            var re = /(\-([a-z]){1})/g;
            if (prop == 'float') prop = 'styleFloat';
            if (re.test(prop)) {
                prop = prop.replace(re, function () {
                    return arguments[2].toUpperCase();
                });
            }
            return el.currentStyle[prop] ? el.currentStyle[prop] : null;
        }
        return this;
    }
gablabelle commented 11 years ago

@Pixelous Exactly what I did at http://www.gablabelle.com/ without success... Doesn't work in IE8 and -. Using IE-Tester on Windows XP (VirtualBox)

The script is there: http://www.gablabelle.com/wp-content/themes/gablabelle/js/script.js

gablabelle commented 11 years ago

@Pixelous the error: http://www.visualise.ca/files/images/error-isotope01.jpg

ultimatedelman commented 11 years ago

@gablabelle I think I speak for everyone watching this project when I say that this is not a forum for you to fix your specific codebase. That's what StackOverflow is for. This is a place to report issues with the code itself. Every time you post something, all nearly 2300 people get an email about your coding issues. I feel like I get at least 5 emails a day from you. I would prefer not to unstar or unfollow this project, (and I'm sure that @desandro wouldn't like that either) but your constant spamming of this project with your particular problems is getting out of hand.

If there's a legitimate problem with the codebase, by all means, post here. But if you just can't figure something out, please take it to StackOverflow.

Thanks.

Pixelous commented 11 years ago

Sorry, seems it don't work for IE 9 too, will be glad to hear an answer from David. Thanks and sorry for posting so much time. I have found that after pressing F12 on Windows 7 then update the page Masonry layout begin to work. Really strange.

gablabelle commented 11 years ago

@ultimatedelman I was running into a problem with combining media queries and Isotope. Is that a legitimate problem with the isotope codebase? You tell me... @desandro was kind enough to provide US with code that works. I am really grateful. After that I simply reported the bug in Firefox, he corrected it. Following that, I found this IE bug, so I'm reporting it in order to have an improved solution that works will all browsers.

I will not be the only one that will benefit from this thread. We were 5 participants.

I really get your point. But according to the facts that lead me here, I really don't see my thread as the selfish action you described.

ultimatedelman commented 11 years ago

@gablabelle I'm not talking about this thread in particular. You've opened a lot of issues on this project. It appears as though you've discovered a minor bug here. Congrats. However, your path to discovering this, while effective this time, is incorrect for most instances. You didn't know it was a bug when you reported this. You only found out after some digging that should have happened elsewhere.

The typical research path is to first Google the issue. If you can't find anything about it, then go to StackOverflow (usually Google will take you there) and look. If you can't find the answer from searching, try to ask a question. Someone will likely answer it (there are at the time of this writing 297 questions about this library).

It should really only be after this point where all other hope is lost that you should file a ticket with a project. @desandro has been nice enough to answer all your problems personally, but he surely does not have time to be your personal code debugger. He's too busy writing awesome code :) Although, if you have paid for support, that may be another story. I'm not sure how he handles that, but I'm nearly positive it's not through public issues on the project site.

I am sure he appreciates your enthusiasm with this project, as it is a phenomenal library, but you run the risk of making it an unpopular project to follow due to your spamming, unintentional as it may be.

Pixelous commented 11 years ago

Hm, after I have commented this

//console.log( mediaQueryId );

my page with Isotope/Masonry works fine in IE9 now. @ultimatedelman, seems u have problem in IE8 beacuse of this:

// fix for firefox, remove double quotes "
mediaQueryId = mediaQueryId.replace( /"/g, '' );

But to be honest IE8 market share is low now, so, don't worry about it. But your Isotope/Masonry don't work at IE9 too it's because your page still renders like IE7. U need to paste this in the head of your site:

meta http-equiv="X-UA-Compatible" content="IE=9" /

Or Press F12 at IE9 and then choose Document Mode: Standard IE9, then u will see that everything is work in IE9.

gablabelle commented 11 years ago

I get your point and I'm sorry for the inconvenience... But the truth is I only created 4 threads over the last 7 months. So no... you're not getting 5 e-mails a day from me (Except for today I guess). 2 were bugs, for the 2 others, yes I agree, I could of done better. And yes questions were previously asked on stackoverflow. See my isotope question on stackoverflow here:

http://stackoverflow.com/search?q=user%3A534369+isotope

This is the stackoverflow question linked to this thread:

http://stackoverflow.com/questions/12589842/messed-up-layout-with-isotope-in-a-responsive-web-design

So @ultimatedelman ... I suggest we talk less about my "Disorderly conduct" and more about a solution for #271 that works great in all browsers. ;-)

@Pixelous It works OK on IE9 but not in IE8 and -. I get the 'null' is null or not a object when the getComputedStyle IE fix code is included.

desandro commented 11 years ago

slow clap

Thank you @ultimatedelman


@gablabelle You have identified an IE8 pitfall with the Conditional CSS technique. This is a separate issue from Isotope. So you're on your own at this point. I would point out that IE8 does not support media queries, so you're going to have to account for that. Best of luck.

gablabelle commented 11 years ago

@desandro @Pixelous Here is the solution that also works in IE8 and under:

Instead of putting the values we want to catch in the CSS we use jQuery. They end up in the DOM and can be manipulated more easily. Hope it helps! ;-)

jQuery:

    $(document).ready(function(){
        var layoutI = 0;
        var $container = $("#stream");
        var $window = $(window);
        function windowSizeMe(){
            var windowSize = $window.width();
            if (windowSize > 1199) {
                $("#switch").attr("data-content", "bigger");
            } else if (windowSize < 1200 && windowSize > 979) {
                $("#switch").attr("data-content", "big");
            } else if (windowSize < 768) {
                $("#switch").attr("data-content", "small");
            } else {
                $("#switch").attr("data-content", "medium");
            };
        }; 
        function reLayout(){
            windowSizeMe(); 
            var mediaQueryId = $("#switch").attr("data-content");
            console.log(mediaQueryId);
            // fix for firefox, remove double quotes
            var mediaQueryId = mediaQueryId.replace( /"/g, '' );
            var masonryOpts;
            // update sizing options 
            switch ( mediaQueryId ) {
                case 'bigger' :
                    masonryOpts = {
                        columnWidth: 270,
                        gutterWidth: 30
                    };
                break;
                case 'big' :
                    masonryOpts = {
                        columnWidth: 220,
                        gutterWidth: 20
                    };
                break;
                case 'medium' :
                    masonryOpts = {
                        columnWidth: 166,
                        gutterWidth: 20
                    };
                break;
                case 'small' :
                    masonryOpts = {
                        columnWidth: $container.width() / 2,
                        gutterWidth: 0
                    };  
                break;
            };
            $container.isotope({
                resizable: false, // disable resizing by default, we'll trigger it manually
                itemSelector : "article.post",
                animationEngine: "best-available",
                masonry: masonryOpts,
                onLayout: function() {
                //  console.log('layout!' + (layoutI++) )
                    forceLoad();
                    setTimeout(function(){
                        html_height = $container.height();
                        $("#sidebar").height(html_height - masonryOpts.gutterWidth);
                    }, 500);
                }
            });
        };
        // start up isotope with default settings
        $container.imagesLoaded( function(){
            reLayout();
            $window.smartresize( reLayout );
        });
    });

HTML (can be added anywhere):

    <span id="switch"></span>

CSS (I don't think the media queries part is mandatory since we set these using jQuery above):

    #switch {
        display: none;
    }
    /**** Media queries ****/
    @media (max-width: 767px) {
        #switch:after {
            content: attr(data-content) "small";
        }
    }
    @media (min-width: 768px) and (max-width: 979px) {
        #switch:after {
            content: attr(data-content) "medium";
        }
    }
    @media (min-width: 980px) and (max-width: 1199px) {
        #switch:after {
            content: attr(data-content) "big";
        }
    }
    @media (min-width: 1200px) {
        #switch:after {
            content: attr(data-content) "bigger";
        }
    }
Pixelous commented 11 years ago

gablabelle, thanks for the solution.

EUPRAXIA1 commented 10 years ago

@gablabelle Don't worry about @ultimatedelman sometimes it's just best to not feed the trolls. I appreciate that you asked the question as I was having a similar problem and I (as you did) I appreciate very much the effort Desandro put into fixing this issue. If somebody like edelman wants to judge you differently from the facts and call you out because he values nobody else's issues but his own just let that roll off your back like water off of a duck; his behavior is his fault, not yours.