Is it possible for CSS to differentiate between a genuine hover and an inherited hover state?

When the mouse hovers over an element on an HTML page, a :hover pseudo-class is generated by the browser for that specific element as well as all its parent elements, regardless of whether the mouse is directly over any part of the parent element itself.

This behavior can be observed in the example below. In the "Two Nested Divs" scenario, hovering over the blue square will trigger a :hover pseudo-class for both the blue and its parent red square.

Is there a CSS selector available that can respond to the mouse only when it's directly over the red square?

In order to achieve this, I have demonstrated a workaround using the Three Overlapping Divs illustration. Here, the red and blue squares are positioned as siblings with an invisible square div at their intersection. This hidden square intercepts the pointer-event causing the creation of a :hover pseudo-class. This approach allows me to write CSS as if a :hover pseudo-class exists for both visible squares without any inheritance issues.

However, with the Three Overlapping Divs scenario, the blue square is no longer considered a child of the red square. In my real-life scenario, maintaining this hierarchical relationship is crucial.

:root {
  --line: 1px;
  --side: 1vmin;
  --size: max(min(100vh, 50vw), min(50vh, 100vw));
  --font: calc(var(--size) / 20);
  --rect: calc(var(--size) * 0.666 - var(--line));
  --drop: calc(var(--rect) * 0.5);
  --edge: calc(var(--drop) - var(--side));
  --red:  #9009;
  --blue: #0099;
  --bg:   #040;
}

body {
  margin: 0;
  height: 100vh;
  color: #ddd;
  background-color: #222;
  font-size: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}

@media (aspect-ratio < 1/1) {
  main {
    width: var(--size);
  }
}

div {
  position: relative;
  box-sizing: border-box;
}

div[id] {
  font-size: var(--font);
  display: inline-block;
  width: var(--size);
  height: var(--size);
  border: var(--line) solid #ddd;

  p {
    position: absolute;
    pointer-events: none;
    z-index: 1;

    span {
      display: block;
      width: var(--rect);
      margin-top: 0.5em;
      font-size: 0.7em;
    }
  }

  div.red,
  div.blue,
  div.overlap {
    width: var(--rect);
    height: var(--rect);
    border: var(--side) solid red;
  }
  div.red:hover {
    background-color: var(--red);
  }

  div.blue {
    border-color: blue;

    &:hover {
      background-color: var(--blue);
    }
  }

  &#two {
    background-color: var(--bg);
    
    .blue {
      top: var(--edge);
      left: var(--edge);
    }
  }

  &#three {
   .blue {
      position: absolute;
      top: var(--drop);
      left: var(--drop);
    }

      .overlap {
        position: absolute;
        top: var(--drop);
        left: var(--drop);
        width: var(--drop);
        height: var(--drop);
        border-color: transparent;
      }
  }
}

#three:has(.overlap:hover) {
  .red {
    background-color: var(--red);
  }
  .blue {
    background-color: var(--blue);
  }
}
<div id="two">
  <p>Two nested divs
    <span>Hover over the red square to highlight it</span>
    <span>Hovering over the blue square also highlights its parent red square, even without touching the intersecting area</span>
  </p>
  <div class="red">
    <div class="blue"></div>
  </div>
</div>
<div id="three">
  <p>Three overlapping divs<span>Hover over either square to highlight it</span><span>Hover over the intersection to simultaneously highlight both squares</span></p>
  <div class="red"></div>
  <div class="blue"></div>
  <div class="overlap"></div>
</div>

Answer №1

Adjust the structure by making the .overlap element a child of .blue, and then make .blue a child of .red. After that, modify the condition specified for the .red class.

:root {
  --line: 1px;
  --side: 1vmin;
  --size: max(min(100vh, 50vw), min(50vh, 100vw));
  --font: calc(var(--size) / 20);
  --rect: calc(var(--size) * 0.666 - var(--line));
  --drop: calc(var(--rect) * 0.5);
  --edge: calc(var(--drop) - var(--side));
  --red: #9009;
  --blue: #0099;
  --bg: #040;
}

body {
  margin: 0;
  height: 100vh;
  color: #ddd;
  background-color: #222;
  font-size: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}

@media (aspect-ratio < 1/1) {
  main {
    width: var(--size);
  }
}

div {
  position: relative;
  box-sizing: border-box;
}

