CSS to create multiple columns

I’m not sure if CSS is going to be the right solution but I’d like to take a stab at it.

So what I want to do is create a CSS mechanism that will break a single column of div containers into two or more columns based on the number of div containers it contains. For instance, I have an area called #right-column in a dynamic CMS website. Within the right column are article teasers. I would like to be able to stack the article teasers in columns of three. So the first three teasers stack one on top of the other and the fourth starts a new stack.

The markup would be something like this:


<div id="right-column">
    <div class="article-teaser"> . . . </div>
    <div class="article-teaser"> . . . </div>
    <div class="article-teaser"> . . . </div>
    <div class="article-teaser"> . . . </div>
    <div class="article-teaser"> . . . </div>
    <div class="article-teaser"> . . . </div>
</div>

I know I can use jQuery to count the number of containers and then manipulate the CSS but I wonder if there is a pure CSS method.

Thanks,
Andrew

You probably have requirements that aren’t mentioned such as a need for some flexibility in the size of each teaser container. Nevertheless, in answer to your question, “Is there a pure css solution?”, yes, but… (this completely doesn’t work in IE8) :slight_smile:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<!--
http://www.sitepoint.com/forums/showthread.php?910793-CSS-to-create-multiple-columns
  1. "Is it possible with css?", yes.  Is it practical, probably not.
  2. Both versions of this mockup are essentially the same.  The second just adds some margin around the items.
  3. Width autosizes to fit "columns" of teasers.  In this demo, the outer container is horizontally centered.
  4. A dedicated height that matches the height of 3 items is required.
  5. All items are expected to occupy the same size and shape.
  6. :nth-child pseudoclass and display:table limit browser compatibility.
  7. Adapted from an example by dresden_phoenix. For his practical solution, see:
http://www.sitepoint.com/forums/showthread.php?896957-2-Column-List-Need-Vertically  #4
-->
<head>
    <title>template</title>
    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
    <meta http-equiv="content-language" content="en-us">
    <style type="text/css">

ul {
    display:table;
    border:1px solid #aaa;
    list-style-type:none;
    height:186px;    /* a fixed height is required */
    padding:0px;
    margin:0 auto;
}
li {
    border:1px solid #aaa;
    height:60px;
    width:148px;
}
li:nth-child(3n+1) {
    background-color:#faa;    /* LAYOUT TESTING */
}
li:nth-child(3n+2) {
    background-color:#afa;    /* LAYOUT TESTING */
}
li:nth-child(3n+3) {
    background-color:#aaf;    /* LAYOUT TESTING */
}
/* position map */
li:nth-child(4) {margin-left:150px;margin-top:-186px;}
li:nth-child(5) {margin-left:150px;}
li:nth-child(6) {margin-left:150px;}
li:nth-child(7) {margin-left:300px;margin-top:-186px;}
li:nth-child(8) {margin-left:300px;}
li:nth-child(9) {margin-left:300px;}
li:nth-child(10) {margin-left:450px;margin-top:-186px;}
li:nth-child(11) {margin-left:450px;}
li:nth-child(12) {margin-left:450px;}

.teasers {
    display:table;
    border:1px solid #aaa;
    height:202px;    /* a fixed height is required */
    padding-left:4px;
    margin:0 auto;
}
.teasers div {
    border:1px solid #aaa;
    height:60px;
    width:144px;
    margin:4px 4px 4px 0px;
}
.teasers div:nth-child(3n+1) {
    background-color:#faa;    /* LAYOUT TESTING */
}
.teasers div:nth-child(3n+2) {
    background-color:#afa;    /* LAYOUT TESTING */
}
.teasers div:nth-child(3n+3) {
    background-color:#aaf;    /* LAYOUT TESTING */
}
/* position map */
.teasers div:nth-child(4) {margin-left:150px;margin-top:-198px;}
.teasers div:nth-child(5) {margin-left:150px;}
.teasers div:nth-child(6) {margin-left:150px;}
.teasers div:nth-child(7) {margin-left:300px;margin-top:-198px;}
.teasers div:nth-child(8) {margin-left:300px;}
.teasers div:nth-child(9) {margin-left:300px;}
.teasers div:nth-child(10) {margin-left:450px;margin-top:-198px;}
.teasers div:nth-child(11) {margin-left:450px;}
.teasers div:nth-child(12) {margin-left:450px;}
    </style>
</head>
<body>

<ul>
    <li>A - Item List</li>
    <li>B - Item List</li>
    <li>C - Item List</li>
    <li>D - Item List</li>
    <li>E - Item List</li>
    <li>F - Item List</li>
    <li>G - Item List</li>
    <li>H - Item List</li>
    <li>I - Item List</li>
    <li>J - Item List</li>
    <li>K - Item List</li>
