I've been learning some HTML & CSS recently, and I had a question on how CSS style priorities work and also which style gets applied when we have conflict situations.
So let's look at the following code:
.container {
color: green;
}
.things {
color: blue;
}
p#item {
color: yellow;
}
#item {
color: orange;
}
.things .container {
color: brown;
}
p.things {
color: red;
}
<div class="container things">
<p>A</p>
<p id="item">B</p>
<div class="container">C</div>
<p class="things">D</p>
</div>
Now based on the answer key provided to us, the colors of the different elements are: A-Blue, B-Yellow, C-Brown and D-Red. Now B & D, I find pretty easy to understand. However, I don't understand how A & C got the colors that they did. I guess essentially I'm struggling to see why A & C aren't the same color. Could someone explain how it all works?
Thanks
Lets get into styles one by one,
Here you color everything to green, by default
.container {
color: green;
}
Now you overwrite(only those elements which have both classes container and things) to blue,
.things {
color: blue;
}
(in your case it is the parent div, so everything will now have a blue color )So here everything including A and C becomes Blue
So here ,
A-> Blue
B-> Blue
C-> Blue
D-> Blue
Now you color container which is inside the things(so only C satisfies this condition) to brows, thus c is brown.
.things .container {
color: brown;
}
So here ,
A-> Blue
B-> Blue
C-> brown
D-> Blue
Also,
p#item{
color: yellow;
}
#item {
color: orange;
},
here though #item is colored orange at last, still p#item has the most specificity, so the color for B becomes yellow
So it becomes,
A-> Blue
B-> yellow
C-> brown
D-> Blue
And finally you give this style,
p.things {
color: red;
}
Only D satisfies this rule, so D becomes red
So final result is,
A-> Blue
B-> yellow
C-> brown
D-> red
CSS styles are applied from top to bottom and if you applied multiple classes on 1 element like your .container class first applies the color:green which is overwritten by the the color:blue from the .things class.
So first you applied the .container class that initially applies the color:green on the all the DOM elements. Then .things class overwrites the style by applying 'color:blue' which shows the A in blue color. Then B gots the style from .item class and changes its color:blue to color:yellow and then you applied .container class again on the <div> which contains C which overwrites the color:blue to color:green again. And at the end you applied the .things class to your <p> which overwrites the color:blue by color:blue.
But if you are confused in the order of CSS classes, You can overwrite the style by forcefully applying the color you want by using !important at the end of your styles.
like in your container class :
.container {
color: green !important;
}
it will apply the same color on A and C whatever the classes order or styles, it always applies the green color to the element which contains multiple classes including .container. and other classes.
Working Fiddle Here.
Edit:
If you want the style to not be overwritten by any class and always applies the style(means all the styles including color) that you have define with the !important.
CSS is a Cascading Style Sheet, which means the styles are applied from the top to the bottom. The first <div class='container things'> first gets the color:green style from the container class, but then that is overwritten by the color:blue by the things class. Now since the first <p> tag inside that div is not being targeted by any CSS, it inherits the color from its parent, which is blue, hence A becomes blue.
As for C, the lowest selector that targets C is the .things .container selector, which targets elements with the container class that are inside an element with a things class, resulting in C being brown.
Also check out the other answers for information about specificity.
CSS specificity said that stronger always win.
See his link to calculate what ruke is stronger than others: css-specificity
In fact, Id is stronger than class that is stronger than elements.
Style elements (inline) is stronger that Id, and there is again strongest than inlin: the !important; so
!important; > inline > Id > class > elements. You can combine multiple id, class or elements to make difference.
If some rules are exactly equals, the latest take the advantage.
See this funny picture to understand it:
in simple word, the more specific one gets selected so for example if you add these lines of code:
<p class="things" id="ye">D</p>
p.things#ye{color:black}
the D is gonna be black because you had more selectors.
Related
Say, I want to change the background color of all the content in a paragraph that does not have any text-decoration (like bold, underline, etc.). Is it possible to do it just using CSS with a some kind of syntax like this?
p[text-decoration=none] {
background-color: yellow;
}
A sample HTML content that this CSS should be applied will be something like this:
<p class="special">Yellow background <b>default background for paragraph</b> yellow
again <i>default</i> once again yellow.</p>
Requirements for the above to work:
Do not add style and/or class attributes to the paragraph contents, i.e., to <b>, <i>, etc.
Do not change the styles for <b>, <i>, etc.
Background-color should be specified for any content (HTML or CSS-style based) that does not have any text-decoration.
The parent of <p> may have a custom background-color, so elements like <b> or <i> should assume that color.
It is impossible to make the absolutely correct decision according to your requirements with the help of CSS. But you can apply a little trick, which is to use the CSS variables declared inside :root.
The principle is to use the same background color for the background of the main parent and the background of tags b and i. You need to declare a variable like this:
:root {
--backColor: yellowgreen;
}
Next, using function var(), assign the declared variable for rules background-color, body tags (parent), b and i:
background-color: var(--backColor);
In pseudo-class :is(), you need to specify tags (b and i) for which the background color of the variable will be assigned.
:root {
--backColor: yellowgreen;
}
body {
background-color: var(--backColor);
}
p {
background-color: yellow;
display: inline-block;
}
p * {
display: inherit;
}
p *:is(b, i) {
background-color: var(--backColor);
}
<p class="special">Yellow background <b>default background for paragraph</b> yellow again <i>default</i> once again yellow.</p>
I am getting red background-color for both h1. For the first h1, ID has the highest precedence and for the second h1, the inline has the highest precedence. Why?
#myid { background-color: pink; }
.main h1 { background-color: red; }
div h1 { background-color: blue; }
h1 { background-color: green; }
<!-- the background-color expected
to be pink for the following h1 -->
<div class="main" id="myid">
<h1>This is paragraph one!</h1>
</div>
<!-- the background-color expected
to be brown for the following h1 -->
<div style="background-color:brown;" class="main" >
<h1>This is paragraph two!</h1>
</div>
Both of these have to do with whether the style is applied directly to the element or to the parent element.
In both cases, your intuition is correct for the outer div.main element. However, there are rules that apply to the h1s that, while less specific, apply directly to the h1s so they take precedence over the more specific rules that apply to the divs.
Styles for a directly targeted element will always take precedence over inherited styles, regardless of the specificity of the inherited rule.
https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity#Directly_targeted_elements_vs._inherited_styles
You are not applying the background to h1 element but to its parent element. Considering this, there is no specificity here because we only consider the rules applied to h1 and if no rules we consider inheritance (the styles applied to parent element that get inherited by childs). Also background is not a value that get inherited by default so inheritance will not apply here even if you don't specify a background to h1.
So in this case the red will always win because it's the rule with highest specificity applied directly to h1.
The pink background is present, but it's being hidden by the red background of the H1 that's sat on top of it.
If you add some padding to the #myid styles the you will see a pink outline around the red of the H1
I have something like this
<div class="text-holder">
<h2>this is text-holder</h2>
<p>this is text</p>
</div>
<a href="#" class="ignore">
<div class="text-holder">
<h2>this is text-holder</h2>
<p>this is text</p>
</div>
</a>
<a href="#">
<div class="text-holder">
<h2>this is text-holder</h2>
<p>this is text</p>
</div>
</a>
And CSS that does this
.text-holder {
color: green;
}
a {
color: red;
other css
}
.ignore {
other css
}
Is there a way that the link can ignore the css style for the global a style, and just use the ignore? I don't want to use !important because there will be other instances of text-holder that will want to use the global a style.
EDIT
Thanks for all the replies, but let me be a little more clear so hopefully you understand better. (Not the best at explaining)
The problem is text-holder has it's text styling from global p, h2 and etc. Which are above a in the hierarchy of the stylesheet. so p, h2, a, .ignore, .text-holder etc
a has a lot of info on it, hover, visited, focus, color, font-weight and etc. Now for all the divs I wanted to ignore this info I was looking to see if there was a simpler way of just creating an ignore rule, rather than for all the divs I want to ignore it to overwrite them with all the rewritten information.
CSS doesn't support "ignoring", but part of its nature (the Cascading part of Cascading Style Sheets) supports "overwriting"; Newer CSS properties will overwrite older CSS properties of the same name, so you just need to give .ignore a different color value than your previous a selector's color value.
Is there a way that the link can ignore the css style for the global a style, and just use the ignore?
No. If a selector matches then all applicable rules in it will be applied.
.ignore is at least as specific as all preceding rules, so you just need to set the properties you want to override to the desired value.
Yes, basically what you're trying to do is already how CSS works.
The key to understand is the concept of specificity.
CSS rules applied through the style="" attribute have a weight of 1000.
Rules applied against an #id selector have a weight of 100.
Rules applied against a .class selector have a weight of 10.
And rules applied against an element tag name or :pseudo-selector get a weight of 1.
So for example, if you have...
a { color: red; }
.ignore { color: black; }
The weight of the red links is 1, while the weight of black text is 10, so the black has higher specificity and would win.
The important concept is that .ignore doesn't tell it to ignore its old assignment, it is instead a way to override the assignment.
EDIT
I should also add that cascading rules have no weight, so any definition in a child element will override them.
For example:
a { color: red; }
.ignore { color: black; }
div { color: blue; }
<a class="ignore"><div>hello world</div></a>
The text will be blue, not black, because the div tag has a rule applied to it which overrides the cascading black from the .ignore class.
You can try:
:not(.ignore) .text-holder {
color: green;
}
Or if you move your ignore class to .text-holder element
.text-holder:not(.ignore) {
color: green;
}
Is it possible to apply certain CSS to any element, except descendants of a certain class?
Here's a fiddle: http://jsfiddle.net/68jgdthm
As you can see I want everything on the page to be dark except elements which are descendants of the light class. The trick here is that one can't know if the element is a direct descendant, e.g. it might be this:
<div class="light">
<p>Element</p>
</div>
but it might also be this:
<div class="light">
<div>
<div>
<p>Element</p>
</div>
</div>
</div>
The dark class is almost always added to the body element and will always be a parent of any light classes.
One might say:
Just make the body "light" and add dark classes to any elements you need. - But I actually need the opposite, I need everything to be dark and certain elements to be light.
Then add "light" styles and add the light class to elements you need. - I already have the dark styles, so I'm looking for an easier "excluding" solution (I'm using LESS, so prefixing etc. is quite easy).
You will not be able to exclude descendants this way without writing a separate selector. You won't be able to do this even using :not(), for the reasons stated here.
Fortunately, the fact that .light elements will only ever occur within the context of a .dark element and not vice versa makes this a little easier. Since you have a body CSS rule already, just add .light p to that rule, and move the entire ruleset underneath .dark p so .light p will take precedence:
.dark p {
color: #000;
}
body, .light p {
color: #ccc;
}
Updated fiddle
Alternatively if you want to keep the body rule on top, you could bump up the specificity of .light p to ensure it will take precedence:
body, body .light p {
color: #ccc;
}
.dark p {
color: #000;
}
Color is an inherited property. Therefore just by declaring .dark and .light to have the wanted color is a good thing. You can make a default by assigning it to the body. I think atomic design like this is a good practice, as you don't add too much specificity in your CSS.
You could do this:
body {
color: #ccc;
}
.dark {
color: #000;
}
.light {
color: #fff;
}
Demo: http://jsfiddle.net/68jgdthm/1/
I have a case where I have a .menu within a #header and when I accessed .menu's children via a css selector like .menu a, it is using the #header a instead.
I was expecting the .menu a to override the #header a as it is closer to the a element. Why isn't this happening? I'm assuming it has with it being a class compared to an id based on the example below.
In the example, is there a good way override #red span css within .blue span without otherwise restricting the parent style?
By "good way" I suppose I mean flexible. For example .blue could be an element created by a php framework that is used in many places (possibly not within an id styled parent element, or possibly within a parent styled on a different id).
Here is an example. All except #green will still be red:
HTML:
<div id="red">
<span>red</span>
<div class="blue">
<span>blue(class) - should be blue</span>
</div>
<div id="green">
<span>green(id) - should be green</span>
</div>
<div class="green">
<span>green(class) - should be green</span>
</div>
<div>
<span>no child div style - should still be red</span>
</div>
</div>
CSS:
#red span {
color: red;
}
.blue span {
color: blue;
}
.green, #green span {
color: green;
}
The priority of applying a CSS rule (without !important) is:
Number of IDs in the selector. If draw,
Number of attributes and classes. If draw,
names or pseudo-elements. If draw,
last declaration on the CSS file. This, of course, never draws.
Since #red span has an ID, and .green doesn't have any, #red span applies.
For further explanation of which CSS rule is apply first, check this nice article on smashing magazine
To work around, you can use a more specific rule. This way it gets tie on number one, but since it have extra classes, your rule wins due the number two.
Selector specificity dictates that id had priority over class. Even though the blue class is after red in the Cascade, red takes priority because of specificity. You can use the Selector #red .blue span if needed
the simplest and cleanest:
http://jsfiddle.net/f4ke2/7/
#red {
color: red;
}
.blue span {
color: blue;
}
.green, #green span {
color: green;
}
OR What if you do this? :)
#red > span {
color: red;
}
OR
#red .blue span {color: blue;}
OR
.blue span {
color: blue !important;
}
OR for "flexibility"
#red .blue span, .blue span, #someotherID .blue span {color: blue;}
OR something as horrid as this
var id = $("#red");
id.addClass(id.attr("id")).removeAttr("id");
If you are using style sheets (in a framework or otherwise) that assign properties to elements by class, i.e. using class selectors, you simply have to take this into account when writing other CSS rules. So this is a matter of disciplined coding (HTML and CSS), not about using some trick to get rid of normal CSS principles.
Basically, set properties only on those elements that you want to have affected, without using selectors with too wide coverage. Say, if you want to set the text inside some element red, set color: red on that element only, not on its descendants, unless you really want to override whatever settings they might have.
For example, if there is a style sheet with .foo { color: blue }, then this will affect any element in class foo, unless overridden by another rule, as per the CSS cascade. So if you don’t want it to be overridden in a situation like <div id=xxx>...<span class=foo>...</span>...</div>, you just can’t set #xxx span { color: red }, because then you would override the rule, by virtue of a more specific selector. Using #xxx { color: red } would be safe in this sense, since the span (having its color set) will not inherit its parent’s color.
Using !important as in .foo { color: blue !important } might seem to solve the problem, but !important makes style sheets difficult to manage and maintain. It also creates problems when you need a tool for overriding the effect of specificity but can’t, because you’ve already fired the weapon. The rule .foo { color: blue !important } is not effective against #xxx span { color: red !important }.