div[id] {
  font-size: var(--font);
  display: inline-block;
  width: var(--size);
  height: var(--size);
  border: var(--line) solid #ddd;
  p {
    position: absolute;
    pointer-events: none;
    z-index: 1;
    span {
      display: block;
      width: var(--rect);
      margin-top: 0.5em;
      font-size: 0.7em;
    }
  }
  div.red,
  div.blue,
  div.overlap {
    width: var(--rect);
    height: var(--rect);
    border: var(--side) solid red;
  }
  div.red:hover:not(:has(.blue:hover)),
  div.red:has(.overlap:hover) {
    background-color: var(--red);
  }
  div.blue {
    border-color: blue;
    &:hover {
      background-color: var(--blue);
    }
  }
  &#three {
    .blue {
      position: absolute;
      top: var(--drop);
      left: var(--drop);
    }
    .overlap {
      position: absolute;
      width: var(--drop);
      height: var(--drop);
      border-color: transparent;
    }
  }
}
<div id="three">
  <p>Three overlapping divs<span>Roll over either square to highlight it</span><span>Roll over the intersection to highlight both squares</span></p>
  <div class="red">
    <div class="blue">
      <div class="overlap"></div>
    </div>
  </div>
</div>

Answer №2

:root {
  --line: 1px;
  --side: 1vmin;
  --size: max(min(100vh, 50vw), min(50vh, 100vw));
  --font: calc(var(--size) / 20);
  --rect: calc(var(--size) * 0.666 - var(--line));
  --drop: calc(var(--rect) * 0.5);
  --edge: calc(var(--drop) - var(--side));
  --red:  #9009;
  --blue: #0099;
  --bg:   #040;
}

body {
  margin: 0;
  height: 100vh;
  color: #ddd;
  background-color: #222;
  font-size: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}

@media (aspect-ratio < 1/1) {
  main {
    width: var(--size);
  }
}

div {
  position: relative;
  box-sizing: border-box;
}

div[id] {
  font-size: var(--font);
  display: inline-block;
  width: var(--size);
  height: var(--size);
  border: var(--line) solid #ddd;

  p {
    position: absolute;
    pointer-events: none;
    z-index: 1;

    span {
      display: block;
      width: var(--rect);
      margin-top: 0.5em;
      font-size: 0.7em;
    }
  }

  div.red,
  div.blue,
  div.overlap {
    width: var(--rect);
    height: var(--rect);
    border: var(--side) solid red;
  }
  div.red:hover {
    background-color: var(--red);
  }

  div.blue {
    border-color: blue;

    &:hover {
      background-color: var(--blue);
    }
  }

  &#two {
    background-color: var(--bg);
    
    .blue {
      top: var(--edge);
      left: var(--edge);
    }
  }

  &#three {
   .blue {
      position: absolute;
      top: var(--drop);
      left: var(--drop);
    }

      .overlap {
        position: absolute;
        top: var(--drop);
        left: var(--drop);
        width: var(--drop);
        height: var(--drop);
        border-color: transparent;
      }
  }
}

#three:has(.overlap:hover) {
  .red {
    background-color: var(--red);
  }
  .blue {
    background-color: var(--blue);
  }
}
<div id="two">
  <p>Two nested divs
    <span>Roll over the red square to highlight it</span>
    <span>Rolling over the blue square also highlights its parent red square, even when the mouse is not over the intersection</span>
  </p>
  <div class="red">
    <div class="blue"></div>
  </div>
</div>
<div id="three">
  <p>Three overlapping divs<span>Roll over either square to highlight it</span><span>Roll over the intersection to highlight both squares</span></p>
  <div class="red"></div>
  <div class="blue"></div>
  <div class="overlap"></div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to conceal a dynamically generated div upon page load?

I am currently facing a scenario where I need to dynamically create a div. My initial approach was to create it on the document ready event, but the requirement is for it to be displayed only upon selection. The problem I am encountering is that the empty ...

Position Bootstrap 5 modal footer elements to the left and right for an enhanced visual

Can anyone assist me with customizing the Bootstrap 5 modal footer? I am looking to align a text (either using span or label) to the left and a button to the right within the modal footer. I came across this solution and attempted to implement it by cha ...

Why is it that vanilla HTML/JS (including React) opts for camelCase in its styling conventions, while CSS does not follow the same pattern

Each type of technology for styling has its own set of conventions when it comes to naming properties, with camelCase and hyphenated-style being the two main options. When applying styles directly to an HTML DOM Node using JavaScript, the syntax would be ...

The problem with maintaining a 100% height background image size is persisting