</ul>
<br>
<div class="teasers">
    <div>A - Teaser</div>
    <div>B - Teaser</div>
    <div>C - Teaser</div>
    <div>D - Teaser</div>
    <div>E - Teaser</div>
    <div>F - Teaser</div>
    <div>G - Teaser</div>
    <div>H - Teaser</div>
    <div>I - Teaser</div>
    <div>J - Teaser</div>
</div>

</body>
</html>

Thanks ronpat… That does a very nice job of vertical columns. It requires a fairly specific position map in order to work but in this particular case that is just fine because I will be specifying a maximum number of teasers so this should work just fine.

Thanks again!

Andrew

You’re very welcome. I appreciate the feedback.

Cheers

Andrew,

In the interest of older-browser compatibility, you can replace the position maps that use the css3 :nth-child() pseudo-class with these maps that use the css2 adjacent sibling selector. These even work in IE8 :slight_smile:


/* position map */
li + li + li + li {margin-left:150px;margin-top:-186px;}
li + li + li + li + li {margin-left:150px;margin-top:0px;}
li + li + li + li + li + li + li {margin-left:300px;margin-top:-186px;}
li + li + li + li + li + li + li + li {margin-left:300px;margin-top:0px;}
li + li + li + li + li + li + li + li + li + li {margin-left:450px;margin-top:-186px;}
li + li + li + li + li + li + li + li + li + li + li {margin-left:450px;margin-top:0px;}

/* position map */
.teasers div + div + div + div {margin-left:150px;margin-top:-198px;}
.teasers div + div + div + div + div {margin-left:150px;margin-top:0px;}
.teasers div + div + div + div + div + div + div {margin-left:300px;margin-top:-198px;}
.teasers div + div + div + div + div + div + div + div {margin-left:300px;margin-top:0px;}
.teasers div + div + div + div + div + div + div + div + div + div {margin-left:450px;margin-top:-198px;}
.teasers div + div + div + div + div + div + div + div + div + div + div {margin-left:450px;margin-top:0px;}

Ugh… tried to post earlier but my internet was giving me some weird issues; sorry for chiming in late.

The big draw back, regardless of browser compatibility is that you cant FLOW content in CSS ( tho I don’t think that what you were referring to) the other drawback is that you need to have some fixed dimensions on all elements.

Here is a quicky and compact version of how it can be done:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title></title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<style type="text/css">
				.cols{padding:0; margin:0; list-style: none; counter-reset: count; counter-reset: row;}
				.cols li { height: 150px; width: 25%;  border: 1px solid red }
				
				.cols li:nth-child(4n+1) {  counter-reset: row;   counter-increment: count;   }
				.cols li:before {     counter-increment: row; content:"COLUMN:"counter(count) "   / ROW:"counter(row) ;display:block;  font-weight:bold; }
				
				
				/*da 'magic'*/

				.cols li:nth-child(4n+5){color:red; margin-top: -608px}
				.cols li:nth-child(4n)~li{margin-left: 25%;}
				.cols li:nth-child(8n)~li{margin-left: 50%;}
				.cols li:nth-child(12n)~li{margin-left: 75%;}
		</style>
	</head>
	<body>
<ul class="cols" >
	<li> col:1 this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
</ul>
	</body>
</html>


The key concept is to think of each interval of elements as a column break and mark it so, beit with a class in the html or via nth-child.

here is a complex layout based on what I have just said a (col1 has 4 rows, col2 has 5, col3 has 2)


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title></title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<style type="text/css">
				.cols{padding:0; margin:0; list-style: none; height:600px; border:1px solid red}
				.cols li{overflow:auto}
				
				
				/*da 'magic'*/
				.cols li {  width: 25%;  border-top: 1px solid red; height:25%; }
				.cols li:nth-child(1), .cols li:nth-child(5),  .cols li:nth-child(10) {border-top:none}
 				.cols li:nth-child(5), .cols li:nth-child(10){margin-top: -604px}
				.cols li:nth-child(4)~li{margin-left: 25%;width: 50%;height:20%; border-left:1px solid red; }
				.cols li:nth-child(9)~li{margin-left: 75%;width: 25%;height:50%;}
		</style>
	</head>
	<body>
<ul class="cols" >
	<li> col:1 this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
	<li> you can use different methods for marking the column delimiter; for example for IE compatibility you can  just add a class ot the specific elements, instead of using nth child or general sibling selectors </li>
	<li>this would represent a div or  content segment. It must be fix width and height, which is the chief drawback to this method. </li>
</ul>
	</body>
</html>

So, the principle is to “mark” the element that starts a column. From that point you can use general sibling selectors to it up the height of the container, using negative margin and push it right ward the necessary amount. :slight_smile: This concept (remember you can place a class as a marker, if you can’t support nth child) , should work as far back as IE8 (IE7 if you dont have html comments between the elements)

hope that helps