どうやらこれは石積みや同様の解決策で消えない問題であるため、私はここで自分自身を転がす必要があると判断しました。また、デフォルトのフロートDIVには多くの状況で大きなギャップがあるため、これはPHPでより適切に処理されると判断しました。
これが私が使用したアルゴリズムであり、細かい点を説明するコメントが付いています。これは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.
}