After making progress on the background of my new website, I've hit a roadblock. The background image shrinks to less than 100% height when the browser window is resized. I need the background image to remain full size at all times, without the heigh ...

Struggling to create responsive embedded videos?

https://i.sstatic.net/R0GUn.jpgI have successfully created a responsive video, but there seems to be an issue with the width to height ratio when the browser is fully stretched. The iframe appears narrow and tall in this situation. However, when the browse ...

Incorporate a dynamic fading effect for text and images using JQuery

I successfully implemented a Crossfade effect using Jquery: function doAnimationLoop(o, n, t, i, a) { fadeInOut(o, n, t, i, function() { setTimeout(function() { doAnimationLoop(o, n, t, i, a) }, a) ...

There seems to be an issue with the pseudo-elements :before and :after

I have been attempting to apply a double border to my table using the "border" property for one, and :before and :after for the second. However, I am facing an issue as it is not working properly. I am relatively new to CSS and HTML and have tried my bes ...

Completing the remainder of the page with CSS styling

Currently, I have three Divs positioned absolutely on the page - leftDiv, middleDiv, and rightDiv. The middleDiv has a width of 900px, which is fine. However, I need the leftDiv and rightDiv to fill the remaining space on the left and right sides, regardle ...

I am struggling to make my Bootstrap 5 Navbar transparent. Can anyone help me figure this out?

I've been struggling with my Bootstrap Navbar, which appears as white no matter what I do. I've tried numerous solutions from Stack Overflow to make it transparent without any luck. Even after setting the background to transparent and ensuring t ...

Animate internal navigation buttons to fade in with the use of jQuery

I have a webpage with a gallery of images displayed in an unordered list format. My goal is to create a hover effect where up and down arrows fade in when I hover over an image, allowing the user to click on the arrows to navigate between photos. The curr ...

Get a Blob as a PNG File

Hope you had a wonderful Christmas holiday! Just to clarify, I am new to JS and may make some unconventional attempts in trying to download my Blob in PNG format. I am facing an issue with exporting all the visual content of a DIV in either PDF or image ...

Combine React 17 with webpack 5 and babel-plugin-react-css-modules, enabling the use of CSS modules with stylename functionality

I am in the process of setting up a new React application using the latest technologies available, including React 17, Webpack 5, and other essential modules. My goal is to implement CSS modules utilizing the styleName concept with the help of babel-plugi ...

Dynamic CSS class alteration on scrolling using Vue.js

I am currently in the process of developing a web application using vueJs and bootstrap. I am interested in figuring out how to dynamically change the CSS class of an element based on scrolling behavior. Is there a vue-specific method that can achieve this ...

Attaching the CSS file to the Haml layout template

I'm currently working on linking a css file to a haml layout template Within the ApplicationHelper class, I have a method to properly generate html module ApplicationHelper def styletag(sheet_name) "<link rel='stylesheet' href=&a ...

Angular 4 application fails to occupy the entire screen height

Here is how my app.component looks: <div class="wrapper"> <app-header></app-header> <router-outlet></router-outlet> <footer> <section class="page group"> {{ 'COMPANY.address' | translate ...

When trying to show a Vue view, there was an issue with reading properties of null, specifically the 'style' property

I am experiencing an issue with a header that has an @click event in the body. Instead of displaying a Vue view upon clicking, I am encountering the following error: Cannot read properties of null (reading 'style') Upon researching on Stack Ove ...

Are the JQuery appended elements exceeding the width of the parent div?

I have an HTML div that is styled using the Bootstrap class span9. <div class="span9"> <div id = "selectedtags" class="well"> </div> <button class="btn" type="button" id="delegatecontent">Generate report</button&g ...

What is causing images to stretch unnecessarily in Flexbox on IE11?

I am encountering a problem with flexbox on IE11, and despite being aware of the numerous known issues, I am unable to find a solution... <div class="latest-posts"> <article class="post-grid"> <img src="http://lorempixel.com/ima ...

One way to integrate social sharing buttons into your Django blog

I am currently using the django_social_share module and I am struggling to understand how to send the sharing URL for a specific blog post on social media. Here is my post_detail.html: <article> <div class="embed-responsive embed-responsive-1 ...

Tips on making a progress bar with a reverse text color for the "completed" section

I've been tackling this issue for hours, but haven't found a working solution yet. The challenge is to create a progress bar with a dynamic width and a centered label that changes its text color between the progressed and unprogressed parts. Here ...