Reputation: 16045
I'm trying to wrap my head around something about CSS. I've always thought that the order of including CSS files matters (the "cascading" part of it). I'm using Bootstrap 3, and trying to override the background color of the active top nav links.
The exact selector I have to use in order to do this is: (SCSS actually, but that shouldn't matter)
.navbar-default .navbar-nav > .active > a {
background: $sp-blue;
color: #fff;
}
And then scss-lint
yells at me for having a depth of applicability greater than 3. But if I try this:
.navbar-nav > .active > a {
background: $sp-blue;
color: #fff;
}
then it stops working. This is what I don't understand. Why do I have to include .navbar-default
in the selector? If .navbar-nav
is within it, I shouldn't need more than that. It's annoying to have to copy the selector exactly as it's used in the previous stylesheet. Now, if I use !important
, then it works, but we all know that's bad practice.
Can someone help me grasp this aspect of CSS?
Upvotes: 1
Views: 256
Reputation: 976
This is a FANTASTIC question! This shows you are actually thinking through css rather than the millions of novices who don't ask and just 'important!' whenever there's a problem. But you are EXACTLY right. Supposedly well-written CSS has the following constraints:
Do not use 'important!. 'important!' breaks the cascading nature of CSS and opens your design to problems with maintainability and simplicity: See: What are the implications of using "!important" in CSS?
Avoid a large 'depth of applicability' For the same reasons as 'important!' again this results in a design that is not as maintainable, simple, or easily redesigned: See: https://smacss.com/book/applicability
Don't modify your framework code Certainly you shouldn't go back and modify your framework's CSS. What if you need to update this code in the future, or some automated process overwrites it? Your code breaks.
One solution (if you believe in the above) is to use the CSS rules them self and target your elements in a more efficient way. Using a CSS specificity calculator such as this one:
We can see other ways to target your element better. According to the calculator, the specificity of your element is 0031. However, a single id
#mynav {
background: $sp-blue;
color: #fff;
}
scores 0100 and would satisfy the above constraints. One problem is that some ALSO say...
Don't use IDs For similar reasons as the above: See: http://oli.jp/2011/ids/
We could also use 'inline style' (as you can see from the calculator), however....
Don't use inline styles What's so bad about in-line CSS?
So is there any other way to 1) increase the specificity 2) without increasing the depth, and not using 3) IDs 4) 'important!' 5) inline styles, or 6) modifying your framework code? Well by assigning multiple classes to an element (or parent), we can increase specificity without increasing depth of applicability. Of course this would also work
.thislink1.thislink2.thislink3.thislink4 {
background: $sp-blue;
color: #fff;
}
Now, of course, you don't have to assign 4 different classes to your anchor just to be specific enough or to have your depth less than 3. If you assign a class to the parent
.navbar-nav.mynav > .active.myactivelink {
background: $sp-blue;
color: #fff;
}
this scores 0040 (depth of 2). You could perhaps simplify this further if you are sure that your css modifications are loaded last (since the later loaded rules take priority).
.navbar-nav > .active > a.mylink {
background: $sp-blue;
color: #fff;
}
this scores 0031 (with a depth of 3), like your bootstrap CSS, but if it's loaded after the bootstrap it will be applied.
The takeaway: CSS is not a computer language studied by experts to quantify metrics such as cyclomatic complexity and code quality, it is a style sheet language without much rigorous study of objective measures. It is easy enough to learn that you have many inexperienced armatures and more bad advice than hard evidence. I am certainly no expert so take the above as 'options'. Realize that style is important to learn from the pitfalls others have suffered from. But your particular situation includes your preferences and type of development environment you are in, and how much time it takes to learn all this advice.
Upvotes: 0
Reputation: 538
That's becuase .navbar-default .navbar-nav > .active > a
is more specific than .navbar-nav > .active > a
.
Although the ordering of stylesheets have something to do on how the browser will analyze which css is more relevant, CSS specificity also plays a role.
Basically, the more specific your CSS selector is, the more relevant it is for the browser. Say, we have your css ordered like this:
/*this will be followed*/
.navbar-default .navbar-nav > .active > a {
background: #fff;
}
/*this will be ignored*/
.navbar-nav > .active > a {
background: #000;
}
Although the second selector is ordered last, it cannot override the previous selector, simply because it has a weaker specificity. It can override another css only if it has an equal or greater specificity than the previous one. But of course, !important
is an exception to that rule.
Further Reading: http://css-tricks.com/specifics-on-css-specificity/
Upvotes: 4