0

I HAVE UPDATED WITH FIDDLES, SEE BOTTOM

I am developing a wordpress theme to work on iphone and ipads and other webkit devices.

I am using media queries to change the width of divs depending on the size and orientation of the device.

These divs however float left, to fill the device screen.

My problem is that the floated div's height are variable. And the div's which are higher than some, are causing gap issues on the floated elements.

I need possible advice on a fix so there are never any gaps, and elements always float, even if there is a higher div in its path.

Is there a possible way of equalizing the div heights to the highest div, the only problem with this is that it need to work with orientation changes on iPad. On iPhone it's not so bad because there is only one column. But on iPad, portrait has 2 columns and landscape has 3 columns.

Please see diagram below explaining my issue.



Diagram



CURRENT CSS

/* GLOBAL STYLE ( which iPhone uses first - 1 column ) ----------- */

.module {
    display: block;
    overflow: hidden;
    width: 100%;
    float: left;
}

/* IPADS (PORTRAIT - 2 column ) ----------- */
@media only screen
and (min-device-width : 768px)
and (max-device-width : 1024px)
and (orientation : portrait) {

    .module {
        width: 50%;
    }

}

/* IPADS (LANDSCAPE - 3 Column ) ----------- */
@media only screen
and (min-device-width : 768px)
and (max-device-width : 1024px)
and (orientation : landscape) {

    .module {
        width: 33.33%;
    }

}

BASIC MARKUP

<div>

    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>

</div>





UPDATE - I HAVE CREATED PURE CSS FIDDLES TO SIMULATE MY PROBLEM


The fiddle below simulates SMARTPHONES (PORTRAIT AND LANDSCAPE) - ONE COLUMN

See style .module - width: 100% which simulates the appearance of this @media query

@media only screen
and (min-device-width : 320px)
and (max-device-width : 480px)

http://jsfiddle.net/motocomdigital/kdgnP/1/


The fiddle below simulates IPADS (PORTRAIT) - TWO COLUMN

See style .module - width: 50% which simulates the appearance of this @media query

