Может ли CSS обнаружить разницу между фактическим и унаследованным наведением?

Если указатель мыши наводит курсор на элемент на HTML-странице, браузер создает псевдокласс :hover для этого элемента и для всех его родителей, даже если указатель мыши не наводит курсор на какую-либо часть самого родительского элемента.

Вы можете увидеть это во фрагменте ниже. В примере «Два вложенных элемента Div» при наведении курсора на синий квадрат также будет создан псевдокласс :hover для его родительского красного квадрата.

Существует ли селектор CSS, который можно использовать для реакции на мышь, только если мышь находится над самим красным квадратом?

Я показал обходной путь в примере с тремя перекрывающимися элементами. Здесь красный и синий квадраты являются однородными, а на пересечении видимых квадратов находится невидимый квадратный элемент div. Этот невидимый квадрат перехватывает событие указателя, которое запускает создание псевдокласса :hover. Это позволяет мне писать CSS, который реагирует так, как если бы для обоих видимых квадратов существовал псевдокласс :hover. Это также предотвращает привязку класса :hover к красному квадрату, когда указатель мыши находится над синим квадратом, поскольку здесь нет наследования.

Однако в примере с тремя перекрывающимися элементами синий квадрат больше не является дочерним элементом красного квадрата. В моем реальном случае это наследование — это то, чего я хочу.

: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>

Вы можете применить форматирование при наведении для красного элемента, только если у него нет наведенного синего потомка — div.red:hover:not(:has(.blue:hover))

C3roe 26.08.2024 14:04

Да, но когда указатель мыши находится над перекрестком, я хочу, чтобы красный квадрат реагировал.

James Newton 26.08.2024 14:12

Затем дайте div.red псевдоэлемент, который вы расположите над этим пересечением, чтобы он мог «захватить» курсор мыши в этой области.

C3roe 26.08.2024 14:50

Это казалось хорошим решением, но div .blue является дочерним элементом div .red, а не дочерним элементом какого-либо псевдоэлемента в div .red. «Псевдоэлементы — это... недействительные селекторы внутри :has())». Таким образом, невозможно захватить указатель мыши над псевдоэлементом .red и использовать его для применения стиля к его дяде .blue. .red:has(::after:hover) .blue не работает.

James Newton 26.08.2024 15:34

Примените предложенный мной селектор и добавьте div.red::after { content: ""; position: absolute; inset: 50% 0 0 50%; background: rgba(255, 0, 0, .5); } — это должно помочь. (цвет фона добавлен только для того, чтобы можно было легко увидеть, где расположен псевдоэлемент; вы можете удалить его, как только выясните точное правильное позиционирование.)

C3roe 26.08.2024 15:49

Спасибо за ваш постоянный поиск решения. Я применил ваше предложение в CodePen, чтобы сохранить его отдельно. Я использовал более сложный набор правил для стиля ::after, но эффект аналогичен тому, что вы задумали. При наведении курсора мыши на элемент ::after синий квадрат не выделяется.

James Newton 26.08.2024 16:29
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
CSS: FlexBox
CSS: FlexBox
Ранее разработчики использовали макеты с помощью Position и Float. После появления flexbox сценарий полностью изменился.
1
6
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сделайте .overlap дочерним элементом .blue и .blue дочерним элементом .red, затем немного измените состояние .red.

: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>

Другие вопросы по теме