CSS - Only select the first descendant - html

I'm trying to style all my main tags based on a certain theme.
If a section's class is red, all of of it's inner tags should use the red style regardless of if that section is inside another section which uses the yellow style.
So my question is how do I restrict the inner tags of a section/div/nav etc, to only use the style of the first descendant it encounters.
Note: I do not want to rely on the order of which I declare my tags.
.red input {
background-color: red;
}
.red article {
background-color: red;
}
.red p {
background-color: red;
}
/*.. other tags.. */
.yellow input {
background-color: yellow;
}
.yellow article {
background-color: yellow;
}
.yellow p {
background-color: yellow;
}
/*.. other tags.. */
.blue input {
background-color: blue;
}
.blue article {
background-color: blue;
}
.blue p {
background-color: blue;
}
/*.. other tags.. */
<section class="yellow">
<section class="blue">
<form>
<input type="button" value="This should use the blue theme" />
</form>
</section>
<section class="red">
<article>
<p>This should use the red theme</p>
<!-- This is instead yellow, how do I fix that? -->
</article>
</section>
<section class="yellow">
<nav>
<p>This should use the yellow theme</p>
</nav>
</section>
<p>This should be yellow.</p>
</section>
UPDATE
Okay so I've tried the given solutions and they work with the given example but as soon as I expand the html code to something more complex it doesn't work anymore.
The thing is that since I have to build a general theme, I cannot use css rules that depend on the order of how the html is built. A user should be able to build its website and regardless of how the html is built the correct styles should be applied.
So if the user gives a container tag (nav, section, div, aside, etc.) the class dark-theme, yellow-theme or whatever other theme, all of its children should use that style UNLESS a child container has also specified its own theme.
Is it just not possible? :(
Ex:
section class=yellow-theme
p: use yellow-theme
aside: use yellow-theme
div class=red-theme
ul: use red-theme *not yellow
p: use red-theme *not yellow
footer class=blue-theme
a: use blue-theme *not red not yellow
h3: use blue-theme *not red not yellow
div class=yellow-theme
header: use yellow-theme *not blue * not red
form: user yellow-theme *not blue *not red
<!--This could go on forever and in any order with any tags-->
css:
.yellow-theme anytag{
/* Style any attributes needed: borders, colors, fonts, margins, paddings, etc. */
}
/* Do this for all the tags that needs to be styled */
.red-theme anytag{
/* Style any attributes needed: borders, colors, fonts, margins, paddings, etc. */
}
/* Do this for all the tags that needs to be styled */
.blue-theme anytag{
/* Style any attributes needed: borders, colors, fonts, margins, paddings, etc. */
}
/* Do this for all the tags that needs to be styled */

Any selector-only solution requires you to make assumptions about your markup that may or may not be within your control since the specificity of two contextual selectors is always the same regardless of how close the ancestor is to each descendant that is matched, and any solution that makes use of inheriting the actual properties themselves requires you to apply them to the .red, .yellow and .blue sections, which may not be desired. For example, you'd have to apply background-color to the sections in order for background-color: inherit to work on the descendants, but you may not want the sections themselves to have any background color, so that won't be an option to you.
Custom properties allow descendants to inherit values from their closest ancestors without polluting other properties in this manner, and without other cascading rules getting in the way (competing rules with equally specific contextual selectors, etc). You'll only be able to do this reliably with custom properties for this reason.
.red {
--color: red;
}
.yellow {
--color: yellow;
}
.blue {
--color: blue;
}
input, article, p {
background-color: var(--color);
}
<section class="yellow">
<section class="blue">
<form>
<input type="button" value="This should use the blue theme" />
</form>
</section>
<section class="red">
<article>
<p>This should use the red theme</p>
</article>
</section>
<section class="yellow">
<nav>
<p>This should use the yellow theme</p>
</nav>
</section>
<p>This should be yellow.</p>
</section>

This porblem is a little bit difficult if you want to solve it with all elements.
You have to think the other way: NOT "a rule is valid until there is another rule" BUT "the closest rule is valid".
How to achieve this?
First set a rule for all elements that are grandchildren except the form tag (perhaps also the ol, ul, nav, ... tags) that the background-color shell inherit. Now all this elements inherit theire background-color from the parent element.
Second set one rule for each theme that defines the background-color of all direct children. Here you have to take a look at the problem with the form tag. the form tag has no inheritage (see above) so the children of the form will not get the rule from the closest theme parent. So you have to setup an extra rule for this case.
All in all:
*.color * > *:not(form):not(html):not(body) {
background-color:inherit!important;
}
.red > *:not(form):not(.color), .red > form > *:not(.color) {background-color: red!important}
.yellow > *:not(form):not(.color), .yellow > form > *:not(.color) {background-color: yellow!important}
.blue > *:not(form):not(.color), .blue > form > *:not(.color) {background-color: blue!important}
(.color is a css class that all sections have, that also have the css class .red or .yellow or .blue)
the > - signs are important
you can mix up all the rules.
EDIT Now I see that !important is not neccessary :)
You can also write
*.color * > *:not(form):not(html):not(body) {
background-color:inherit;
}
.blue > *:not(form):not(.color), .blue > form > *:not(.color) {background-color: blue}
.red > *:not(form):not(.color), .red > form > *:not(.color) {background-color: red}
.yellow > *:not(form):not(.color), .yellow > form > *:not(.color) {background-color: yellow}
EDIT2 if you want to style a specific tag in a theme, you have to add the rules in the following way.
1) Add all css attributes that you want to style to the first rule of the set:
*.color * > *:not(form):not(html):not(body) {
background-color:inherit;
color:inherit;
}
2) replace the asterisk by the tag name
.blue > *:not(form):not(.color), .blue > form *:not(.color) {background-color: blue}
.red > *:not(form):not(.color), .red > form *:not(.color) {background-color: red}
.yellow > *:not(form):not(.color), .yellow > form *:not(.color) {background-color: yellow}
.blue > input:not(form):not(.color), .blue > form input:not(.color) { color:white; }
.red > input:not(form):not(.color), .red > form input:not(.color) { color: green; }
.yellow > input:not(form):not(.color), .yellow > form input:not(.color) { color: purple; }
3) have a look at the > - signs! I removed it at one position to make it work with all tags.

