Responsive layout, variable-dimension CSS table?

I’m working on a responsive layout that displays some <div> boxes, ungrouped in the source, as part of a rectangular grid:

http://sl.cosd.com

Each of the boxes on this front page has this HTML structure:

<div class="control">
<div class="controlContent">
<a>SOME VARIABLE-HEIGHT CONTENT including an image which might float</a>
</div>
</div>

The control divs assign the boxes percentage widths to at first the whole, then 1/2 or 1/3 the screen width, so they double & triple up into rows as the screen size is increased. The controlContent divs assign properties like padding, margin, background, border-radius, etc.

I have imagined this as a linear flow of content (which will be read by screenreaders in source order), to be displayed via CSS like a table. I know CSS2.1 allows elements to be assigned properties like:

display: table;
display: table-row;
display: table-cell;

My main problem: I have assigned display: table-cell to these elements (via the controlContent div) which prevents margin collapse inside the content but does not provide a uniform height to the cell-like divs. I need a way for all siblings on the same row to have matching height.

The smaller cells have gaps below them where the gradient background only covers the box height of the cell. (Worse, the text after this array of cells sometimes fills into these gaps: another problem that could be fixed with presentation markup, though one which will probably go away when the first problem is fixed.)

I think I understand the basics of the problem: each <div> which I have told to behave like a table cell has nothing to match its height to, since I have no way of grouping elements into a containing <div> to which I can assign the display: table-row property, since this grouping changes according to CSS media queries.

In my reading about the problem I’ve heard of “anonymous table boxes” and “anonymous table rows” being created but don’t know how to use them in this case. Since I’m using the CSS :nth-child() selectors to clear the floating boxes at the end of each row, I’d hoped I could use these selectors to establish a new table row at every such point… but how?

I’m not married to any particular solution. I’d just like to know the best-practice way of doing this. I’m hoping to find a solution that doesn’t involve presentation markup, especially considering that a general solution should provide a responsive variable-dimension table for any number of boxes, not just a small, easily factorable number like 6.

Looking forward to your input & hoping I have missed something simple and straightforward.

Hi rphair. Welcome to the forums. :slight_smile:

Display-table sounds like the best bet, though it’s tough if you can’t wrap the rows in divs. One thing you could try is

.control {
  display: inline-block;
  vertical-align: top;
}

It will align the boxes nicely, but not equalize their heights. You could set a min-height on them to help with this. For example:

<!DOCTYPE html>
<html lang="en">

<head>

<meta charset="utf-8">

<title>Experiment</title>
	
<style media="all">
.wrap {width: 900px; margin: 0 auto;}
.wrap div {width: 30%; display: inline-block; background: yellow; vertical-align: top; min-height: 200px;}
.wrap div + div {background: green;}
.wrap div + div + div {background: orange;}
.wrap div + div + div + div {background: red;}
.wrap div + div + div + div + div {background: blue;}
.wrap div + div + div + div + div + div {background: violet;}
</style>
	
</head>

<body>

<div class="wrap">
	<div>
		<p>This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. </p>
	</div>
	
	<div>
		<p>This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. . </p>
	</div>
	
	<div>
		<p>This is text. This is text. This is text. </p>
	</div>
	
	<div>
		<p>This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. </p>
	</div>
	
	<div>
		<p>This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. This is text. </p>
	</div>
	
	<div>
		<p>This is text. This is text. This is text. This is text. This is text. </p>
	</div>
</div>

</body>

</html>

We do have some experts here who probably have a real solution for this: @Paul_O_B and @Rayzur.

thanks for the suggestion, Ralph; I can’t follow it in this case because:

  1. the layout is responsive and the typical box heights may vary substantially depending upon screen width
  2. the site itself is a CMS and the client will be free to change the box content, possibly going beyond the size boundaries that I have assumed.

I’d still like to find a general solution for this & look forward to what your mates would think. I certainly can learn from such expertise. For now I’m going to apply rounded corners to the boxes and separate them since I think it will be fine for this layout, just having the top edges line up.

But I’m also thinking of mobile apps in the future where one might want to tile a box with responsively sized active areas, all equally-sized. It would be wonderful to have a standards-compliant way of doing that.

