michaelcssguy
michaelcssguy

Reputation: 33

CSS nesting: inherit from whom?

here is a fiddle with the problem:
https://jsfiddle.net/c2exs2f7/3/

How does the second "blue" stay like the first instance (it should have color: white) without changing the HTML structure?

HTML

<div class="blue">
  <div class="content">
    <div class="label">blue</div>
    <div class="yellow">
      <div class="content">
        <div class="label">yellow</div>
        <div class="blue">
          <div class="content">
            <div class="label">blue</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

SCSS

// Skip until...

div {
  border-radius: .25em;
  padding: .5em;
  font-family: helvetica, sans-serif;
}

// ...here:

.blue {
  background-color: hsl(220,100%,50%);

  .content {
    color: white;
  }
}

.yellow {
  background-color: hsl(60,100%,50%);

  .content {
    color: hsl(0,0%,10%);
  }
}

EDIT #1 Thank you guys for these fast responses!
I am working on a grid system where I am able to nest different grid systems (with different CSS values).

Upvotes: 3

Views: 1518

Answers (5)

Valentin Forester
Valentin Forester

Reputation: 85

Since the most inner label has no siblings, you can do the following:

.blue .label:only-child {
  color: white;
}

The :only-child CSS pseudo-class represents an element without any siblings

Upvotes: 0

Must Impress
Must Impress

Reputation: 347

I had this same issue where the HTML nesting varies and so it's not possible to make more specific selectors due to overwhelming complexity and non-DRY code.

Here's the solution I came to:

https://jsfiddle.net/cg0u8v1s/

Basically, a systematic approach to the class names is key so you can use a CSS attribute selector reliably (although I'd recommend a more unique naming convention than "color-" as it's too generic.).

Example:

.color-blue {
  &,
  [class*="color-"] &,
  [class*="color-"] [class*="color-"] & {// Only needed if you want a 3rd level of nesting to work.
    background-color: blue;

    .content {
      color: skyblue;
    }
  }
}

.color-yellow {
  &,
  [class*="color-"] &,
  [class*="color-"] [class*="color-"] & {// Only needed if you want a 3rd level of nesting to work.
    background-color: yellow;

    .content {
      color: brown;
    }
  }
}

This will output selectors that become more specific with nesting without the need for non-DRY code or having to use !important.

The CSS output will look like this:

.color-blue,
[class*="color-"] .color-blue,
[class*="color-"] [class*="color-"] .color-blue {
  // code...
}

Upvotes: 0

Josh Crozier
Josh Crozier

Reputation: 240938

The selectors .yellow .content and .blue .content have the same specificity (20 in this case), therefore the selector that appears later in the stylesheet will override the first one due to the cascading nature of a stylesheet. In this case, the selector .yellow .content is overriding .blue .content, which is why the nested .blue element is black.

One quick solution would be to select nested .blue element with the selector .blue .blue:

Updated Example

.blue,
.blue .blue {
    background-color: hsl(220,100%,50%);

    .content {
        color: white;
    }
}

An arguably better approach would be to only select direct .content children elements using the child selector, >:

Updated Example

.blue {
    background-color: hsl(220,100%,50%);

    > .content {
        color: white;
    }
}

.yellow {
    background-color: hsl(60,100%,50%);

    > .content {
        color: hsl(0,0%,10%);
    }
}

Based on your comments, the ordering/layering of the elements may vary. An alternative solution would be to set the color property on the .blue/.yellow element and then set the color property of the children elements to inherit:

Updated Example - this seems to work for all variants.

.blue {
    background-color: hsl(220,100%,50%);
    color: white;

    .content {
        color: inherit;
    }
}

.yellow {
    background-color: hsl(60,100%,50%);
    color: hsl(0,0%,10%);

    .content {
        color: inherit;
    }
}

Upvotes: 2

therebelcoder
therebelcoder

Reputation: 1018

You can't. Not with inherent anyway. Because the second blue will inherent from the yellow. So if u want all blue always have white letters and yellow always black letters. Why not just put:

.blue { color: #fff; }
.yellow { color: hsl(0,0%,10%); }

And you won't need the ".content" wrapper.

Upvotes: 0

Niloct
Niloct

Reputation: 10015

See https://jsfiddle.net/c2exs2f7/4/

What I did was to enforce inheritance only for the child content classed DIV, not the entire descendance.

Applying the immediate children operator > in the SCSS makes the .content div to consider only its immediate parent color.

Go on and try nesting more DIVs, you will see that it works.

Upvotes: 1

Related Questions