To target only the direct descendant of an element, you can use the direct descendant operator: >:
.red > input {
background-color: red;
}
And to go one step better, you can replace all repetitions like so, instead of having to manually declare each element:
.red > * {
background-color: red;
}
.yellow > * {
background-color: yellow;
}
.blue > * {
background-color: blue;
}

Try This :
.yellow > *:not(form):not(section), .yellow form * {background-color: yellow !important}
.blue > *:not(form):not(section), .blue form * {background-color: blue !important}
.red > *:not(form):not(section), .red form * {background-color: red !important}
.yellow > *:not(form):not(section), .yellow form * {background-color: yellow !important}
.blue > *:not(form):not(section), .blue form * {background-color: blue !important}
.red > *:not(form):not(section), .red form * {background-color: red !important}
<section class="yellow">
<section class="blue">
<form>
<input type="button" value="This should use the blue theme" />
</form>
</section>
<section class="red">
<article>
<p>This should use the red theme</p>
<!-- This is instead yellow, how do I fix that? -->
</article>
</section>
<section class="yellow">
<nav>
<p>This should use the yellow theme</p>
</nav>
</section>
<p>This should be yellow.</p>
</section>

Not sure if I understand your question, so just comment if I'm wrong.
Increase the specificity of the style so that will not be overridden that easily.
.red > article > p {
background-color: red;
}
.red input {
background-color: red;
}
.red article {
background-color: red;
}
.red > article > p {
background-color: red;
}
/*.. other tags.. */
.yellow input {
background-color: yellow;
}
.yellow article {
background-color: yellow;
}
.yellow p {
background-color: yellow;
}
/*.. other tags.. */
.blue input {
background-color: blue;
}
.blue article {
background-color: blue;
}
.blue p {
background-color: blue;
}
/*.. other tags.. */
<section class="yellow">
<section class="blue">
<form>
<input type="button" value="This should use the blue theme" />
</form>
</section>
<section class="red">
<article>
<p>This should use the red theme</p>
<!-- This is instead yellow, how do I fix that? -->
</article>
</section>
<section class="yellow">
<nav>
<p>This should use the yellow theme</p>
</nav>
</section>
<p>This should be yellow.</p>
</section>