there is also some related discussion on this page, my posting of the same problem… css table, varying dimensions

Hi,

You can’t really do it with css (yet) although flexbox in css3 may be useful when it is finalised. The display:table wont work as it only works for rows and not wrapping cells. In the end you may need to add a little jquery to equal the heights out.

You can make it appear to work like this but is very contrived.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style type="text/css">
.outer {
	width:70%;
	margin:auto;
	list-style:none;
	position:relative;
	overflow:hidden
}
.outer li {
	width:24%;
	margin:5px 1% 5px 0;
	float:left;
	position:relative;
	border-top:1px solid #fff;
}
.outer li:nth-of-type(4n+1) { clear:left; }
.outer li:before {
	content:"";
	position:absolute;
	display:block;
	width:100%;
	background:blue;
	height:999em;
	border-top:1px solid #fff
}
.box {
	position:relative;
	z-index:2;
	padding:10px;
}
.outer li:hover:before { background:red }
 @media only screen and (max-width: 920px) {
.outer li { width:32% }
.outer li:nth-of-type(4n+1) { clear:none; }
.outer li:nth-of-type(3n+1) { clear:left; }
}
 @media only screen and (max-width: 620px) {
.outer li { width:48% }
.outer li:nth-of-type(4n+1) { clear:none; }
.outer li:nth-of-type(3n+1) { clear:none; }
.outer li:nth-of-type(2n+1) { clear:left; }
}
</style>
</head>

<body>
<ul class="outer">
		<li>
				<div class="box">test</div>
		</li>
		<li>
				<div class="box">test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">test</div>
		</li>
		<li>
				<div class="box">test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">test</div>
		</li>
		<li>
				<div class="box">test</div>
		</li>
		<li>
				<div class="box">test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">test</div>
		</li>
		<li>
				<div class="box">test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">test</div>
		</li>
		<li>
				<div class="box">test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">test</div>
		</li>
		<li>
				<div class="box">test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">test</div>
		</li>
		<li>
				<div class="box">test</div>
		</li>
		<li>
				<div class="box">test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">test</div>
		</li>
		<li>
				<div class="box">test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
</ul>
</body>
</html>

dear Paul: thanks for checking in. That’s a really interesting approach & I appreciate the thought & presentation. I will definitely keep it on hand, though the layout currently calls for top-to-bottom CSS gradients in the cells… if the total height of the row is 999em then that would make the displayed portion of the gradient almost imperceptible (?).

From an artistic point of view, after I tentatively decided to live with the empty space: with variably sized elements, extra space has to exist no matter what, and who’s to say whether it looks better inside or outside the cell? Anyway I’ve added finishing CSS code to my simpler layout and the result is back on the original site, and I think I’m happy with it. Maybe it’s even better this way than with a densely featured layout.

Thanks to the contributors & hope to see you again soon. /robert

Maybe it’s even better this way than with a densely featured layout.

Looks good to me:)

Yes you are correct and with my demo you couldn’t use a gradient to full effect so is not a viable solution but is too contrived anyway.

I had a play around with it and just for fun and came up with something that looks exactly like you wanted (in Firefox not chrome) but is not usable as it removes elements to create the effect.

