How does specificity work with inherited styles? - css

HTML
<div class='container'>
<p>foo</p>
</div>
CSS
.container {
color: red;
}
p {
color: blue
}
Code Pen
The applied color is blue. Why is this? I was thinking that since .container has more specificity than p, the color would end up being red.
What is happening here? Why is it blue?
My hypothesis is that the process is "Does p have any selectors? If so use it and don't look up for .container. If it didn't have any styles, it'd look up and use the style for .container."

From the MDN page on Specifity
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
Hence p will override .container no matter what. The inherited style from .container is overwritten

think of the css in this specific case as a target bulls eye.
you start from the most specific pointer to your element in question.
in your example above, it is the p selector since the text is within the p tag wrapper. then going outward from that (the ring right outside the bulls eye, if you will) is the .container div. since the target p is closest to the text you want to color, it inherits that css (color text of blue).
in the example below:
.container {
color: red;
}
p {
color: blue
}
<div class='container'>
i should be red text since im outside the p tag but inside the div container
<p>foo</p>
</div>
you see that the text "i should be red...." doesnt necessarily have a "bulls eye" css, so it goes one ring outside and sees .container and is assigned the color red.
========
now to answer your question about specificity
specificity applies to a case like the example below:
.makeMeBlue {
color: blue;
}
.makeMeBlue.actuallyMakeMeRed {
color: red;
}
<div class="makeMeBlue">i am some random text</div>
<div class="makeMeBlue actuallyMakeMeRed">some more text here</div>
in the above example, you see that make .makeMeBlue has css to make the color of the text blue. however, the second .makeMeBlue div's text color is red. this is because we were more specific about targeting the second element. we used the selector .makeMeBlue.actuallyMakeMeRed utilizing both classes of the element to say "this is the element i want to target specifically and assign this css to".
so instead of the element being like "developers are blue, ok i'll be blue" it sees "hey, someone just said all developers who are named 'jason' are red, and my name is jason and i'm a developer - it is more specific to me, so i'll be red".
i hope that explained specificity a little more clearly.

Related

The order of a descendant combinator CSS definition [duplicate]

This question already has answers here:
Understanding CSS selector priority / specificity
(4 answers)
Closed 4 years ago.
This must be a very simple question for HTML ninjas out there, but I feel I'm missing something obvious here. Here is a snippet:
#red span {
color: red;
}
#green span {
color: green;
}
<div id="red">
<p><span>red</span></p>
<div id="green">
<p><span>green</span></p>
</div>
</div>
If I swap the stylesheet order, all of the text becomes red:
#green span {
color: green;
}
#red span {
color: red;
}
<div id="red">
<p><span>red</span></p>
<div id="green">
<p><span>green</span></p>
</div>
</div>
This happens despite the fact that <div id="green"> is a more inner parent of <span>green</span> than <div id="red"> in the DOM tree. I suppose it doesn't take precedence simple because its CSS now appears first in the order of stylesheets. So the order of stylesheets is what matters here.
Is this an expected behavior? Is this implementation/browser specific? Is there some official specs detailing that?
Finally, is there any CSS selector syntax I can use to make it work as in the first snippet, without relying on the order of stylesheets or adding new class names, ids, etc?
Yes, the result you got is absolutely expected—well, maybe not expected, but they are correct. Here are the official specs. And here’s a tweet poll of mine detailing the exact same problem. (Spoiler: the majority of voters got it wrong.) Read the replies for a more in-depth discussion.
Currently, there’s not any CSS technology that takes “closest parent” scope into account. And this is a common misconception a lot of programmers have. (CSS is not a programming language.) A typical programmer will think, “The selector #red span means wherever I see a #red, look for a span inside, and then apply the styles. Since #green span is inside the #red, the green will apply after the red.” This is simply incorrect.
The way CSS actually applies styles is that it looks at each element, then goes through the stylesheets from top to bottom, decides if it matches, and then applies/overrides styles as it goes. That’s just one aspect of the cascade, among others (such as inheritance and specificity). Since in your second example #red span comes last in the CSS source, it gets applied last, overriding #green span, regardless of “how close” the span is within the #red in the DOM.
To fix your specific problem, the easiest thing to do is use a direct child selector, like #red > p > span and #green > p > span. But as you’d suspect, these selectors would have to be updated if you ever change the HTML. Coupling your CSS and HTML is a hassle, especially as your project grows.
The best strategy is not to depend on the DOM to style your elements. What happens when you move the span outside the #red? Would you want it to keep its style? For maintainable and scalable CSS, you should use classes only (not IDs) and apply the class to the actual element you want styled, without depending on DOM structure or parent-child relationships. That way, when your HTML structure changes, you don’t have to adjust your CSS to match.
Example:
.red {
color: red;
}
.green {
color: green;
}
<div>
<p><span class="red">red</span></p>
<div>
<p><span class="green">green</span></p>
</div>
</div>
You can use > selector to make it apply to only specific span inside the div with the id you give and not all the span inside the div
#green > span {
color: green;
}
span {
color: red;
}
<div id="red">
<p><span>red</span></p>
<div id="green">
<span>green</span>
</div>
</div>
If you want to do it to all descendants, you can achieve it by Javascript like following, it decreases many line of codes if you want to apply many colors, but will be slower time than css. It's up to your preferences
var colors = ['red', 'green', 'blue', 'orange', 'brown']
var spans = document.querySelectorAll('span');
spans.forEach(function(spanElement) {
colors.forEach(function(color){
if(spanElement.closest(`#${color}`)){
spanElement.style.color=color
}
})
})
<div id="red">
<span>red</span>
<div id="green">
<span>green</span>
<p><span>green</span></p>
</div>
<div id="blue">
<span>blue</span>
</div>
<div id="orange">
<span>orange</span>
</div>
<div id="brown">
<span>brown</span>
</div>
</div>