I tried this and it works, regardless of what element is it as long as you define the parent, hope this helps
body > :first-child
{
background-color: #ff0000;
}

Related

Can a component be styled based on its closest parent in pure CSS?

If I use this css, the span's text color is determined by its closest parent (i.e. text is blue):
.red {
color: red;
}
.blue {
color: blue;
}
.green {
color: green;
}
<div class="green">
<div class="red">
<div class="blue">
<div class="my-component">
<span>Hello World</span>
</div>
</div>
</div>
</div>
However, I want this behavior for .my-component specifically. I therefore added .my-component to my selector but suddenly, the span's text color is determined by the definition order (i.e. text is green):
.red .my-component {
color: red;
}
.blue .my-component {
color: blue;
}
.green .my-component {
color: green;
}
<div class="green">
<div class="red">
<div class="blue">
<div class="my-component">
<span>Hello World</span>
</div>
</div>
</div>
</div>
Why is this?
EDIT
Ok, so I messed up a bit here. As noted in the comments, I was mostly surprised that the distance between .red and .my-component did not affect specificity. However, my second question was the one I was really interested in. This question has already received a lot of great answers to the first question, so I'm reverting this question to its original state and will split the second question off into a new one. Thank you all for the great answers!
Given that the question was (originally) titled: "Can a component be styled based on its closest parent in pure CSS?" and looking at the original examples given
you can do it like this:
.red > .my-component {
color: red;
}
.blue > .my-component {
color: blue;
}
.green > .my-component {
color: green;
}
<div class="green">
<div class="red">
<div class="blue">
<div class="my-component">
<span>Hello World</span>
</div>
</div>
</div>
</div>
The > demands a direct parent-child relationship. A "grandparent" will have no effect on the target element's formatting.
However, the above snippet will not work if the target div is placed several levels under the innermost "colored" div.
This is all determined by Specificity:
Specificity is the algorithm used by browsers to determine the CSS declaration that is the most relevant to an element, which in turn, determines the property value to apply to the element. The specificity algorithm calculates the weight of a CSS selector to determine which rule from competing CSS declarations gets applied to an element.
With this being said, you can use more specific selectors such as the child combinator > with reference to the element to specify styles. You'll notice the more specific I get with the selectors that it will take precedence over other styles.
.red .my-component {
color: red;
}
.blue > .my-component span {
color: blue;
}
.green .my-component {
color: green;
}
<div class="green">
<div class="red">
<div class="blue">
<div class="my-component">
<span>Hello World</span>
</div>
</div>
</div>
</div>
If I were to use .green > .red > .blue > .my-component span in the last part of the CSS then this would take precedence because it is more specific. An example of that is below.
.red .my-component {
color: red;
}
.blue > .my-component span {
color: blue;
}
.green > .red > .blue > .my-component span {
color: green;
}
<div class="green">
<div class="red">
<div class="blue">
<div class="my-component">
<span>Hello World</span>
</div>
</div>
</div>
</div>
So this happens because the code below:
.red {color: red;}
.blue {color: blue;}
.green {color: green;}
influences the color of the element and its children.
Since one children is inside the another and CSS selectors here have the same priority then the one that is the cloest (the last) has the final word.
The color value is inherited but every time changed because of your classes. That's why the sequence in html has a meaning.
.red .my-component {color: red;}
.blue .my-component {color: blue;}
.green .my-component {color: green;}
In the second case you are targeting only .my-components inside the proper class elements so when you change color to red, you are then changing it to blue and at last to green. That's why the sequence in css file has a meaning and not in html.
I hope this will help.

How can I get two anchor elements to hover together? [duplicate]

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; }

CSS inherit keyword "Exclude selected elements from a rule"

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>

In this piece of code, why are both paragraphs blue?

.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;
}

Change color of sibling elements on hover using CSS

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; }