Если указатель мыши наводит курсор на элемент на 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
псевдоэлемент, который вы расположите над этим пересечением, чтобы он мог «захватить» курсор мыши в этой области.
Это казалось хорошим решением, но div .blue является дочерним элементом div .red, а не дочерним элементом какого-либо псевдоэлемента в div .red. «Псевдоэлементы — это... недействительные селекторы внутри :has())». Таким образом, невозможно захватить указатель мыши над псевдоэлементом .red и использовать его для применения стиля к его дяде .blue. .red:has(::after:hover) .blue
не работает.
Примените предложенный мной селектор и добавьте div.red::after { content: ""; position: absolute; inset: 50% 0 0 50%; background: rgba(255, 0, 0, .5); }
— это должно помочь. (цвет фона добавлен только для того, чтобы можно было легко увидеть, где расположен псевдоэлемент; вы можете удалить его, как только выясните точное правильное позиционирование.)
Спасибо за ваш постоянный поиск решения. Я применил ваше предложение в CodePen, чтобы сохранить его отдельно. Я использовал более сложный набор правил для стиля ::after
, но эффект аналогичен тому, что вы задумали. При наведении курсора мыши на элемент ::after
синий квадрат не выделяется.
Сделайте .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>
Вы можете применить форматирование при наведении для красного элемента, только если у него нет наведенного синего потомка —
div.red:hover:not(:has(.blue:hover))