1

How can I change the style of another element when a link is hovered - without jQuery/ JavaScript?

ul>li>a:hover main {
  opacity: 0.1;
}

main p {
  font-size: 200px;
}
<header>
  <ul>
    <li><a href="#">Hover me</a></li>
  </ul>
</header>

<main>
  <p>Hello World!</p>
</main>

I want to change the opacity of the text in main when the link is hovered.

Is it possible?

EDIT

I tried with a sibling:

a:hover ul {
  opacity: 0.5;
}
<header>
  <ul>
    <li><a href="#">Hover me</a><span></span>
      <ul>
        <li>Child 1</li>
        <li>Child 2</li>
        <li>Child 3</li>
      </ul>
    </li>
  </ul>
</header>

But still does not work...

laukok
  • 47,545
  • 146
  • 388
  • 689

4 Answers4

3

It's possible but the layout must be situated differently due to CSS cascading behavior. Whatever you hover over (call it the trigger) and whatever is fading because of the hover (call it target) must have specific positions in order for it to work.

Trigger -

Can be before target as an "older" sibling.

OR

Can be an ancestor of target or a sibling of an ancestor of target.

Demo

a {
  border: 3px dotted blue;
  padding: 0 5px;
  color: #000;
  text-decoration: none;
  display: block;
}

a.aunt {
  border-color: red;
  margin: 10px 0;
}

a.aunt:hover+main p {
  opacity: 0.1;
  transition: 1s;
}

a.brother:hover+p {
  color: red;
}

a.sister:hover~p {
  color: blue;
}

main.mom {
  border: 5px dashed tomato;
}

main.mom p {
  opacity: 1;
  font-size: 50px;
  margin-top: 10px;
  transition: 1s;
  border: 3px solid red;
}

main.mom:hover p {
  font-size: 100px;
}

b {
  font-size: 25px
}
<a href='#/' class='aunt'>Aunt - Older sibling of an ancestor of the target</a>


<main class='mom'>
  <a href='#/' class='sister'>Big Sister - Sibling to target with <br>sibling combinator: <b>~</b></a><br><br>

  <a href='#/' class='brother'>Big Brother - Adjacent Sibling to target with <br>adjacent sibling combinator: <b>+</b></a>

  <p>Target</p>
  <a href='#/' class='brother'>Little Brother - Cannot influence target when hovered on.</a>
  <br> Mom - hovering over affects all descendants<br>(i.e. all siblings and siblings' and target's descendants)<br>
</main>

<a href='#/' class='aunt'>Aunt - This is after target's ancestor so it cannot influence target</a>
Community
  • 1
  • 1
zer00ne
  • 31,838
  • 5
  • 32
  • 53
  • Nice! I never knew that selector lineage can be specified with triggers! Good method! :) – varun Jul 24 '17 at 16:14
  • The term trigger is of my making, sorry if there's any confusion. It's just easier to refer to the "element being hovered on" as "trigger". – zer00ne Jul 24 '17 at 16:30
  • Perfect, I interpreted it just the same (as events). You can see I used the word "trigger" in my answer too. Technically they are called Pseudo-classes! :) – varun Jul 24 '17 at 16:36
  • 1
    The pseudo-classes are not the element in DOM which I was referring to. I was oversimplifying ;) – zer00ne Jul 24 '17 at 16:43
  • Yep! It's sometimes so easy to interpret such usages wrongly due to the nature of English language and Computer Science jargon! :P – varun Jul 24 '17 at 16:55
2

In general, this type of problem is solved using combinators.

In this specific case, you need a parent combinator, which does not exist in CSS, so it is impossible without restructuring the HTML (e.g. to make the <main> a sibling of the <a>).

Quentin
  • 800,325
  • 104
  • 1,079
  • 1,205
1

It is not possible to use + or ~ sibling selectors, becouse <a> and <main> elements are not siblings. Thus you could use JavaScript. For example it is possible using by fadeTo() within hover() method:

$("a[data-opacity-target]").hover(function() {
  var selector = $(this).data("opacity-target");
  $(selector).fadeTo(500, 0.1);
}, function() {
  var selector = $(this).data("opacity-target");
  $(selector).fadeTo(500, 1);
});
main p {
  font-size: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
  <ul>
    <li><a href="#" data-opacity-target="main">Hover me</a></li>
  </ul>
</header>
<main>
  <p>Hello World!</p>
</main>

In your EDIT section you should use a:hover~ul selector instead of a:hover ul.

Alexander
  • 3,922
  • 7
  • 24
  • 34
0

Really interesting question.

You can try out the following code:

.trigger{
 color: black;
}

div:hover ~ .trigger{
 color: orange;
}

div{
 display: inline-block;
 border: 1px solid green;
 border-radius: 10px;
 padding: 5px;
 width: auto;
}
<!DOCTYPE html>
<html>
<head>
 <title>Pure CSS event handling</title>
</head>
<body>
 <div>Hover over me for pure CSS events</div>
 <p class="trigger">Hey Pikachu!</p>
</body>
</html>

Take a look at this link, it explains about the tilde selector in CSS:

what-does-the-tilde-squiggle-twiddle-css-selector-mean

I personally thought this was not possible. I learnt something new today! :D

varun
  • 1,503
  • 13
  • 16
  • @Quentin Hey there! I just noticed that someone downvoted my answer! If it was you, can I please get a reason? Is my answer not correct / inefficient / considered bad practice? :) – varun Jul 24 '17 at 16:11
  • @zer00ne Hi there! I just noticed that someone downvoted my answer! If it was you, can I please get a reason? Is my answer not correct / inefficient / considered bad practice? :) – varun Jul 24 '17 at 16:13
  • Not me, sir. I only downvote an answer at least 30 minutes after I inform the poster that the answer isn't suitable. – zer00ne Jul 24 '17 at 16:46
  • @zer00ne Wonderful policy you have there! I just want to know if someone found something wrong in my approach... A silent downvote doesn't help me realize my mistake(if any)... :\ – varun Jul 24 '17 at 16:58
  • Technically, I see nothing wrong. You could add that in that layout the adjacent sibling combinator: `+` also works as well. – zer00ne Jul 24 '17 at 17:38