CSS inheritance -- color property [duplicate]

This question already has answers here:
Why doesn't my child element inherit color from its parent when parent has more specific selector?
(4 answers)
Closed 3 years ago.
Probably missing something really simple here as I am quite new to this -- but, I don't understand why, in the below code, the <a> and <h2> elements do not inherit the color property (white) from the .hero class. Simplified the code as much as possible.
The HTML:
<section class="hero container">
<h2>A header!</h2>
<p>Some stuff!!!</p>
Linky
</section>
The CSS:
a {
color: #648880;
}
h2 {
color: #648880;
}
.hero {
color: #fff;
}
The result of this code is that the <p> element has text w/ color #fff, as specified in the .hero class -- which is as expected. However, the <a> & <h2> elements have color #6488880, as specified in the element selectors for <a> & <p>.
Same issue demonstrated in JSFiddle here
Shouldn't the .hero class's color attribute be overriding the color attribute in the element selectors? Am I completely misunderstanding specificity somehow? Of course I can use .hero a or .hero h2, but I don't see why I have to.
Why would you expect a property specified on a parent to override one specified on a child?
Specificity refers to a way to prioritize rules selecting the same element. The specificity of a rule on a parent (.hero) has no relevance to the specificity of a rule on its children (a).
In this case, the default color on the a element is inherit. However, you explicitly specified a different color. No amount of specificity or !important on the parent can cause it to override an explicit color specified on the child.
You set the elements to a specific color. Setting the color of the parent won't override that. You need to be more specific about those elements.
.hero a,
.hero h2{
color: inherit;
}
This article may help.

Do parent selectors take precedence over child selector in CSS?

I had a question about how CSS selectors work between parent and children, and which one would take precedence over the other.
<div class="red">
<div class="blue">
<div class="green">
</div>
</div>
</div>
If you then have
.red .green{
border: 1px solid red;
}
.blue .green{
border: 1px solid blue;
}
Which one would take effect? And to override a CSS style does it have to be as specific a selector as the one you're trying to override?
You should read up on specificity.
To answer your immediate question, all your selectors carry the same specificity, so in the case of .green, the last rule takes precedence: your border would be blue.
the parent selectors encompass everything within those tags that aren't assigned a value. So in your case the 2nd , you wanted to add text or images there, it would follow in line with that class. The third would do the same. Think of it like a math equation and parenthesis:
5 x 4 x (3x3) = 180
you would do the parenthesis first then the other factors.
The position of an element has no effect on selector specificity if you are simply using ascendant/descendant selectors. Note that
.red, .green
.blue, .green
Select elements separately because of the comma. That is, the <div class=red> and <div class=green> are both selected, and this would happen no matter if one were a descendant of the other. I think that you mean to remove the comma.
In that case, the order of the declaration of the rules will take effect with later rules having higher precedence. That is .blue, .green has higher precedence over .red, .green even though the specificity is the same simply because it is declared later.

What does "div.container" and mean in CSS