However it does show what I think you were basically after.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style type="text/css">
.outer {
	width:70%;
	margin:auto;
	list-style:none;
	position:relative;
	border-spacing:5px;
}
.outer li {
	width:25%;
	margin:0;
	position:relative;
	background: #051b00;
	background: -webkit-gradient(linear, 0 0, 0 100%, from(#093700), to(#000000));
	background: -webkit-linear-gradient(top, #093700, #000000);
	background: -moz-linear-gradient(top, #093700, #000000);
	background: -ms-linear-gradient(top, #093700, #000000);
	background: -o-linear-gradient(top, #093700, #000000);
	background: linear-gradient(top, #093700, #000000);
	border-radius: 10px;
	box-shadow: 0 0 5px black;
	display:table-cell;
	border-spacing:5px;
	color:#fff;
}
.outer li a, .outer li a:visited{color:#fff}
.outer li:nth-of-type(5n) {
	display:block;
	height:0;
	width:0;
	overflow:hidden
}
.box {
	position:relative;
	z-index:2;
	padding:10px;
}
.outer li:hover:before { background:red }
 @media only screen and (max-width: 920px) {
.outer li { width:33.33% }
.outer li:nth-of-type(5n) {
	display:table-cell;
	height:auto;
	width:auto
}
.outer li:nth-of-type(4n) {
	display:block;
	height:0;
	width:0;
	overflow:hidden
}
}
 @media only screen and (max-width: 620px) {
.outer li { width:50% }
.outer li:nth-of-type(5n) {
	display:table-cell;
	height:auto;
	width:auto
}
.outer li:nth-of-type(4n) {
	display:table-cell;
	height:auto;
	width:50%
}
.outer li:nth-of-type(3n) {
	display:block;
	height:0;
	width:0;
	overflow:hidden
}
}
</style>
</head>

<body>
<ul class="outer">
		<li>
				<div class="box">1 <a href="#test">test</a></div>
		</li>
		<li>
				<div class="box">2 test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">3 test</div>
		</li>
		<li>
				<div class="box">4  A test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">5 test</div>
		</li>
		<li>
				<div class="box">6 test</div>
		</li>
		<li>
				<div class="box">7 test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div id="test" class="box">8 test</div>
		</li>
		<li>
				<div class="box">9 test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">10 test</div>
		</li>
		<li>
				<div class="box">11 test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">12 test</div>
		</li>
		<li>
				<div class="box">13 test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">14 test</div>
		</li>
		<li>
				<div class="box">15 test</div>
		</li>
		<li>
				<div class="box">16 test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
		<li>
				<div class="box">17 test</div>
		</li>
		<li>
				<div class="box">18 test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test </div>
		</li>
</ul>
</body>
</html>


The above demo is just for fun and not meant to be used :slight_smile:

Is this too corny?

Consider the ultimate of simplicity… at a price, of course.

Construct at least 2 basic css tables: one with 2 rows of 3 columns, one with 3 rows of 2 columns.
Assign the gradient to the background of the table-cells.
Position header, image, and text within the cells as desired.

Preset the tables to display:none;

Allow the media query to determine which one to set to display:table;

Content would have to be redundant across the tables, but the css would be much easier and would work smoothly today. This of it as faux responsive. :slight_smile:

Sounds plausible.

Paul, are you secretly from Hogwarts?

Is this too corny?

Kinda thought my previous post might be a moaner.

From Ralph and dresden_phoenix’s discussion in the “adding multiple classes and id’s” thread this evening, I see that I have a bit to learn about serving up content.

If there is a silver lining to the hide-and-show-tables thought it’s that I made it work; and insodoing, used media query code successfully for the first time <happy>.

Living and learning.

I haven’t had a chance to look closely at your suggestion, but keep experimenting! Your contributions here are great, ronpat, so keep it up. :slight_smile:

Could you post the code that you got working? I’d love to see it.

Not too corny but maybe too expensive:)

As you said you would need to have redundant tables full of data for every iteration which in my example would be 3 sets of duplicate tables for 2,3 and 4 columns. You’d also incur overheads in that you’d have to program it so that your same data is inserted into three different tables in 3 different manners. Having done all that then yes it would work as you simply show whichever layout you wanted at the suitable width :slight_smile:

The original premise was to take a single sequence of elements and have then auto adjust into columns as required of course ;).

Here’s a working example that works in Firefox and IE9 but Chrome isn’t obeying the media query properly and needs to be refreshed when the media query kicks in (I’ve seen this happen before ion Chrome on other responsive layouts).

It uses the same method as my other example but instead of hiding actual data it starts with an extra element in the sequences to start with which is then hidden and revealed to trigger the rows. As with Ronpat’s example it uses redundant elements but the structure is still a sequence of elements that could easily be programmed.

Again this is only for fun but interesting to see what can be achieved. If it wasn’t for chrome/safari this could almost be viable :slight_smile:

(As I mentioned earlier it looks like flexbox may be able to do this when it is completed)

That’s weird. I’ve never seen Chrome do that before. Is it anything in particular that seems to make this happen in Chrome?

I can’t remember what the problem was before but I’ve seen it twice now. It may be to do with the display:table properties where the browser needs to create anonymous table rows etc. and Chrome seems to only do this on refresh and not when the media query is triggered.