显然这是 Masonry 和类似解决方案的一个不可磨灭的问题,我决定我需要在这里推出自己的解决方案。我还决定这会在 PHP 中更好地处理,因为默认的浮动 DIV 在很多情况下会有很大的差距。
这是我使用的算法,并带有注释来解释细节。这也可以在 jQuery 中轻松完成,但不利的一面是,对于没有 JavaScript 的用户来说,它看起来很讨厌。
$LeftPos = 0; //Tracks where we are on the grid. Our item grid is three wide, but some items may use up to three units of space.
$j = 0; //Using a second counter to track total iterations. This is to prevent infinite loops, either because of future concerns I can't predict or because of someone setting a content block to be wider than the containing grid.
for ($i = 0; $i < sizeOf($Items); $i++){
if ($LeftPos == 3){ $LeftPos = 0; } //If we filled the third column on the last iteration, we loop back round.
if ($Items[$i]['Placed'] !== true){ //If we've already put this object into the new array, skip it.
if ($Items[$i]['SpanWidth'] + $LeftPos <= 3 || $j > (sizeOf($Items) * 3)){ //If inserting this would push us past the third column, save it for when we have more room. But if we've looped over the entire array three times, chances are we're stuck for some reason so just vomit everything out so the user can look at SOMETHING, even if it's an ugly page.
$Placed++; //Increment the counter for placed objects.
$Items[$i]['Placed'] = true; //Set this item as placed, too.
$NewProducts[$i] = $Items[$i]; //Add the current item to the new array.
$LeftPos = $LeftPos+ $Items[$i]['SpanWidth']; //And calculate our new position on the grid.
}
}
if (($i+1 == sizeOf($Items) && $Placed < sizeOf($Items))) {$i = 0;} //If we reach the end and we have placed less items than we have total, loop through again.
}