@media only screen
and (min-device-width : 768px)
and (max-device-width : 1024px)
and (orientation : portrait) {

http://jsfiddle.net/motocomdigital/kdgnP/2/


The fiddle below simulates IPADS (LANDSCAPE) - THREE COLUMN

See style .module - width: 33.33% which simulates the appearance of this @media query

@media only screen
and (min-device-width : 768px)
and (max-device-width : 1024px)
and (orientation : landscape) {

http://jsfiddle.net/motocomdigital/kdgnP/3/


mskfisher
  • 3,291
  • 4
  • 35
  • 48
Joshc
  • 3,825
  • 16
  • 79
  • 121
  • You need to position them absolutely and calculate positions by hand with javascript. See http://stackoverflow.com/questions/7109362/how-to-replicate-pinterest-coms-absolute-div-stacking-layout – Esailija Jan 25 '12 at 13:14

3 Answers3

1

Like I said in a comment, you need to calculate this in javascript and use absolute positioning. Here is an example:

http://jsfiddle.net/rJxtm/4/

//Generate random height for each module, normally this doesn't need to be done because
//they have various amounts of contents in a real app.
$(".module").each(function(i) {
    var height = (150 + (Math.random() * 100 | 0));
    this.style.height = height + "px";
});


$(window).bind("orientationchange resize", function(e) {
    var modules = $(".module"),
        columnWidth = modules[0].offsetWidth,
        margin = 10,
        parentWidth = $(".modules").width(),
        fits = Math.floor(parentWidth / (columnWidth + margin * 2)),
        columnHeights = {},
        i;

    for (i = 0; i < fits; ++i) {
        columnHeights[i] = 0;
    }

    function getTop(i) {
        var nColumn = i % fits;
        return columnHeights[nColumn];
    }

    modules.each(function(i) {
        var height = this.offsetHeight, //Now I am just retrieving the height
            nColumn = i % fits;

        this.style.left = ((columnWidth + margin) * nColumn) + "px";
        this.style.top = getTop(i) + "px";
        columnHeights[nColumn] += (height + margin);
    });

}).trigger("resize");
Esailija
  • 138,174
  • 23
  • 272
  • 326
  • Thanks for taking the time to do a jsfiddle. Though as soon as I add position absolute to my .module - my contain div collapses. If I did get this to work, do you think it will work on @media orientation from landscape to portrait? My containing div width is 100%, the 768px is maybe causing it not to work. – Joshc Jan 25 '12 at 13:59
  • @user801773 to do this you'd need to react to orientation dynamically in javascript (`"onorientationchange"`, `"onresize"`) and recalculate and reposition everything (well just the module containers) in javascript. The parent having `100%` width is not a problam, you just need to retrieve the parent width dynamically every time something changes. In this example, it was set to static `768`, but I could have done `parentDiv.offsetWidth` as well. With position `absolute`, all positional calculations are left to you and css won't do anything for you. – Esailija Jan 25 '12 at 14:03
  • This is tricky for me, I will try and persist. It's bizarre how something so simple cant be solved with CSS. I'm struggling to get my head round javascript orientation change, surely javascript orientation changes must have to reload the page to make the necessary DOM changes, no? CSS @media orientations are so much simpler for me to understand, and are full proof across webkit :/ – Joshc Jan 25 '12 at 14:33
  • @user801773 No they don't require pagereload, they are just events. I can resize my window right now without having to reload page. – Esailija Jan 25 '12 at 14:37
  • how do you write orientationchange script, I can't find much on how to add it to your script? – Joshc Jan 25 '12 at 16:32
  • @user801773 See here: http://jsfiddle.net/rJxtm/3/ Just try to resize the lower right window and see how they reposition automatically. I even put 100% width to the parent node. I simply just bound the events using jQuery... – Esailija Jan 25 '12 at 17:19
  • @user801773 btw do not use the code verbatim, it is generating heights randomly. In real app you would retrieve real height of each module instead of generating it. – Esailija Jan 25 '12 at 17:24
  • Right I'm with ya I think, really appreciate your time on this. So where it says modules.each, should I use something like this... var moduleHeight = $(this).find('.module').height(); ? – Joshc Jan 25 '12 at 17:31
  • I've tried to get your script working, but the absolute positioning is throwing my layout out. I'm not using fixed headers or footers. I've attached 3 fiddles at the bottom of my question, simulating iPhone, iPad portrait/landscape with my layout. I've included some dummy content so no need for random math. I'm really intrigued if your idea will work but I can't seem to figure it out, the absolute positioning throws everything off. Thanks for your help. – Joshc Jan 26 '12 at 00:20
  • @user801773 see http://jsfiddle.net/kdgnP/4/ and http://jsfiddle.net/kdgnP/5/ I modified .modules and .module css in both and added the code with `margin = 0,`. I have jQuery there btw. Now there is a problem with footer since absolute positioned elements don't take space. – Esailija Jan 26 '12 at 00:34
  • @user801773 I solved the footer problem here (and only here) http://jsfiddle.net/kdgnP/7/ – Esailija Jan 26 '12 at 00:39
  • WOW - Seriously slick, works amazing!!! I get a log on debug iOS console, 1 on load, then another 2 everytime I rotate. Does not say much in the log tho... I think I can live with it because it works too good. Big thank you!!! – Joshc Jan 26 '12 at 00:54
  • @user801773 just remove the `console.log` call from the javascript code. :P – Esailija Jan 26 '12 at 10:59
0

This cannot be sloved simply by float - only option is to make all this modules same sized ( or add some margin for smaller ones )

SergeS
  • 11,533
  • 3
  • 29
  • 35
  • it uses javascript to fit all the boxes ( it is easly visible if you scroll fast, then new boxes will not appear immediatly ) - and it fill columns, not rows I assume – SergeS Jan 25 '12 at 13:15
  • Looked at DOM, and they uses position: absolute – SergeS Jan 25 '12 at 13:16
  • Yeah I saw that, but maybe @Esailija method is doing something similar, but when I add position absolute to the .module div, my containing div callapses to nothing (as it would do if you position anything absolute) – Joshc Jan 25 '12 at 14:10
  • Esalija and Eliseu method both uses scripts to fit it all - it is only alternative solution. But most stable solution is to simply make all heights same, so it will float. Position absolute causes some lags with width in percents AFAIK – SergeS Jan 25 '12 at 15:40
  • another solution is to make columns and fill them using javascript ( using removeChild / appendChild ) – SergeS Jan 25 '12 at 15:41
  • It's a shame but I think I got to make fixed heights. Is the there away of styling list li's incrementally> The modules don't have to be divs. – Joshc Jan 25 '12 at 16:46
0

You can use JavaScript to set equal height to all of them.

This is the minified jQuery plugin:

(function(a){a.fn.equalHeight=function(){var b=0;this.each(function(){var c=a(this).height();c>b&&(b=c)});this.each(function(){a(this).height(b)})}})($);

And you can use like that:

$('#modules').children().equalHeight();

Another good solution would be CSS display table. Take a look at this post: http://css-tricks.com/fluid-width-equal-height-columns/

  • Tried this, it works, but screws up on orientation. Guess because this is dom related. Thanks anyway – Joshc Jan 25 '12 at 13:39
  • What you mean? The orientation change event? Try this (jQ 1.7+, use .bind for others): $(document).on('orientationchange', function() { $('#modules').children().equalHeight(); }); – Eliseu Monar dos Santos Jan 25 '12 at 13:45
  • @media orientation - Ok I will have a go. – Joshc Jan 25 '12 at 13:56
  • $(window).bind("orientationchange resize", function(e) { $('#modules').children().equalHeight(); }).trigger("resize"); I've tried this, but on orientation change, it doesn't update, it uses the original heights from page load. – Joshc Jan 26 '12 at 00:38