I wonder how the CSS rules applied to the child elements.
The h2's gray style is been overriding because there is a parent level style .level2 h2with blue color.
But the .level1 h2 is not applying the same way.
Please see the below example.
.level1 h2 {
color: green;
}
.level2 h2 {
color: blue;
}
h2 {
color: gray;
}
<div class="level1">
<div class="level2">
<h2>test</h2>
</div>
</div>
It's all about specificity and inheritance.
The notion of a “cascade” is at the heart of CSS (just look at its
name). It ultimately determines which properties will modify a given
element. The cascade is tied to three main concepts: importance,
specificity and source order. The cascade follows these three steps to
determine which properties to assign to an element. By the end of this
process, the cascade has assigned a weight to each rule, and this
weight determines which rule takes precedence, when more than one
applies.
It also depend of the order in the stylesheet if both selectors have the same specificity.
.level2 h2 {
color: blue;
}
.level1 h2 {
color: green;
}
h2 {
color: gray;
}
<div class="level1">
<div class="level2">
<h2>test</h2>
</div>
</div>
Source : https://www.smashingmagazine.com/2010/04/css-specificity-and-inheritance/
This is a matter of CSS Specificity
The concept
Specificity is the means by which browsers decide which CSS property
values are the most relevant to an element and, therefore, will be
applied. Specificity is based on the matching rules which are composed
of CSS selectors of different sorts.
How is it calculated?
Specificity is a weight that is applied to a given CSS declaration,
determined by the number of each selector type in the matching
selector. When specificity is equal to any of the multiple
declarations, the last declaration found in the CSS is applied to the
element. Specificity only applies when the same element is targeted by
multiple declarations. As per CSS rules directly targeted element will
always take precedence over rules that an element inherits from an
ancestor.
Where :
.level1 h2 and .level2 h2 will have a specificity of : 0 0 1 1
While:
h2 only has a specificity of: 0 0 0 1
therefore h2 is less specific.
It will prevail the latest style applied if having the same specificity
You can test/calculate specificity here
Snippet with level2 as last style applied
.level1 h2 {
color: green;
}
.level2 h2 {
color: blue;
}
h2 {
color: gray;
}
<div class="level1">
<div class="level2">
<h2>test</h2>
</div>
</div>
Snippet with level1 as last style applied
.level2 h2 {
color: blue;
}
.level1 h2 {
color: green;
}
h2 {
color: gray;
}
<div class="level1">
<div class="level2">
<h2>test</h2>
</div>
</div>
.level2 h2 is given more importance as it's declared further down in the stylesheet. And it's also more important than h2, because it's composed of a tag name AND a class name.
Since the specifity here is the same for ".level1 h2" and ".level2 h2", the browser looks at the order it is declared in the CSS.
The "h2" tag that makes the tag gray has lower specifity, so that will alwayss be overridden by the other declarations.
h2 {
color: gray;
}
/* Situation 1, level 2 declared first */
.situation1.level2 h2 {
color: blue;
}
.situation1.level1 h2 {
color: green;
}
/* Situation 1, level 2 declared last */
.situation2.level1 h2 {
color: green;
}
.situation2.level2 h2 {
color: blue;
}
Level 2 declared <b>first</b>
<div class="level1 situation1">
<div class="level2 situation1">
<h2>test</h2>
</div>
</div>
Level 2 declared <b>last</b>
<div class="level1 situation2">
<div class="level2 situation2">
<h2>test</h2>
</div>
</div>
Related
In my HTML below, when I hover on the <a> element I want to change the colour of the <h1> element using only CSS. Is there a way to achieve this?
<h1>Heading</h1>
<a class="button" href="#"></a>
What if I wrap a div around it with an id in it?
<div id="banner">
<h1>Heading</h1>
<a class="button" href="#"></a>
</div>
Will this help?
You can make a sibling that follows an element change when that element is hovered, for example you can change the color of your a link when the h1 is hovered, but you can't affect a previous sibling in the same way.
h1 {
color: #4fa04f;
}
h1 + a {
color: #a04f4f;
}
h1:hover + a {
color: #4f4fd0;
}
a:hover + h1 {
background-color: #444;
}
<h1>Heading</h1>
<a class="button" href="#">The "Button"</a>
<h1>Another Heading</h1>
We set the color of an H1 to a greenish hue, and the color of an A that is a sibling of an H1 to reddish (first 2 rules). The third rule does what I describe -- changes the A color when the H1 is hovered.
But notice the fourth rule a:hover + h1 only changes the background color of the H1 that follows the anchor, but not the one that precedes it.
This is based on the DOM order, and it's possible to change the display order of elements, so even though you can't change the previous element, you could make that element appear to be after the other element to get the desired effect.
Note that doing this could affect accessibility, since screen readers will generally traverse items in DOM order, which may not be the same as the visual order.
Edit
This should now be possible using the has selector, in the browsers that support it.
See the comments in the CSS below.
I will edit again in the future; currently my Chrome and Safari browsers are not yet at versions that support it.
h1 {
color: #4fa04f;
}
h1 + a {
color: #a04f4f;
}
h1:hover + a {
color: #4f4fd0;
}
a:hover + h1 {
background-color: #444;
}
/* Select an H1 heading that has an <a>nchor as a sibling */
h1:has(+ a) {
background-color: cyan;
}
/* Select an H1 heading that has a currently-hovered <a>nchor as a sibling */
h1:has(+ a:hover) {
background-color: yellow;
}
<h1>Heading</h1>
<a class="button" href="#">The "Button"</a>
<h1>Another Heading</h1>
There is no CSS selector that can do this (in CSS3, even). Elements, in CSS, are never aware of their parent, so you cannot do a:parent h1 (for example). Nor are they aware of their siblings (in most cases), so you cannot do #container a:hover { /* do something with sibling h1 */ }. Basically, CSS properties cannot modify anything but elements and their children (they cannot access parents or siblings).
You could contain the h1 within the a, but this would make your h1 hoverable as well.
You will only be able to achieve this using JavaScript (jsFiddle proof-of-concept). This would look something like:
$("a.button").hover(function() {
$(this).siblings("h1").addClass("your_color_class");
}, function() {
$(this).siblings("h1").removeClass("your_color_class");
});
#banner:hover h1 {
color: red;
}
#banner h1:hover {
color: black;
}
a {
position: absolute;
}
<div id="banner">
<h1>Heading</h1>
<a class="button" href="#">link</a>
</div>
The Fiddle: http://jsfiddle.net/joplomacedo/77mqZ/
The a element is absolutely positioned. Might not be perfect for your exisiting structure. Let me know, I might find a workaround.
It is indeed possible to achieve this with only a few lines of CSS and some basic Flexbox understanding.
As Stephen P said in his answer, the adjacent sibling combinator does select immediately following siblings. To achieve what the OP asked, you could use two flex approaches:
Approach 1 (using "flex-flow" shorthand property)
.flex-parent {
display: flex;
flex-flow: column-reverse wrap
}
.flex-child-1:hover + .flex-child-2 {
color: #FF3333;
}
<div class="flex-parent">
<a class="flex-child-1">Hover me</a>
<h1 class="flex-child-2">I am changing color</h1>
</div>
Approach 2 (using "order" property and multiple children)
.flex-parent {
display: flex;
flex-direction: column;
}
.flex-child-1 {
order: 2;
}
.flex-child-2 {
order: 1;
}
.flex-child-3 {
order: 3;
}
.flex-child-1:hover+.flex-child-2 {
color: #FF3333;
}
<div class="flex-parent">
<h1 class="flex-child-3">I am not changing color</h1>
<a class="flex-child-1">Hover me</a>
<h1 class="flex-child-2">I am changing color</h1>
</div>
Bonus:
CodePen Bonus
http://plnkr.co/edit/j5kGIav1E1VMf87t9zjK?p=preview
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
<style>
ul:hover > li
{
opacity: 0.5;
}
ul:hover li:hover
{
opacity: 1;
}
</style>
</head>
<body>
<h1>Hello Plunker!</h1>
<ul>
<li>Hello</li>
<li>Hello</li>
<li>Hello</li>
<li>Hello</li>
<li>Hello</li>
</ul>
</body>
</html>
here is an example how it can be done in pure css , hope it helps somebody
Try this one-line pure CSS solution:
.parent:hover .child:not(:hover) {
/* this style affects all the children *except* the one you're hovering over */
color: red;
}
More info here: https://codyhouse.co/nuggets/styling-siblings-on-hover
Change the H1 tag into a link, style it the same as the normal text maybe?
And then use this,
a:link {color:#FF0000;}
a:hover {color:#FF00FF;}
And it should work when you hover :) you can also make it specific by containing it in a div and then targeting it like this:
.exampledivname a:link {color:#FF0000;}
.exampledivname a:hover {color:#FF00FF;}
This should help.
Someone helped me with this so I thought I would share here as well.
In your first example that is indeed impossible with pure CSS. However, when you wrap it with a parent container you then have the ability to do a bunch of stuff with hovering children.
#banner:hover>h1{
color:red;
}
h1:hover{
color:black !important;
}
#banner{
display:inline-block;
}
.button{
display:inline-block;
font-size:24px;
width:100%;
border:1px solid black;
text-align:center;
}
h1{
padding:0;
margin:0;
}
<div id="banner">
<h1>Heading</h1>
<a class="button" href="#">Button!</a>
</div>
The parent just controls the children who aren't currently being hovered. You then can set hover states for individual elements and classes to make sibling selection possible without JS.
Here is a more advanced example of this in action
https://codepen.io/levyA/pen/gOrdaLJ
For set styles in sibling elements you can use ~ character
in first case when h1 hovered set color for a tag
and in second case when a is hovered, change background color of h1 section
h1:hover ~ a {
color: #e34423;
}
a:hover ~ h1 {
background-color: #eee;
}
This might work, I've recently used this idea to stop sibling elements in an animation.
h1 { color: inherit; }
#banner:hover { color: your choice; }
I was reading MDN docs about inherit keyword and the example there is very confusing to me can anyone PLEASE explain to me the exact example on MDN docs about excluding selected elements from the rule. Thank you.
Examples
Exclude selected elements from a rule
/* Make second-level headers green */
h2 { color: green; }
/* ...but leave those in the sidebar alone so they use their parent's color */
#sidebar h2 { color: inherit; }
In this example, the h2 elements inside the sidebar might be different colors. For example, if one of them were the child of a div matched by the rule ...
div#current { color: blue; }
... it would be blue.
It is my first time asking question so please don't mind my formatting.
Let's take it step by step in this snippet:
/* Make second-level headers green */
h2 {
color: green;
}
/* ...but leave those in the sidebar alone so they use their parent's color */
#sidebar h2 {
color: inherit;
}
div#current {
color: blue;
}
<h2>this is an h2 outside the sidebar so it should have the color set for h2 in the style sheet which is green.</h2>
<div id="sidebar">
<h2>This is an h2 inside the sidebar so it has inherited its parent's color - which in this example is the default which is black</h2>
<div id="current">
<h2>This is an h2 inside a div. The div has id current and color blue. This h2 has inherited its parent's color which is blue.</div>
</div>
Are you looking for this example?
h2 {
color: green;
}
.sidebar h2 {
color: inherit;
}
.sidebar {
color: blue;
}
.red {
color: red;
}
<h2>This is Green Heading</h2>
<div class="sidebar">
<h2>This is Blue Heading</h2>
<div class="red">
<h2>This is Red Heading</h2>
</div>
</div>
the first h2 element will be green, because it has a css rule.
The second h2 for example became black because he has the rule inherit so he get the color of his parent.
If sidebar has another parent with color declared, h2 get this color
h2 {
color: green
}
div#current {
color: blue;
}
.sidebar h2 {
color: inherit
}
<h2> Green </h2>
<div class="sidebar">
<h2>Default color</h2>
</div>
<div id="current">
<div class="sidebar">
<h2>Default color</h2>
</div>
</div>
.red p {
color: red;
}
.blue p {
color: blue;
}
<div class="blue">
<p> first </p>
<div class="red">
<p> second </p>
</div>
</div>
I assumed the first would have been blue and the second as red, but that isn't the case. Why are both paragraphs blue?
Both paragraphs are blue due to the "C" in CSS - which stands for cascading. Review the MDN docs to see how CSS rules are applied and inherited.
In your case all of <p> elements are blue because the .blue p selector is the last rule in your CSS and it overrides the .red p selector.
You can restructure your CSS like this to ensure that the <p> elements within the .red div are red.
.blue p {
color: blue;
}
.blue .red p {
color: red;
}
As you know:
.blue p matches any p tags within a .blue class.
.red p matches any p tags within a .red class.
Your <p> first </p> is within a blue class, so it matches the .blue p rule, and is rendered as blue.
<div class="red"> is within both a red class and a blue class, so we have a dilemma. The way CSS resolves this is by using whichever rule appeared last. In this case the .blue p rule appears last, and the text is rendered as blue.
CSS fix
If p tags are always going to be an immediate child of your color classes, you could do the following. The > is a descendant selector that only matches immediate descendants.
.red > p {
color: red;
}
.blue > p {
color: blue;
}
CSS fix 2
You can also do as Tom suggested. The reason why it works is because CSS rules that are more specific will overwrite CSS rules that are less specific. Even though the blue rule comes second because div .red p has two classes, it is more specific than .blue p.
.red p,
.blue .red p {
color: red;
}
.blue p,
.red .blue p {
color: blue;
}
However, this only takes your problem one level deeper. The red class in the following HTML will still be rendered blue.
<div class="blue">
<div class="blue">
<p> first </p>
<div class="red">
<p> second </p>
</div>
</div>
</div>
HTML fix
This is the method I would suggest you use. You can simply move your classes to the p tags:
<div>
<p class="blue"> first </p>
<div>
<p class="red"> second </p>
</div>
</div>
Other items to watch out for
There are other ways a CSS rule can get overridden. I would suggest you research CSS specificity.
Because you have given blue color to the parent div. This should be your structure.
<div class="blue">
<p>first</p>
</div>
<div class="red">
<p>second</p>
</div>
CSS code will be :
.red {
color: red;
}
.blue {
color: blue;
}
* {
color: yellow
}
.outermost {
color: blue
}
.middle {
color: red
}
<div class="outermost">
<div class="middle">
<p>Some Text</p>
</div>
</div>
I expect the color of <p>Some Text </p> to be red because <div class="middle"> is its parent. However, the color ends up as yellow. This seems counter-intuitive because the global selector is less specific than the parent container. Why does the p element inherit from global, and how can it be changed so that it inherits from the parent container?
As #j08691 notes in his comment, the universal selector * has no effect on specificity:
* {
color: yellow;
}
.middle {
color: red;
}
<div class="middle">
<p>Some Text</p>
</div>
If you'd like the specificity to operate under normal effects change the * to body:
body {
color: yellow;
}
.middle {
color: red;
}
<div class="middle">
<p>Some Text</p>
</div>
You're conflating inheritance with specificity. Those aren't the same thing; they're totally unrelated concepts in CSS.
It's true that the global selector has a much lower specificity than the .middle class selector, but that's irrelevant because the .middle selector isn't targeting your p element; it's targeting the p element's parent.
Normally that would be sufficient to make p use red text, because, by default, p has its color property set to the special value called inherit, which causes it to inherit its color from it's parent element. But p isn't using the default value (inherit) for its color property, because you have a matching rule telling explicitly to use yellow instead:
* {
color: yellow;
}
Inheritance doesn't even come into play here, because your p element isn't set to inherit from it's parent in the first place.
You can override that behavior using a selector with a higher specificity that targets the element containing your text (not just one of its ancestors) explicitly telling it to inherit from its parent:
* {
color: yellow;
}
.outermost {
color: blue;
}
.middle {
color: red;
}
.middle > p {
color: inherit; // This overrides the rule defined by the global selector above
}
<div class="outermost">
<div class="middle">
<p>Some Text</p>
</div>
</div>
Or alternately, you could just stop using the global selector and instead rely on inheritance to set the text color for most of your elements:
body {
color: yellow;
}
.outermost {
color: blue;
}
.middle {
color: red;
}
<div class="outermost">
<div class="middle">
<p>Some Text</p>
</div>
</div>
Note that using the global selector for this sort of thing is usually discouraged anyway, for numerous reasons.
To help you better understand why your current code isn't working, here's essentially what it's doing:
<div style="color:blue;"> <!-- Matches * and .outermost. Result: Blue -->
<div style="color:red;"> <!-- Matches * and .middle. Result: Red -->
<p style="color:yellow;">Some Text</p> <!-- Matches *. Result: yellow -->
</div>
</div>
This is how you would target the font inside the "middle" class https://jsfiddle.net/DIRTY_SMITH/cfckvvzw/3/
.middle > p {
color: red
}
In my HTML below, when I hover on the <a> element I want to change the colour of the <h1> element using only CSS. Is there a way to achieve this?
<h1>Heading</h1>
<a class="button" href="#"></a>
What if I wrap a div around it with an id in it?
<div id="banner">
<h1>Heading</h1>
<a class="button" href="#"></a>
</div>
Will this help?
You can make a sibling that follows an element change when that element is hovered, for example you can change the color of your a link when the h1 is hovered, but you can't affect a previous sibling in the same way.
h1 {
color: #4fa04f;
}
h1 + a {
color: #a04f4f;
}
h1:hover + a {
color: #4f4fd0;
}
a:hover + h1 {
background-color: #444;
}
<h1>Heading</h1>
<a class="button" href="#">The "Button"</a>
<h1>Another Heading</h1>
We set the color of an H1 to a greenish hue, and the color of an A that is a sibling of an H1 to reddish (first 2 rules). The third rule does what I describe -- changes the A color when the H1 is hovered.
But notice the fourth rule a:hover + h1 only changes the background color of the H1 that follows the anchor, but not the one that precedes it.
This is based on the DOM order, and it's possible to change the display order of elements, so even though you can't change the previous element, you could make that element appear to be after the other element to get the desired effect.
Note that doing this could affect accessibility, since screen readers will generally traverse items in DOM order, which may not be the same as the visual order.
Edit
This should now be possible using the has selector, in the browsers that support it.
See the comments in the CSS below.
I will edit again in the future; currently my Chrome and Safari browsers are not yet at versions that support it.
h1 {
color: #4fa04f;
}
h1 + a {
color: #a04f4f;
}
h1:hover + a {
color: #4f4fd0;
}
a:hover + h1 {
background-color: #444;
}
/* Select an H1 heading that has an <a>nchor as a sibling */
h1:has(+ a) {
background-color: cyan;
}
/* Select an H1 heading that has a currently-hovered <a>nchor as a sibling */
h1:has(+ a:hover) {
background-color: yellow;
}
<h1>Heading</h1>
<a class="button" href="#">The "Button"</a>
<h1>Another Heading</h1>
There is no CSS selector that can do this (in CSS3, even). Elements, in CSS, are never aware of their parent, so you cannot do a:parent h1 (for example). Nor are they aware of their siblings (in most cases), so you cannot do #container a:hover { /* do something with sibling h1 */ }. Basically, CSS properties cannot modify anything but elements and their children (they cannot access parents or siblings).
You could contain the h1 within the a, but this would make your h1 hoverable as well.
You will only be able to achieve this using JavaScript (jsFiddle proof-of-concept). This would look something like:
$("a.button").hover(function() {
$(this).siblings("h1").addClass("your_color_class");
}, function() {
$(this).siblings("h1").removeClass("your_color_class");
});
#banner:hover h1 {
color: red;
}
#banner h1:hover {
color: black;
}
a {
position: absolute;
}
<div id="banner">
<h1>Heading</h1>
<a class="button" href="#">link</a>
</div>
The Fiddle: http://jsfiddle.net/joplomacedo/77mqZ/
The a element is absolutely positioned. Might not be perfect for your exisiting structure. Let me know, I might find a workaround.
It is indeed possible to achieve this with only a few lines of CSS and some basic Flexbox understanding.
As Stephen P said in his answer, the adjacent sibling combinator does select immediately following siblings. To achieve what the OP asked, you could use two flex approaches:
Approach 1 (using "flex-flow" shorthand property)
.flex-parent {
display: flex;
flex-flow: column-reverse wrap
}
.flex-child-1:hover + .flex-child-2 {
color: #FF3333;
}
<div class="flex-parent">
<a class="flex-child-1">Hover me</a>
<h1 class="flex-child-2">I am changing color</h1>
</div>
Approach 2 (using "order" property and multiple children)
.flex-parent {
display: flex;
flex-direction: column;
}
.flex-child-1 {
order: 2;
}
.flex-child-2 {
order: 1;
}
.flex-child-3 {
order: 3;
}
.flex-child-1:hover+.flex-child-2 {
color: #FF3333;
}
<div class="flex-parent">
<h1 class="flex-child-3">I am not changing color</h1>
<a class="flex-child-1">Hover me</a>
<h1 class="flex-child-2">I am changing color</h1>
</div>
Bonus:
CodePen Bonus
http://plnkr.co/edit/j5kGIav1E1VMf87t9zjK?p=preview
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
<style>
ul:hover > li
{
opacity: 0.5;
}
ul:hover li:hover
{
opacity: 1;
}
</style>
</head>
<body>
<h1>Hello Plunker!</h1>
<ul>
<li>Hello</li>
<li>Hello</li>
<li>Hello</li>
<li>Hello</li>
<li>Hello</li>
</ul>
</body>
</html>
here is an example how it can be done in pure css , hope it helps somebody
Try this one-line pure CSS solution:
.parent:hover .child:not(:hover) {
/* this style affects all the children *except* the one you're hovering over */
color: red;
}
More info here: https://codyhouse.co/nuggets/styling-siblings-on-hover
Change the H1 tag into a link, style it the same as the normal text maybe?
And then use this,
a:link {color:#FF0000;}
a:hover {color:#FF00FF;}
And it should work when you hover :) you can also make it specific by containing it in a div and then targeting it like this:
.exampledivname a:link {color:#FF0000;}
.exampledivname a:hover {color:#FF00FF;}
This should help.
Someone helped me with this so I thought I would share here as well.
In your first example that is indeed impossible with pure CSS. However, when you wrap it with a parent container you then have the ability to do a bunch of stuff with hovering children.
#banner:hover>h1{
color:red;
}
h1:hover{
color:black !important;
}
#banner{
display:inline-block;
}
.button{
display:inline-block;
font-size:24px;
width:100%;
border:1px solid black;
text-align:center;
}
h1{
padding:0;
margin:0;
}
<div id="banner">
<h1>Heading</h1>
<a class="button" href="#">Button!</a>
</div>
The parent just controls the children who aren't currently being hovered. You then can set hover states for individual elements and classes to make sibling selection possible without JS.
Here is a more advanced example of this in action
https://codepen.io/levyA/pen/gOrdaLJ
For set styles in sibling elements you can use ~ character
in first case when h1 hovered set color for a tag
and in second case when a is hovered, change background color of h1 section
h1:hover ~ a {
color: #e34423;
}
a:hover ~ h1 {
background-color: #eee;
}
This might work, I've recently used this idea to stop sibling elements in an animation.
h1 { color: inherit; }
#banner:hover { color: your choice; }