Overriding CSS and number of selectors - css

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?

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/

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:
http://specificity.keegan.st/
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.

Related

CSS: Best practice for selecting deeply nested elements [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I frequently need to address generic elements inside some specific sections of a page. I find this approach most easy to understand in terms of what any rule is affecting:
.shop > .products > .product > .description > .warning {
color: red;
}
But I often see this:
.shopProductsProductDesc > .warning {
color: red;
}
Does it really matter which approach is taken?
It really depends on the problem you are trying to solve.
The selector .shop > .products > .product > .description > .warning to my understanding would be used for two cases:
You have multiple warning elements but you only want to select the elements inside your description and there are other selectors used for warning that you don't want to overwrite.
You need to overwrite a previous selector that is less specific. Ex. .shop > .products > .product > .description .warning
The other selector .shopProductsProductDesc > .warning is less specific than the first one but assuming the container of .warning has those two classes .description.shopProductsProductDesc then the outcome would be the same as the first one.
CSS is all about specificity, if your selector is more specific than the last one used the properties would change. This is why you have to be careful if you are using specific selectors because your last option to alter the properties would be to use !important.
I hope this helps to clear things out.
After trying a few different styles, I think that personal preference (or a set standard if you have collaborators) is really the way to go. I prefer the second version, but the first one is also quite legible.
If you consider efficiency of what the browser has to do under the hood to render CSS styles, BEM-style for example, is usually the ultimate winner as it is the most lightweight for the browser. I use BEM for some layout/common elements.
In real life unless you are doing something seriously wrong, modern browsers and devices make this difference of CSS parsing and rendering somewhat negligible. But that is if you code everything well.
I've worked with spaghetti CSS codebases that could take minutes to render all SCSS (it was a huge codebase, but a few files were big bottlenecks).
It matters because of specificity. The first style rule will always override the second, regardless of where they both appear in the stylesheet, because it is more specific (basically it has more class selectors in it).
That said, the first rule is a nightmare from a maintainability perspective, for a number of reasons:
It makes code incredibly hard to read and understand
It's harder to override (as we have seen).
If you change the structure of the HTML, it will break
You can only reuse it if you mirror the structure of the HTML exactly.
It's also bad from a performance perspective. When browsers are matching an element to a style rule they read each selector right-to-left and keep going till they either find a match or can exclude the rule. Therefore, the more simple the selector is, the faster a match can be determined. If a selector consists of just a single class name, the browser can match the element with the style rule more quickly than if it has to search upwards in the DOM tree.
The second rule is better, but optimal would be something like the following:
.shopProductsProductDesc--warning {
color: red;
}
This solves all the problems above, and it's long enough that there's unlikely to be name clashes elsewhere, (though obviously not impossible).
In general, nesting selectors in CSS is bad practise, in my opinion, and the best CSS methodologies are those that have ways of avoiding this, e.g. BEM, CSS-in-JS.
According to my own experience, the second option is often best, not for direct technical reasons (in fine, it will perform the same), but rather for UX consistency and code maintenance.
The first option produce an "heavy" selector, which will be harder to override. It can be wanted, but it is often the sign of an overall messy CSS, because if everything is overconstraint, it is less easily reusable/extensible.
From my understanding of CSS and frontend reusable components, you would always only need two levels.
The style of your warning component (no size, no margin, size depends on where you will display it, and margin is position, only internal design here):
.warning {
//Your design here
font-size: 1.5rem;
font-weight: bold;
color: orange;
}
And the positionining and variants inside containers:
.container > .warning {
//This is an example.
position: absolute;
right: 0;
border: solid 1px red;
}
Having long CSS selectors will make things more complex, hard to follow for your teammates, and hard to override because you will probably need a longer CSS selector, and it never ends. Plus, you will get an heavier bundle at the end.
If you want an efficient UX, the UI shouldn't be that different everywhere, so you should not need to have that many variants of the same component. Otherwise, maybe you need multiple different components, but you certainly want a simple and efficient UX, and that often goes with not so much visual concepts, so you must avoid tons of variants.

Overriding CSS Hover Colors and !Important

I'm working in WordPress and I have one part of the site colored and styled like normally but there is a secondary part of the site that is colored in darker styles. I have been able to separate the two's CSS mostly with the use of classes and !important. I am having a spot of trouble in the menu area.
In the majority of the site I have the following when hovering over the menu:
.header-menu li:hover, a:hover {
background-color: #b89230 !important;
color:#fff4d6;
text-decoration: none !important;
And on what part of the site I have:
.page-template-cryptofact-page-php .header-menu li:hover, a:hover {
background-color: #836F38;
}
As it is written above, the .page-template css is taking on the background color hover of the rest of the site. If I !important the css of the page-template, then the rest of the site takes the coloring effect instead, regardless of its own !important style.
I've tried removing !important postscript from both, swapping either one, and adding it to both and I still cannot get them to act on their own. I was hoping that designating .page-template-cryptofact-page-php would be enough, since it seems enough for all the rest of the styling.
When I open to inspect the element in source, all of either .header-menu or .page-template-etc is grayed out leaving the a:hover as the instigator on either problem.
I'm fairly new to the nuances of CSS, so if someone could explain why this is happening I would greatly appreciate it.
I would post the site but it is insecure so it would not be a good idea. I can post screenshots or any other information you need.
Here I have placed a couple images:
I'm making a bit of an assumption here as to what your problem is, because I'm not 100% sure what you've got going on, but I believe you are mis-using the , in your selectors.
The comma breaks up totally distinct selectors, so if you want to style certain elements under a certain class, you would need to include that class on both sides of the comma, so you should end up with something like this:
.header-menu li:hover, .header-menu a:hover {
background-color: #b89230;
color:#fff4d6;
text-decoration: none;
}
.page-template-cryptofact-page-php .header-menu li:hover,
.page-template-cryptofact-page-php .header-menu a:hover {
background-color: #836F38;
}
Removing the !importants is probably a good idea... they usually make things more difficult to maintain.

CSS grouping :hover & :active

When I want to define css selector with :hover and :active I have to do:
#mainPage #content div.group:hover, #mainPage #content div.group:active {}
As one can see it contians repeated #mainPage #content div.group and can get messy. Is there a way to group it somehow like:
#mainPage #content div.group:hover:active {}
In pure CSS there is not much of a better way to handle both more succinctly without adding a class or ids.
You could consider a CSS pre-compiler (like LESS or SASS/SCSS).
In LESS or SCSS:
#mainPage #content div.group {
&:hover, &:active {
color: red;
}
}
I suggest add ID for the element has class group and write below code will reduce the effort:
#idname.group:hover, #idname.group:active{}
Is there a reason why you're using #mainPage #content before div.group?
Generally, it's not necessary to add that much 'specificity' to your selectors - it's better to instead, have unique classes. So make sure that the class .group is only used for elements that you want to have the same styles.
If you do that, you should be able to style those elements just using
.group { styles here}
You might run into an issue now where if you try to override any of the styles you set like #mainPage #content, those will be more specific and so in effect 'stronger' than styles where you don't use the full list of parents. If possible, change all your styles not to include the parent elements - this is also worthwhile in case you ever want to move an object to a different part of the html!
It's also, in general, advisable not to use id's (#name) to attach css styles - if possible, just use classes. Unless you're doing javascript, you shouldn't have much need for id's.
Obviously there exceptions to the above, and for all I know you may have a perfectly good reason for doing things the way you have - in which case SASS (as suggested in a few other answers) is a good solution for you.
If not useful for you, I hope at least this answer might be useful for someone who might come along later - I've noticed that a lot of people newer to css don't realize how specificity of selectors works and end up making their styles a lot more complicated than necessary as a result! :)
Old question, but this should be relevant for somebody who needs this.
Pseudo-class released by the end of 2020
You can use :is() pseudo-class like so :
#mainPage #content div.group:is(:hover, :active) {
}
Here is a little snippet to picture it :
a:is(:hover, :focus) {
color: red;
outline: #5bc8ea dotted 4px;
outline-offset: 4px;
font-weight: 600;
}
Hover/Focus me
More informations about :is() pseudo class here: https://developer.mozilla.org/en-US/docs/Web/CSS/:is and here: https://css-tricks.com/almanac/selectors/i/is/.
Works with most of the popular browsers (incompatible with IE, Opera and Safari < 14) https://caniuse.com/css-matches-pseudo.
It surely is more often used to select elements than pseudo-classes like :hover or :focus but it will do the trick as I can't see any other solution for now.
Why you use #mainPage #content? #content should be enough to find the div your looking for without the #mainPage.
Also id's are only allowed to be used once and not in multiple places like classes are. Id's are usually reserved for script assignments and not CSS. I would do
#content .group:hover{}
#content .group:active{}
if i understood correctly, you want a group of elements to act a certain way? manipulate the parent class then.
.parent-class:hover {
.child-class {
…desired styles go here
}
}

