This may be hard to explain without seeing the result, so please have a look at these examples:
JSFiddle Example 1 - looks okay
JSFiddle Example 2 - broken
Code from fiddles:
HTML:
<ul id="homepage-grid">
<li id="tile11" class="col1 row1 sizex1 sizey1">
<a href="#" title="test">
<img src="http://placehold.it/295x160" alt="test" title="test" style="width: 295px;height: 160px" />
</a>
</li>
<li id="tile8" class="col2 row1 sizex2 sizey1 last">
<a href="#" title="test">
<img src="http://placehold.it/602x160" alt="test" title="test" style="width: 602px;height: 160px" />
</a>
</li>
<li id="tile1" class="col1 row2 sizex1 sizey1">
<a href="#" title="testing">
<img src="http://placehold.it/295x160" alt="testing" title="testing" style="width: 295px;height: 160px" />
</a>
</li>
<li id="tile4" class="col2 row2 sizex2 sizey1 last">
<a href="#" title="test3">
<img src="http://placehold.it/602x160" alt="test3" title="test3" style="width: 602px;height: 160px" />
</a>
</li>
<li id="tile10" class="col1 row3 sizex1 sizey2">
<a href="#" title="test">
<img src="http://placehold.it/295x332" alt="test" title="test" style="width: 295px;height: 332px" />
</a>
</li>
<li id="tile12" class="col2 row3 sizex1 sizey2">
<a href="#" title="test">
<img src="http://placehold.it/295x332" alt="test" title="test" style="width: 295px;height: 332px" />
</a>
</li>
<li id="tile2" class="col3 row3 sizex1 sizey1 last">
<a href="#" title="testing2">
<img src="http://placehold.it/295x160" alt="testing2" title="testing2" style="width: 295px;height: 160px" />
</a>
</li>
<li id="tile9" class="col3 row4 sizex1 sizey1 last">
<a href="#" title="test">
<img src="http://placehold.it/295x160" alt="test" title="test" style="width: 295px;height: 160px" />
</a>
</li>
</ul>
CSS:
#homepage-grid {
width:910px;
position:relative;
padding:0;
overflow: hidden;
}
#homepage-grid li {
list-style:none;
float:left;
padding:0 12px 12px 0;
display:block;
}
#homepage-grid li.last {
list-style:none;
float:left;
padding:0 0 12px 0;
}
#homepage-grid li a {
display:block;
}
Basically what I want to create is a dynamic grid, which is populated by a database (the database part works fine at the moment). In the grid, each tile can span up to 3 columns wide, however can span unlimited rows, which seems to be where I'm running into the problems.
I'm having trouble with the HTML/CSS for something so dynamic. As you can see, one small change from example 1 to example 2 and it broke most of the grid as the bottom left tile should be pushed up to fill the space, and the right tile should be moved up to fill that space.
However, I have full control over the code, so the HTML/CSS can change as I need it to (i.e. to add classes/inline styles/etc).
I guess this would work (relatively) easily using tables, but since it's not tabular content, I don't really want to go down that path.
Would there be a way to make the CSS this dynamic?
Would I need to use more inline styles to achieve this?
Should I be doing it in another way, e.g. absolutely positioning instead of floating?
Any help on how to achieve this would be appreciated.
My first thought was just to set the height
of #title12
to 160px
, but this doesn't work if the element below it is the same width
.
Instead, you might try the following:
Assuming each "row" of your grid has a fixed height, wrap it with a <div>...</div>
or a similar block element, with height:160px;
(or whatever size is appropriate, but make it the same for every div
"row").
Fill the first row with the first row of images. For the second (and subsequent) rows, determine if each "cell" is overlapped by the row before it. If so, add a "filler" block consisting of an empty block element with height
and width
equal to the row and column sizes you desire.
This allows the <li>...</li>
item(s) to overflow the div
"row" into the one(s) below (since overflow is set to visible
by default). The empty block elements prevent the next row from overlapping the overflow from the previous one.
The disadvantages to this approach are:
EDIT: Also, <div>
isn't allowed within a list, so you would need to start/stop your list within each row. Alternately, perhaps use the <ul> </ul>
as rows instead of <div>
.
You're going to run into this problem with floats. However, you can change the positioning of one element on that page, and everything will fall into place like you expect.
Updated Fiddle
Add the following to your CSS:
#homepage-grid li#tile10 {
position: absolute;
top: 342px;
}
This is breaking the offending element out of document flow, thus eliminating the reservation on vertical space being assigned to it by the "float" applied to the rest of the list items. The last item is floated right, so will not overlap the absolutely positioned tile.
EDIT
Per the comments below, here's a slightly more flexible way of doing this. The example works for the posted code.
Assumptions made with the updated fiddle:
position: absolute
from being applied unnecessarily to certain elements
What this does:
This CSS sets different rules based on the existence of siblings with certain classes. This is why the constancy of the sizex1 sizex2 sizey1
and sizey2
values are important.
The CSS:
#homepage-grid li.col1:not(.row1):not(.row2) {
position: absolute;
}
#homepage-grid li.col1.sizey1.row1 ~ li.col1.row2 { /* The first column of the first row has a sizey of 1 */
top: 172px;
}
#homepage-grid li.col1.sizey2.row1 ~ li.col1.row2{ /* The first column of the first row has a sizey of 2 */
top: 342px;
}
#homepage-grid li.col1.sizey1.row1 ~ li.col1.sizey1.row2 ~ li.col1.row3 { /* The first column of the first row has a sizey of 1 and the first column of the first row has a sizey of 1 */
top: 344px;
}
#homepage-grid li.col1.sizey2.row1 ~ li.col1.sizey2.row2 ~ li.col1.row3{ /* The first column of the first row has a sizey of 2 and the first column of the second row has a sizey of 2 */
top: 684px;
}
#homepage-grid li.col1.sizey2.row1 ~ li.col1.sizey1.row2 ~ li.col1.row3,
#homepage-grid li.col1.sizey1.row1 ~ li.col1.sizey2.row2 ~ li.col1.row3 { /* The first column of the first row has a sizey of 2 and the first column of the second row has a sizey of 1, or vice versa */
top: 514px;
}
Ideally, you'd want to set the #homepage_grid li.col1
value at page delivery. That way, you can pick and choose which tiles are broken out of document flow to preserve correct spacing. I'd normally accomplish this by using the :not()
selector, but if you're looking for older browser compatibility, you could just as easily use an override.
Example:
#homepage-grid li.col1:not(.row1):not(.row2) {
position: absolute;
}
*The above will only break rows 3 and greater out of the document flow.
#homepage-grid li.col1 {
position: absolute;
}
#homepage-grid li.col1.row1, #homepage-grid li.col1.row2 {
position: static;
}
This accomplishes the same thing as above, but is more verbose. However, it will render appropriately in less standards-compliant browsers.
EDIT 2 Just for clarity's sake, here's an example using jQuery to set the appropriate elements as static on page load.
Another fiddle example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With