3

I have a parent div#main that contains unknown number of divs in rows. Every row has 3 divs that are display: inline-block. Now, because of that, the last row can contain 1, 2 or 3 divs, depending on their number.

If the last row has only 1 div, then I want do add border-left and border-right to it.

If the last row has 2 divs, then I want do add border-right to the first div in that row, or border-left to the second div.

And if the last row has 3 divs, then I want to add border-left and border-right to to the second div (the middle one).

(You'll get the full picture when you look at the snipper, or the fiddle)

I managed to solve this issue by using JS, but I'm looking for a pure CSS solution, if there is one.

$('.main').each(function(){

 var div_length = $(this).find('div').length;

 if((div_length % 3) === 0){
  div_last_items = div_length;
 }

 else if((div_length % 3) === 1){
  div_last_items = div_length - 1;
  $(this).find('div:nth-last-child(1)').addClass('active-borders');
 }

 else if((div_length % 3) === 2){
  div_last_items = div_length - 2;
  $(this).find('div:nth-last-child(2)').addClass('active-border');
 }

 $(this).find('div:lt('+div_last_items+')').each(function(i){
  i=i+2;
  if(i % 3 === 0){
   $(this).addClass('active-borders') 
  }  
 });
});
.main {
    width: 360px;
    text-align: center;
}
.main>div {
    display:inline-block;
    vertical-align:top;
    width: 100px;
    height: 100px;
    background:red;
    margin-top: 10px;
    margin-bottom: 10px;
}
.main>div:nth-child(3n+2) {
    margin-left: 20px;
    margin-right: 20px;
}

.active-borders{
    border-left: 5px solid black;
    border-right: 5px solid black;
}

.active-border{
    border-right: 5px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>
<hr>
<div class="main">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>
<hr>
<div class="main">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>

JSFiddle

Harry
  • 87,580
  • 25
  • 202
  • 214
Vucko
  • 20,555
  • 10
  • 56
  • 107
  • Just out of curiosity, any reason for wanting a pure CSS solution? I think it is going to be pretty complex (if at all possible). – Harry Jul 05 '15 at 16:20
  • @Harry I'm just looking if there is one so I can tell my client that JS is necessary here. However, I don't know if it can maybe done with SASS somehow? – Vucko Jul 05 '15 at 16:23
  • 1
    Hmm ok. Even with pre-processors (SASS, Less etc) I don't think it would be straight-forward because the preprocessors would not know how many elements are present in your markup (unless you compile them on client side in which case you would need JS anyway). – Harry Jul 05 '15 at 16:24
  • 1
    Possible duplicate: http://stackoverflow.com/questions/8720931/can-css-detect-the-number-of-children-an-element-has or http://stackoverflow.com/questions/26188427/css-trick-nth-of-type – cimmanon Jul 05 '15 at 17:54
  • @Harry yes, that's true. I thought maybe with some combination of `:nth-last-child` and SASS can be possible. Thanks for the effort :) – Vucko Jul 05 '15 at 18:14

2 Answers2

4

I never thought this would be possible with pure CSS but it is. All credits would go to this answer for showing an idea on how this could be achieved. This answer is based on that but I am drafting a separate answer because the selectors are a bit different here and I wanted to explain them.

Selector Additions:

div > div:nth-child(3n) + div:nth-last-child(1) {
  border-left: 5px solid black;
  border-right: 5px solid black;
}
div > div:nth-child(3n+1) + div:nth-last-child(1) {
  border-left: 5px solid black;
}
div > div:nth-child(3n+1) + div:nth-last-child(2) {
  border-left: 5px solid black;
  border-right: 5px solid black;
}

Explanation:

div > div:nth-child(3n) + div:nth-last-child(1)
  • Select the last child of the parent div when it immediately follows the 3nth child. If the last child immediately follows the 3nth child then it would obviously be the only item in the last row.
div > div:nth-child(3n+1) + div:nth-last-child(1)
  • Select the last child of the parent div when it immediately follows the 3n+1th child. If the last child immediately follows the 3n+1th child then it means that the last row has 2 items.
div > div:nth-child(3n+1) + div:nth-last-child(2)
  • Select the second last child of the parent div when it immediately follows the 3n+1th child. If the second last child immediately follows the 3n+1th child then it means that the last row has 3 items.

We cannot use the selector div > div:nth-child(3n+2) + div:nth-last-child(1) for the case where the last row has 3 items because we need the middle element to be styled and not the last,

.main {
  width: 360px;
  text-align: center;
}
.main>div {
  display: inline-block;
  vertical-align: top;
  width: 100px;
  height: 100px;
  background: red;
  margin-top: 10px;
  margin-bottom: 10px;
}
.main>div:nth-child(3n+2) {
  margin-left: 20px;
  margin-right: 20px;
}
div > div:nth-child(3n) + div:nth-last-child(1) {
  border-left: 5px solid black;
  border-right: 5px solid black;
}
div > div:nth-child(3n+1) + div:nth-last-child(1) {
  border-left: 5px solid black;
}
div > div:nth-child(3n+1) + div:nth-last-child(2) {
  border-left: 5px solid black;
  border-right: 5px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
<hr>
<div class="main">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
<hr>
<div class="main">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

The selectors in the above snippet adds a border-left to the second div in the last row if it has only 2 items. If you need to apply border-right to the first div in the last row when it has only 2 items, you can make use of the below selector:

div > div:nth-child(3n+1):nth-last-child(2)
  • This means, select the second last child of the parent div when it also happens to be the 3n+1th div. If this selector is matched, it implies that the last row has two items.

.main {
  width: 360px;
  text-align: center;
}
.main>div {
  display: inline-block;
  vertical-align: top;
  width: 100px;
  height: 100px;
  background: red;
  margin-top: 10px;
  margin-bottom: 10px;
}
.main>div:nth-child(3n+2) {
  margin-left: 20px;
  margin-right: 20px;
}
div > div:nth-child(3n) + div:nth-last-child(1) {
  border-left: 5px solid black;
  border-right: 5px solid black;
}
/*div > div:nth-child(3n+1) + div:nth-last-child(1) {
  border-left: 5px solid black;
}*/
div > div:nth-child(3n+1):nth-last-child(2){
  border-right: 5px solid black;
}
div > div:nth-child(3n+1) + div:nth-last-child(2) {
  border-left: 5px solid black;
  border-right: 5px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
<hr>
<div class="main">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
<hr>
<div class="main">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
Community
  • 1
  • 1
Harry
  • 87,580
  • 25
  • 202
  • 214
  • 1
    There's a typo in the second selector in the explanation... `3n` should be `3n+1` – Danield Jul 06 '15 at 08:40
  • 1
    Here's [a post](http://stackoverflow.com/questions/8720931/can-css-detect-the-number-of-children-an-element-has) from 3 years ago which is also relevant... nice work though +1 – Danield Jul 06 '15 at 08:46
  • 1
    Thanks for both the comment and the link @Danield – Harry Jul 06 '15 at 08:51
  • 1
    I also didin't thought that it can be done with pure CSS, so I'm really stuned now! Now I have to explain my client that I was wrong :P Thanks a million @Harry. – Vucko Jul 08 '15 at 07:01
0

In general adding border changes border-box dimension of the element. That change of geometry by itself may move element to the next row. Chicken-egg problem.

Thus you cannot do that by CSS means. And even with JS you should be careful - you may get not you want in some circumstances.

c-smile
  • 26,734
  • 7
  • 59
  • 86