Using a general purpose selector as a mixin in LESS CSS

I know about mixins and parametric mixins. What we are looking for is a way to make any general purpose selectors in CSS / LESS into a mixin.
Eg in Twitter BootStrap, we have here
.navbar .nav > li {
float: left;
}
If I have to use it in a class say .mynavbar I want to be able to do this
INPUT->
.mynavbar {
.navbar .nav >li;
}
OUTPUT->
.mynavbar {
float:left;
}
Now I know this can't be done with the current version of LESS as the compiler flags a parser error. I wanted someone to help me out on changing the source code of less.js a little so that this is workable.
I've managed to reach the source code for the mixin parser. I've tried changing the RegExp there, but it interferes with other parts of the parser. I know we have to make only a few changes because, instead of just accepting .mixin and #mixin we have to accept any mixin like tags / attribute selectors like input[type=text].
It is currently needed for the development of a UI framework that uses Bootstrap. Unfortunately many places in bootstrap are littered with direct tag selectors instead of ids and classes.
This is possible since version 1.4.0 (2013-06-05) of LESS that include the extend feature. Based on the original example
.navbar .nav > li {
float: left;
}
.mynavbar:extend(.navbar .nav > li) {}
compiles to
.navbar .nav > li,
.mynavbar {
float: left;
}
Documentation here and discussion & example use for the original question here
EDIT: Added Code Sample
First off, I would strongly discourage doing such things. Instead, try to use the power of CSS and build your HTML such that the bootstrap rules apply, for example. Anyway, since you asked for it, here is the solution.
The problem is not the complexity of the selector, or the child rule, but the tag name selector part (i. e. the li). So, what we have to fix is the mixin parser only matching classes and ids. I guess we would not want to tamper with the first class or id test, since that is probably needed to distinguish mixins from normal CSS rules (although the tests run fine with that check commented out). (Actually, there is a parser preference in action, and the only thing tried after mixins are comments and directives, so we can safely remove that check as well). However, we can easily allow tag names in later parts of the mixin selector by adding a question mark after [#.] in the matching regular expression. So
while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) {
– i. e. line 825 – becomes
while (e = $(/^[#.]?(?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) {
The test cases still run through fine, afterwards, but subtle breakage my occur, so be cautious.
Edit: There is a GitHub Issue for the same problem. Apparently the less folks rather want the mixin feature to be more narrow and function-like, instead of allowing a more flexible … well … mixing in of rules. With regard to the CSS output, that's probably reasonable.

Make entire CSS sheet !important

Is there a way to make an entire CSS Style sheet take precedence over another? I know you can do the !important but can I do that with one line rather than modify all thousand properties on the sheet?
Thanks!
Make sure the stylesheet you want is called last (or a specific style you want is called last). For example, using this:
span { color: red; }
span { color: blue; }
...will turn all text in <span>'s blue. Take a look here.
Rules with identical specificity that come later will overrule previous ones, so if both style sheets contain the identical selectors, you should be able to do this by just loading the one before the other.
If they contain different selectors, like
#navigation h3 { color: red }
and
.mainpage .navmenu h3 { color: blue }
you are likely to get specificity conflicts. The only blanket solution for that is indeed !important (although that is really, really terrible architecturally. Are you sure you need this? Maybe explain why, it's possible somebody is able to come up with a better solution.)
There is, however, no single-line directive to elevate the "importance" of one style sheet over the other.

Resources