Internal CSS grid borders for uneven lists

Best to see this in action. I’ve got a product list which has internal borders,but nothing around the outside. The border is 1px and can’t be collapsed as it’s not a table. This system works fine for anything where you have complete rows but when you have 1 or 2 items on the last row, it breaks the layout.

I’m able to add CSS classes to the last item(s) if required but can’t get this to work correctly.

This grid works fine when I have 12 products, or indeed any multiple of the line length (3) but when I have left over items, my borders don’t work. I’m after an internal grid that works for any number of items.

If there is only 1 item on the last line then there are bottom or right borders. If there are 2, then the items have only a right border.

Threads merged because link to the same fiddle

Strange, I got an error when i submitted the first time saying it already existed! Thanks for sorting.

What do you mean by “it breaks”? It seems to work fine to me no matter how many items there are.

Probably the lack of padding on the window. Check again.

With 11 items, the bottom row still has a bottom border and a right most border. When you have 11 items, items 10 and 11 should have a top border and a border between them and no others.

As you have it currently, the bottom row boxes have a bottom border, which you presumably don’t want. So you might have to set this up differently. A manual way would be to give them a special class that removed the bottom border.

To remove the right border on the last item, you could use this:

section.products article.product-single:last-child {
border-right: none;
}

I’ve updated the fiddle to show the problem. When you have 11 items out of 12, the 9th item doesn’t get the border at the bottom as this is actually the border-top from the 12th item. I could switch around the CSS so that I have a border-bottom but would then need to update the CSS to target the last 3 complete row items and remove the border. Not easy!

That’s not the way it is in the fiddle at the moment. The border is still on the bottoms (unless you have a new page now).

Anyhow, probably the thing to do is set the border on the top of each div and target the first three divs and remove that top border. Then use the last-child rule I posted above to remove the right border.

Sorry, I hit run rather than update.

Did you see my last post?

Yup. Border is on the tops.

Is it possible for you to wrap each row in a div? That would make things a lot easier.

Yeah, could do. I was also wondering about display:table ?

Can’t think of a way to do it in just CSS.

There probably is a way, but it’s much easier if each row has a div. I don’t think CSS tables will help much here, as you’d end up in the same situation. If you add the extra row divs, you can target the rows, whether using display: table or not, but without the row div, it seems to be tricky.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title></title>
		<style type="text/css">
		section, article{display:block;}/* older moz NEEDS  this */

* {
 -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    -o-box-sizing: border-box;
    -ms-box-sizing: border-box;
    box-sizing: border-box;
 }
section.products {margin:10% ;  border:   1px solid rgb(195,195,195);  }
section.products article.product-single  {
    width: 33.33%;
    padding: 2%;
    display: inline-block;
    vertical-align: top;
    position: relative;
    min-height: 260px;
    border-right: 1px solid rgb(195,195,195);
}
section.products article.product-single:nth-child(3n) { border-right: none;}

.products article:nth-child(3)~article{border-top:1px solid rgb(195,195,195)}
.products article.ntlr~article{border-bottom:1px solid rgb(195,195,195)}
.products article.lr~article{border-bottom:none; border-top:none}
.products article:nth-child(3n+1):last-child {position: relative}
.products article:nth-child(3n+1):last-child:after{content:""; position: absolute; left:100%; height:100%; width: 100%; top:0;border-right:1px solid rgb(195,195,195); margin-left:1px }
		</style>
	</head>
	<body>
<section class="products"><!--
    --><article class="product-single  cf  ">1</article><!--
    --><article class="product-single  cf">2</article><!--
    --><article class="product-single  cf">3</article><!--
    --><article class="product-single  cf ">4</article><!--
    --><article class="product-single  cf">5</article><!--
    --><article class="product-single  cf ntlr">6</article><!--
    --><article class="product-single  cf ">7</article><!--
    --><article class="product-single  cf">8</article><!--
    --><article class="product-single  cf lr">9</article><!--
    --><article class="product-single  cf ">10</article><!--
    --><article class="product-single  cf">11</article><!--
--></section>
   </body>
</html>

Tho that should solve your issue, am not entirely happy with that solution as :

  1. It relies too much on chained pseudo elements
  2. it relies on CSS3 so am not sure how backwards compatible it is ( if what you are trying to do is display a LIST as a table)
  3. it isnt scalable to any number ( you could probably tweak it work for 4 or 5 columns … but nothing after that)

I don’t think there is a perfect way to mimic “display empty cells”, even in my example above if you are missing 2/3 of a row you will see the 2 empty “cells” merged as one. It’s really a list NOT a table, mostly because a table, CSS or HTML , requires a tag for rows so that the info can indeed be tabular.

Thanks Dresden, I wondered if there was a pseudo-element solution. I’ll see how well supported that is and make a call. Alternatively, I’ll pop in a container div for the rows. One of those things that should be easy to do but isn’t yet with CSS.