16

I am working on a simple HTML for an image gallery. Each row of the gallery can have 2, 3 or 4 images. (In an 2-image row, each image element is named type-2, the same goes to type-3 and type-4.)

Now I want to select the last element of each row to set a custom margin. My HTML is like this:

<div id="content">
    <div class="type-2"></div>
    <div class="type-2"></div> <!-- I want this, 2n+0 of type-2 -->
    <div class="type-3"></div>
    <div class="type-3"></div>
    <div class="type-3"></div> <!-- this, 3n+0 of type-3 -->
    <div class="type-4"></div>
    <div class="type-4"></div>
    <div class="type-4"></div>
    <div class="type-4"></div> <!-- this, 4n+0 of type-4 -->
    <div class="type-2"></div>
    <div class="type-2"></div> <!-- this -->
    <div class="type-3"></div>
    <div class="type-3"></div>
    <div class="type-3"></div> <!-- this -->
    <div class="type-4"></div>
    <div class="type-4"></div>
    <div class="type-4"></div>
    <div class="type-4"></div> <!-- this -->
</div>

I think the following CSS would work but it didn't:

.type-2:nth-of-type(2n+0) {margin-right:0;}
.type-3:nth-of-type(3n+0) {margin-right:0;}
.type-4:nth-of-type(4n+0) {margin-right:0;}

What this CSS selects is:

<div id="content">
    <div class="type-2"></div>
    <div class="type-2"></div> <!-- selected by .type-2:nth-of-type(2n+0) -->
    <div class="type-3"></div> <!-- selected by .type-3:nth-of-type(3n+0) -->
    <div class="type-3"></div>
    <div class="type-3"></div>
    <div class="type-4"></div>
    <div class="type-4"></div>
    <div class="type-4"></div> <!-- selected by .type-4:nth-of-type(4n+0) -->
    <div class="type-4"></div>
    <div class="type-2"></div> <!-- selected by .type-2:nth-of-type(2n+0) -->
    <div class="type-2"></div>
    <div class="type-3"></div> <!-- selected by .type-3:nth-of-type(3n+0) -->
    <div class="type-3"></div>
    <div class="type-3"></div>
    <div class="type-4"></div>
    <div class="type-4"></div> <!-- selected by .type-4:nth-of-type(4n+0) -->
    <div class="type-4"></div>
    <div class="type-4"></div>
</div>

I can edit my HTML to achieve what I want, but just out of curiosity, is there some kind of CSS for this?

Edit: this question may look like a duplicate of questions asking if nth-child and nth-of-type can be applied to classes -- not elements. I already knew the answer is no. What I'm really asking for is a pure CSS solution/hack for it, and the chosen answer did just that.

Hoang Huynh
  • 1,384
  • 2
  • 16
  • 33

4 Answers4

15

This is not possible to do with CSS Selectors Level 3 (at least, without CSS hacks, extra markup, or JavaScript).

The draft CSS Selectors Level 4 proposes the :nth-match() pseudo-class, which would do what you want:

:nth-match(2n+0 of .type-2) {margin-right:0;}
:nth-match(3n+0 of .type-3) {margin-right:0;}
:nth-match(4n+0 of .type-4) {margin-right:0;}

This is not yet implemented by any browser that I know of, but there is a bug filed to implement it in Chrome.

Brian Campbell
  • 322,767
  • 57
  • 360
  • 340
10

With only CSS hacks, without modifying your markup, you can do something like the below:

[class*=' type-'], [type^='type-']{ /* Set all the divs to float: left initially */
    float: left;
    content: url('http://static.adzerk.net/Advertisers/db5df4870e4e4b6cbf42727fd434701a.jpg');
    height: 100px; width: 100px;
}

.type-2 + .type-2 + div{
    clear: both; /* Clear float for a div which follows two div with class type-2 */
}

.type-3 + .type-3 + .type-3 + div {
    clear: both; /* Clear float for a div which follows three div with class type-3 */
}

.type-4 + .type-4 + .type-4 + .type-4 + div {
    clear: both; /* /* Clear float for a div which follows four div with class type-4 */
}

Demo Fiddle

hitautodestruct
  • 20,081
  • 13
  • 69
  • 93
Harry
  • 87,580
  • 25
  • 202
  • 214
  • The above example is essentially to set the no. of divs to be displayed per row depending on the type. If you want additional CSS to be applied, it should still be possible. – Harry Oct 19 '13 at 17:40
  • Such a simple and nice workaround, thank you! Also, thanks for the demo! – Hoang Huynh Oct 19 '13 at 17:48
  • 1
    @Harry Why not use `.type-n` instead of `[class*="type-n"]`? – hitautodestruct Oct 19 '13 at 18:48
  • @hitautodestruct: We can use as `.type-n` also mate (in fact for this very case that is the best). I just wanted to show that we can use the attribute selectors with a data* HTML5 attribute also. Was very late in the night yesterday when I answered this and must have dozed off in between :D – Harry Oct 20 '13 at 02:42
7

nth-child and nth-of-type are pseudo classes and can only be applied to elements.

.layout:nth-of-type is a pseudo-class of a class and so will not work.

Jquery's EQ might offer a solution

http://api.jquery.com/eq/

Paulie_D
  • 107,962
  • 13
  • 142
  • 161
  • Thank you for the confirmation on the functionality of `nth-child` and `nth-of-type`. JS is fine but as I want a pure CSS solution, I accepted @Harry's answer. – Hoang Huynh Oct 19 '13 at 17:57
3

Short answer

There is no way to do what you're asking in pure css.

Why

:nth-of-type Can only be used against an element selector like so:

div:nth-of-type(2n+0) { margin-right: 0; }

Reference link.

Possible JS solution

You can try your luck with some jQuery though:

var $this;

$('[class^="type-"]').each(function (){

  $this = $(this);

  if ( $this.attr('class') !== $this.next().attr('class') )
    $this.addClass('last');

});

Then use .type-2.last to access your "last row of type".

Demo

Heres a demo.

hitautodestruct
  • 20,081
  • 13
  • 69
  • 93