block14
block14

Reputation: 619

Selector for even and odd level children

What is the correct selector for selecting even and odd level children?

I would like to simplify my current CSS while allowing for infinite levels without manually writing in the CSS for them.

.box {
    max-width:100%;margin:25px 0px;padding: 15px;
    border:#d1ddbd solid  2px;
    background-color:#f3fae8;
}

.box > .box {
    border:#d1ddbd solid  1px;
    background-color:#fff;
}

.box > .box > .box {
    border:#d1ddbd solid  1px;
    background-color:#f3fae8;
}

.box > .box > .box > .box {
    border:#d1ddbd solid  1px;
    background-color:#fff;
}

Upvotes: 7

Views: 2576

Answers (5)

Igor Bedesqui
Igor Bedesqui

Reputation: 36

You can do it with container queries now! just took 8 years.

basically, you use a container query to target a specific style, and inside of it you toggle the style itself:

layering {
  container-name: layering;
  --depth-is-odd: true;
}

@container layering style(--depth-is-odd: true) {
  .layering {
   // styles for odd levels of nesting
    --depth-is-odd: false;
  }
}

@container layering style(--depth-is-odd: false) {
  .layering {
   // styles for even levels of nesting
    --depth-is-odd: true;
  }
}

Upvotes: 2

keja
keja

Reputation: 1363

I think a bit of JS would be the easiest way to simplify the CSS, unless you wanna use LESS/SASS. - As already written above, there is no real way of doing this with short CSS selectors.

(function addClasses(element, selector, level){
  [].forEach.call(element.querySelectorAll(selector), 
                  function (item, index) {
  		    item.className += " " + (level % 2 ? "white-bg" : "green-bg");
                    item.innerHTML += "";
                    addClasses(item, ".box", level+1);
                  }
  );
})(document, ".box", 0);
.box {
    max-width: 100%;
    margin:25px 0px;
    padding: 15px;
    border: #d1ddbd solid  2px;
}

.box.white-bg {
  background-color: #ffffff;
  border: #d1ddbd solid  1px;
}
.box.green-bg {
  background-color: #f3fae8;
  border: #d1ddbd solid  1px;
}
<div class="box">
  1
  <div class="box">1.1</div>
  <div class="box">1.2</div>
</div>

<div class="box">
  2
  <div class="box">
    2.1
    <div class="box">
      2.1.1
      <div class="box">2.1.1.1</div>
    </div>
    <div class="box">2.1.2</div>
    <div class="box">2.1.3</div>
    <div class="box">2.1.4</div>
    <div class="box">2.1.5</div>
  </div>
  <div class="box">
    2.2
  </div>
  <div class="box">
    2.3
  </div>
</div>

<div class="box">
  3
  <div class="box">3.1</div>
</div>

Upvotes: 0

You can easily set classes by JavaScript.

Depends on planed amount and appropriate performance. (I presume you don't need thousands.)

This example takes: 500 8ms, 5.5K 47ms, 55K 446ms

/** Extending Javascript Array for function Contains */
Array.prototype.contains = function (element) {
    return this.indexOf(element) > -1;
};

/** Set class "odd" to itself and run proceedEven() on all children with class "box" */
function proceedOdd(oddItem) {
    oddItem.classList.add("odd");
    if (oddItem.children.length) {
        [].forEach.call(oddItem.children, function (child) {
            if (child.classList.contains("box")) {
                proceedEven(child);
            }
        })
    }
}

/** Set class "even" to itself and run proceedOdd() on all children with class "box" */
function proceedEven(evenItem) {
    evenItem.classList.add("even");
    if (evenItem.children.length)
        [].forEach.call(evenItem.children, function (child) {
            if (child.classList.contains("box")) {
                proceedOdd(child);
            }
        })
}

// set root having first even box as child
var root = document.querySelectorAll("body");

if (root.length) {
    // just for case more in root
    [].forEach.call(root, function (rootItem) {
        if (rootItem.children.length)
            [].forEach.call(rootItem.children, function (child) {
                // proceed first level of evens - rest done recursively
                if (child.classList.contains("box")) proceedEven(child);
            });
    })
}

Upvotes: 0

user663031
user663031

Reputation:

There's no way to do this in CSS, other than just sitting down and writing the rules. It's not that big a deal to write ten rules, taking you down to ten nesting levels. Your alternative is to spend more time writing JS to add classes, or having your back-end add classes, or fighting with a SASS macro, any of which will take more time than this is worth.

.box {
  max-width: 100%;
  margin:    25px 0px;
  padding:   15px;
  border:    #d1ddbd solid 2px;
}

.box > .box {
  border-width: 1px;
}

.box,
.box > .box > .box, 
.box > .box > .box > .box > .box, 
.box > .box > .box > .box > .box > .box > .box,
.box > .box > .box > .box > .box > .box > .box > .box > .box {
    background-color:#f3fae8;
}

.box > .box, 
.box > .box > .box > .box, 
.box > .box > .box > .box > .box > .box,
.box > .box > .box > .box > .box > .box > .box > .box,
.box > .box > .box > .box > .box > .box > .box > .box, .box > .box {
    background-color:#fff;
}

Upvotes: 5

Jtuck
Jtuck

Reputation: 310

In the event you make "box" using div's you could do something like this. (See code and preview below)

div:nth-child(even)
{
    border:#d1ddbd solid  1px;
    background-color:#f3fae8;
    width:76px;
    height:75px;
}
div:nth-child(odd)
{
    border:#d1ddbd solid  1px;
    background-color:#fff;
    width:76px;
    height:75px;
}
#MainDiv{
    max-width:100%;margin:25px 0px;padding: 15px;
    border:#d1ddbd solid  2px;
    background-color:#f3fae8;
    display:block;
    padding:2px;
    height:auto;
}

    <div id="MainDiv">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
    </div>

Preview code output

Upvotes: 0

Related Questions