Currently tweaking a theme and have tried searching for an answer to this question to this! I'm not stuck - but more just want to know the answer out of curiosity.
I understand that
"#" means an id and
"." means a class.
I've also been reading on this post about how you can add specificity to your html/css through combination of elements/ids/classes ie:
a.fancy { color: red; } /*an element that has an anchor and a class = red.*/
However the code I am working on has the following elements that I don't understand:
div.footer {background-color: {{ settings.footer_color }};
Why would you specify "div.footer" as both the div and the class when simply using a "." would suffice? In my mind there would be no point when the class ".footer" could be used without a div?
Hope you can help me work this one out!
div.footer means the element must both BE a <div> and HAVE the class footer.
.footer would trigger for any element with class footer; for example, a <span class="footer".
div.footer means you are targeting only <div> elements with the class .footer.
<div class="footer">This is targeted.</div>
<p class="footer">This isn't targeted, as it isn't a div with the class .footer.</p>
div .footer, however, would target all elements with the class .footer that are descendants from <div> elements.
<div><p class="footer">This is targeted.</p></div>
<section><p class="footer">But this isn't targeted.</p></section>
With the new implementation of html5 <footer> is a legitimate tag just like <div> or <p>. As confusing as it may be the period . before the footer declaration constrains it to a class name instead of the tag.
So in your case: div.footer = <div> with class name footer = <div class="footer>.
There are numerous reasons why you may make such a declaration.
Sample html
<div>
<div class="footer">Footer only</footer>
<div>Div only</div>
<footer>Footer tag; DIFFERENT</footer>
</div>
Example Css
div {
border: 1px solid red;
}
.footer {
background: blue;
color: #fff; /* white font color */
}
Depending on what you want to do, let's use the specific div.footer examples to show what we can do.back
Inheritance
By inheritance, div.footer will inherit "3 properties" -> background, color and border from the div and .footer declarations.
Now you may want to override some of these properties so...
Overriding Property
Use something like div.footer { color: red; } this will override the white color.
Layout Insight
The beauty of css is that you can use declaration to give you "insight" on what the html markup will be laid out as.
Omitting properties I would write the css as follows:
#footer {}
#footer ul {}
#footer ul li {}
#footer p {}
#footer p a {}
The html:
<div id="footer">
<ul>
<li>List 1</li>
<li>LIst 2</li>
</ul>
<p>Hello! Copyright website company name.</p>
</div>
You could then reverse engineer the html through just css because of the descendent character use. This maximizes the power of "cascading".
--
NOow I hope some of this has given you some insight. A few other pointers are this:
Typically a webpage has only one footer. When there is only one of something use the # id selector ALWAYS.
Use classes to not only apply styles to multiple elements but to also provide "meaning to your markup" -> go back to the principle of "layout insight" to understand what I mean.
div.footer should could more simply be .footer Now, it may be necessary to include div just to say "I only want to apply this class to divs only" and in that case go for it. But defining all your declarations with div.someClasName is not all that valuable.
DO NOT use names of tags as classnames. div.div is very confusing - especially if you are programming for a while. Therefore, since <footer> is now a legit tag you shouldn't apply it as a classname. On the other hand "#footer" could be argued differently because it can only exist once in a webpage.
It's about specificity. div.footer is more specific (a div with that particular class) than .footer (any element with that class).
As to when to use one or the other, it really depends on the markup and CSS you are building.

CSS div naming grammar

Can you use the word div to name a div class? or id?
for example:
#div.leftcol
or does it just get seen as
#leftcol
The browser will see that as <div id="div" class="leftcol"></div>
I don't follow what you mean, but I think what you're asking is can you use the word div to apply a class to div elements. If that's what you mean, then yes you can, and you do it exactly as you have shown in your question:
div.leftcol { color: red }
That style would be applied to all elements of type div with class leftcol. Without the div part, the style would apply to any element with class leftcol, regardless of what type of element it is:
.leftcol { color: red }
Edit now the question has been edited...
After the edit to your question, it makes a bit more sense (I think). Your first example would apply to an element with an id of div and a class of leftcol:
<div id="div" class="leftcol"></div>
The second example would apply to an element with an id of leftcol:
<div id="leftcol"></div>
Or if you are simply asking whether div is a some sort of reserved word in CSS, no, it's not, so feel free to use it as an identifier. However, that could get confusing (for example, you could end up with selectors like div.div #div)
can you provide an example?
you can use <div class="leftcol"> left content </div>
and then in your css .leftcol { background:red; }
you can address it either div.leftcol or just simple .leftcol
As in?
<div id="div.leftcol">Some content</div>
While it may work for HTML and Javascript it should cause a problem if you try to style it in a CSS stylesheet. As I am sure you know the following
div.leftcol {
color: #efefef;
}
means "Set the text color to #efefef for any div element that has leftcol as a class name" so it would not work. I have no idea if
div.div.leftcol {
color: #efefef;
}
would work but that is just ugly...

Resources