Inheritance and Specificity

Inheritance is the most fundamental concept of CSS, but at its heart, it is simple. It says that elements inherit properties from their containers, and there is no limit to how far that goes. It might be easier to think of this the other ways, as, “Properties propagate to containers.”

Every character sheet is made up of HTML elements. Some of those elements are containers, and they might contain other containers. Imagine this HTML:

<div class="page">
    <div class="attributes">
        <h4>Dexterity</h4>
        <input type="number" name="attr_dextity">
    </div>
    <div class="saves">
        <h4>Reflex Save</h4>
        <input type="number" name="attr_reflex">
    </div>
    <div class="description">
        <h4>Appearance</h4>
        <textarea name="attr_appearance">
        <img name="attr_character_avatar">
    </div>
</div>Code language: HTML, XML (xml)

Here we have a simple sheet containing a single all-encompassing div, and inside it are three adjacent divs. Inside those interior divs are a collection of different elements.

Now we apply this style:

.page {
   text-align: center;
}Code language: CSS (css)

Recall that .page is a selector, and applies the declaration to the class=”page”. Since inheritance says, “Apply this to everything contained in this class,” this makes text centred for all elements in that div, as well as all elements in any containers in that div, and so on until there are no more containers.

But, of course, it’s not as ‘simple’ as that. What if you have this CSS:

.attributes { color: red; }
.page .attributes {color: blue; }
div.attributes {color: green; }
input {color: purple}
.attributes input {color: orange;}Code language: CSS (css)

What colour will the input inside attributes be? We need to use something called Specificity to find out.

Specificity

This says that the most specific rule wins out. People often think that means that the rule with the most “things” in the declaration wins out – so div.attributes wins out over .attributes. But it’s not as simple as that – which is more specific between .page .attributes, div.attributes, and .attributes input?

It turns out that different selectors have different weights. A class is more specific than an element.

Calculate a Specificity Score, looking at the tiers of Selectors in this order, from lowest to highest:

  1. Elements, Pseudo-Elements
  2. Classes, Attributes, Pseudo-classes
  3. IDs
  4. Inline Styles
  5. !important

Each rank has a score 10x greater than the previous one. So each element is worth 1 point; each class is worth 10 points, each ID is worth 100 points, each Inline style is worth 1,000 points, and Important is worth 10,000 points.

Note: this is a simplification. In practice, one item of any give rank is enough to override any number of selectors of lower levels, but this simplification works for nearly all situations.

Here are a few of examples. Try to calculate the score before looking at the next tab.

div.test {display: inline-block;}
.attributes input.stat {padding: 5px}
div.top div#my-id.bottom input[type=text].names {font-size: 18px;}Code language: CSS (css)
div.test {display: inline-block;}
.attributes input[type=text].stat {padding: 5px}
div.top div#my-id.bottom input[value="3"].names {font-size: 18px;}Code language: CSS (css)

Let’s calculate the Specificity Scores for these examples.

The first has an Element (1 point) and a Class (10 points), so that’s a score of 11.

The second has a class, an element (input), an attribute (equal to a class), and another class. That’s 3 classes and an element, so 31 points.

The last contrived monstrosity has an element and class, containing an element with an id and a class, which contains an element, an attribute (equal to class) and a class.

So we have 1 ID (100), 4 classes (40 points), and 3 elements – total specificity of 143.

Zero Values

  • Inherited properties are overridden by any targeted declaration. (This is important for the above question.)
  • The universal selector is also beaten by any other targeted declaration.
  • The various operators than can modify attributes (~ + $ etc. ) have no effect on specificity.
  • The :not() rule adds nothing to specificity, though whatever it contains still counts, so :not([value=1]) counts as a single attribute selector.

Styles and !important

These aren’t considered to be Specificity values, but they work exactly the same, so for simplicity, they are included here.

It’s moot most of the time, since you shouldn’t use either except when there is no alternative.

Order in the CSS File

When Specificity is equal, and only then, the last item in the CSS file always wins. This means that the CSS rules you create always override styles set by Roll20, when specificity is equal. That will be important in the next post.

So, getting back to the original question, which of these is most specific when looking at the input inside attributes?

.attributes { color: red; }           /* score = 10            */
.page .attributes {color: blue; }     /* score = 10 + 10 = 20  */
div.attributes {color: green; }       /* score = 10 +1 = 11    */
input {color: purple}                 /* score = 1             */
.attributes input {color: orange;}    /* score = 10 +1 = 11    */Code language: CSS (css)

Looking at these rules, the second has the highest specificity score at 20 points.

But wait, we are looking at the input, and the top 3 rules are inherited rules – they don’t mention the input specifically. So they are discarded, and only the bottom two rules matter.

Of those, the bottom declaration has the highest specificity, so the text is orange.


More About Inheritance

Properties which apply to specific elements don’t get inherited. Say you have a block like this:

<div class="top">
    <div class="bottom">
       <h2>A Heading<h2>
       <p>Some text</p>
    </div>
</div>Code language: JavaScript (javascript)

If you add a border to the top div, it only applies to that div. If the items inside it all got borders, it would look pretty bad.

There’s no comprehensive write-up saying which properties get inherited and which don’t, but you can usually go by common sense. What makes sense not to be inherited usually isn’t.

Properties That Don’t Appear To Be Inherited, But Are

Likewise, properties are always inherited even when they don’t have any visible effect. For instance, if you apply the property text-align:center to a div, it doesn’t directly affect that div or any divs within it, because divs don’t have the text-align property. But the properties are still there and can be passed on to any elements within the divs, like the headings and inputs.

Inherit

Imagine that block from the previous tab. Say you wanted both divs to be bordered. You could create declarations to border them both, perhaps grouped together like so:

div.top,
div.bottom {
   border: 1pt solid black;
}Code language: CSS (css)

But you could instead force the bottom div to inherit the value, like so:

div.top {
   border: 1pt solid black;
}
div.bottom {
   border: inherit;
}Code language: CSS (css)

In this contrived example, grouping the declarations is probably better, but there are situations where inherit makes sense – and as shown here, it can cause an element to inherit properties that normally can’t be inherited.

Every element has its own default values. initial is a special property value that simply restores those initial values.

All is a special property that allows you to apply a property value to all properties at once. Roll20 has a lot of defaults built-in, so it’s usually not a good idea to use it at all. You don’t want to erase all those properties. It is better to be selective. But if you did use it, it would look like this:

input.example {
   all: initial;
}Code language: CSS (css)

Initial is not very useful on Roll20, because elements have so many styles already built in to them to make them fit a character sheet. If you use initial, you’d have to assign a lot of your own properties – it’s better to use specificity to selectively override the ones you need to.

But it’s listed here for completeness.


Series Navigation<< How To Hide and Reveal Things With CSSAdvanced Positioning >>

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.