Can nth child skip elements and resume the count?

Luckily for me the OP was satisfied with the CSS I was able to provide

div.post-stream > div.topic-post:nth-child(2n) div.topic-body {
  background-color: #bde;
}
div.post-stream > div.topic-post:nth-child(2n+1) div.topic-body {
  background-color: #edb;
}

(the “6 months later” is a div that has a class value of “small-action” and does not have one of “topic-post”)

The stumbling block I ran into is

the odd-even uses the element regardless of the class

If that is as unclear a description as it feels to be I can try to explain it better.

I almost constantly get amazed at what CSS can do. Am I missing something simple here or is this the best that can be done without using JavaScript?

what happens if you pair the :nth-child() with :not() as well?

Good idea, but the results look the same to me.


div.post-stream > div:not(.small-action):nth-child(2n) div.topic-body {
  background-color: #bde;
}
div.post-stream > div:not(.small-action):nth-child(2n+1) div.topic-body {
  background-color: #edb;
}

same with

div.post-stream > div:nth-child(2n):not(.small-action) div.topic-body {
  background-color: #bde;
}
div.post-stream > div:nth-child(2n+1):not(.small-action) div.topic-body {
  background-color: #edb;
}

Hi Mittineague,

Not sure if this will work with your existing html structure and the way your classes are set up.

It looks like you can interrupt the :nth-child order by using the !important declaration. It appears to resume the count as you are wanting, unless I am unclear on that.

I was simply using div > div with !important as my override rule. Actually the :nth-child background color is still there, it’s just laying another layer on top. You can see that with the 20px side margins that were set on it.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>:nth-child override</title>
<style>
body {
    width:50%;
    margin:2em auto;
}
div {
	background: red;
}
div:nth-child(2n+1) {
	background: lime;
}
div > div {
	background: yellow!important;
        margin: 0 20px;
}
</style>
</head>
<body>

    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div><div>4 !important</div></div>
    <div>5</div>
    <div>6</div>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div><div>4 !important</div></div>
    <div>5</div>
    <div>6</div>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>5</div>
    <div>6</div>

</body>
</html>

Thanks Ray.H

Sorry, I should have made specific mention that the HTML is not mine, but that of a Discourse forum topic.

The styling I was thinking of would be like

red
green
skipped
red
green
red
skipped
green
red

instead of

red
green
skipped
green
red
green
red
skipped
red

I see

For what it’s worth, I was able to do what you wanted with :nth-of-type and changing the interrupted item to a <p> tag.

Yes, that would work, but I’m more or less “stuck” working with the HTML as it is.

What would be nice is a :nth-of-attribute-value selector.

1 Like

The first thing that came to my mind was something similar to counter-reset.

Maybe a nth-count:skip; property/value that could be set on item to be skipped in the count, and compatible with all pseudo :nth selectors.

Yes the class is incidental and not relevant to the counting. The style is only applied if the class is present on the matched element.

Thanks for confirming.

After Ray.H’s mention of “reset” I thought of trying to lead off with a
div.small-action { display: none; }
thinking it might remove those divs from the counting, but no joy.

So if a different “tiger striping” is wanted it would have to be done with a different DOM (not likely to happen in the Discourse Core code, but maybe if there was more demand for it) or by using JavaScript.

1 Like

If it were a table you were adding the stripes to then it is simple as each tbody resets the count.

Hi there Mittineague,

as @felgall has suggested, you need to use HTML containers…

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

<meta charset="utf-8">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1">

<title>untitled document</title>

<style media="screen">
div div {
    padding: 0.5em;
 }
div div:nth-child(odd) {
    background-color: #fcc;
 }
div div:nth-child(even) {
    background-color: #cfc;
 }
div div[data-bg="none"] {
    background-color: transparent;
 }
</style>
</head>
<body>
<div> 
  <div>1</div>
  <div>2</div>
  <div>1</div>
  <div>2</div>
  <div data-bg="none">1</div>
</div><div>
  <div>2</div>
  <div>1</div>
  <div data-bg="none">2</div>
</div><div>
  <div>1</div>
  <div>2</div>
  <div>1</div>
  <div>2</div>
  <div data-bg="none">1</div>
</div><div>
  <div>2</div>
  <div>1</div>
  <div>2</div>
  <div>1</div>
  <div>2</div>
</div>
</body>
</html>

coothead

1 Like

Hi @Mittineague,
You may have already solved this, but for the sake of working on my non existent JS skills I stayed with it until I found a solution.

The conditions were -

  1. Don’t alter the html
  2. Maintain tiger striping while skipping div.post-stream in the count

I wound up using :nth-of-type as I mentioned previously. The challenge for me while using my generic div structure was selecting an appropriate element to wrap around the skipped class. Couldn’t use a div and a “p” is not semantic.

Thought I had found the solution with the <element> element because of it’s transparent content model and ability to to define new custom DOM elements. Seemed to be just what I was looking for but it has been removed from the specs.:disappointed:

I went ahead and used <element> in my example anyway and it is working in all my browsers. Custom DOM elements are beyond my knowledge right now but it sounds like you could create your on element.

For what it’s worth, here’s what I came up with, you can see the new element with ff inspector.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Wrap element with new parent</title>
<style>
body {
	width: 50%;
	min-width: 300px;
	margin: 2em auto;
}
div {
	background: yellow;
}
div:nth-of-type(2n+1) {
	background: lime;
}
element > .skip {
	background: aqua;
	margin: 0;
}
</style>
</head>
<body>

    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div class="skip">4 .skip class</div>
    <div>5</div>
    <div>6</div>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div class="skip">4 .skip class</div>
    <div>5</div>
    <div>6</div>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div class="skip">4 .skip class</div>
    <div>5</div>
    <div>6</div>

<script>

function wrap(top, selector, bottom){
  var target = document.querySelectorAll(selector);
  for (var i = 0; i < target.length; i++){
    var modified = top + target[i].outerHTML + bottom;
    target[i].outerHTML = modified;
  }
}
wrap("<element>", ".skip", "</element>");

</script>
</body>
</html>
4 Likes

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.