如何触发包含三个重叠 div 元素的 :hover 过渡(维恩图)
Posted
技术标签:
【中文标题】如何触发包含三个重叠 div 元素的 :hover 过渡(维恩图)【英文标题】:How can I trigger a :hover transition that includes three overlapping div elements (Venn diagram) 【发布时间】:2021-12-05 14:34:32 【问题描述】:我的问题是我有这个由三个 div 元素组成的维恩图,我想用:hover
缩放它们,这样当我将鼠标悬停在交叉点上时,在交叉点处相遇的所有圆圈都会缩放到我定义的值。目前我只能得到一个圆圈来缩放。
.circles-container
position: relative;
width: 45.625rem;
height: 45.625rem;
.circle-blue
position: absolute;
left: 0rem;
top: 0rem;
width: 28.4375rem;
height: 28.4375rem;
background-color: rgba(187, 231, 254, 0.6);
border-radius: 50%;
.circle-purple
position: absolute;
right: 0rem;
top: 0rem;
width: 28.4375rem;
height: 28.4375rem;
background-color: rgba(211, 181, 229, 0.6);
border-radius: 50%;
.circle-pink
position: absolute;
right: 8.59375rem;
left: 8.59375rem;
bottom: 0rem;
width: 28.4375rem;
height: 28.4375rem;
background-color: rgba(255, 212, 219, 0.6);
border-radius: 50%;
.second-section-circle
transition: all, 1s;
.second-section-circle:hover
transform: scale(1.1);
<div class="circles-container">
<div class="circle-blue second-section-circle"></div>
<div class="circle-purple second-section-circle"></div>
<div class="circle-pink second-section-circle"></div>
</div>
【问题讨论】:
您需要纯 CSS 解决方案吗? 没有 CSS 解决方案。至少我不知道。如果有人能证明我错了,那就太好了。 @DeonRich 检查这个:***.com/a/69623597/8620333 【参考方案1】:一种纯 CSS 解决方案,需要更多元素和一个 CSS 变量来控制大小:
.circles-container
--s:150px; /* adjust this to control the size*/
width: var(--s);
height: var(--s);
margin:calc(var(--s)/3) auto;
display:grid;
.circles-container > *
grid-area: 1/1;
transition: all 1s;
border-radius:50%;
position:relative;
.circle-blue
background: rgba(187, 231, 254, 0.6);
top:calc(var(--s)/3);
.circle-purple
background: rgba(211, 181, 229, 0.6);
left:calc(0.866*calc(var(--s)/3));
top: calc(-0.5 *calc(var(--s)/3));
.circle-pink
background: rgba(255, 212, 219, 0.6);
right:calc(0.866*calc(var(--s)/3));
top: calc(-0.5 *calc(var(--s)/3));
.circles-container > *:nth-child(1)
top:calc(var(--s)/3);
clip-path:circle(calc(var(--s)/2) at 21% 0%);
.circles-container > *:nth-child(2)
right:calc(0.866*calc(var(--s)/3));
top: calc(-0.5 *calc(var(--s)/3));
clip-path:circle(calc(var(--s)/2) at 108% 50%);
.circles-container > *:nth-child(3)
left:calc(0.866*calc(var(--s)/3));
top: calc(-0.5 *calc(var(--s)/3));
clip-path:circle(calc(var(--s)/2) at 21% 100%);
.circles-container > *:nth-child(4)
clip-path: polygon(29% 38%, 50% 34%, 71% 38%, 64% 60%, 50% 74%, 36% 60%);
.circles-container > *:nth-child(-n + 4)
z-index:1;
.circles-container > *:nth-child(1):hover ~ .circle-pink,
.circles-container > *:nth-child(1):hover ~ .circle-blue,
.circles-container > *:nth-child(2):hover ~ .circle-pink,
.circles-container > *:nth-child(2):hover ~ .circle-purple,
.circles-container > *:nth-child(3):hover ~ .circle-blue,
.circles-container > *:nth-child(3):hover ~ .circle-purple,
.circles-container > *:nth-child(4):hover ~ *,
.circles-container > *:nth-child(n + 5):hover
transform: scale(1.15);
<div class="circles-container">
<div></div>
<div></div>
<div></div>
<div></div>
<div class="circle-blue"></div>
<div class="circle-purple"></div>
<div class="circle-pink"></div>
</div>
为额外的 div 添加背景颜色以理解谜题:
.circles-container
--s:150px; /* adjust this to control the size*/
width: var(--s);
height: var(--s);
margin:calc(var(--s)/3) auto;
display:grid;
.circles-container > *
grid-area: 1/1;
transition: all 1s;
border-radius:50%;
position:relative;
.circle-blue
background: rgba(187, 231, 254, 0.6);
top:calc(var(--s)/3);
.circle-purple
background: rgba(211, 181, 229, 0.6);
left:calc(0.866*calc(var(--s)/3));
top: calc(-0.5 *calc(var(--s)/3));
.circle-pink
background: rgba(255, 212, 219, 0.6);
right:calc(0.866*calc(var(--s)/3));
top: calc(-0.5 *calc(var(--s)/3));
.circles-container > *:nth-child(1)
top:calc(var(--s)/3);
clip-path:circle(calc(var(--s)/2) at 21% 0%);
.circles-container > *:nth-child(2)
right:calc(0.866*calc(var(--s)/3));
top: calc(-0.5 *calc(var(--s)/3));
clip-path:circle(calc(var(--s)/2) at 108% 50%);
.circles-container > *:nth-child(3)
left:calc(0.866*calc(var(--s)/3));
top: calc(-0.5 *calc(var(--s)/3));
clip-path:circle(calc(var(--s)/2) at 21% 100%);
.circles-container > *:nth-child(4)
clip-path: polygon(29% 38%, 50% 34%, 71% 38%, 64% 60%, 50% 74%, 36% 60%);
.circles-container > *:nth-child(-n + 4)
z-index:1;
.circles-container > *:nth-child(1):hover ~ .circle-pink,
.circles-container > *:nth-child(1):hover ~ .circle-blue,
.circles-container > *:nth-child(2):hover ~ .circle-pink,
.circles-container > *:nth-child(2):hover ~ .circle-purple,
.circles-container > *:nth-child(3):hover ~ .circle-blue,
.circles-container > *:nth-child(3):hover ~ .circle-purple,
.circles-container > *:nth-child(4):hover ~ *,
.circles-container > *:nth-child(n + 5):hover
transform: scale(1.15);
<div class="circles-container">
<div style="background:red;"></div>
<div style="background:green;"></div>
<div style="background:purple;"></div>
<div style="background:black;"></div>
<div class="circle-blue"></div>
<div class="circle-purple"></div>
<div class="circle-pink"></div>
</div>
【讨论】:
当您稍微移出重叠区域进入其中一个圆圈时,会发生轻微故障。似乎可以通过删除:nth-child(n + 5)
来解决此问题,以便所有额外区域也可以通过自己的悬停扩展。【参考方案2】:
我最终确定了Deon Rich's idea,以便圆圈对越界做出反应,而不是围绕它们描述的正方形的边界。
还添加了一个辅助函数和循环,以免手动列出图表中的所有圆圈。现在脚本代码不依赖于图中的圈数了。
https://codepen.io/glebkema/pen/OJjNwzd
let circlesElements = document.getElementsByClassName("second-section-circle");
let circlesInfo = [];
for (let elem of circlesElements)
circlesInfo.push(getCircleInfo(elem));
// console.log(circlesInfo);
window.addEventListener("mousemove", (e) =>
for (let info of circlesInfo)
let deltaX = e.pageX - info.centerX;
let deltaY = e.pageY - info.centerY;
if (deltaX * deltaX + deltaY * deltaY <= info.radius2)
// if mouse is over element, scale it...
info.elem.style.transform = "scale(1.2)";
else
// otherwise, dont scale it...
info.elem.style.transform = "scale(1)";
);
function getCircleInfo(elem)
let rect = elem.getBoundingClientRect();
let radius = (rect.right - rect.left) / 2;
return
elem: elem,
centerX: (rect.right + rect.left) / 2,
centerY: (rect.bottom + rect.top) / 2,
radius2: radius * radius
;
.circles-container
position: relative;
width: 45.625rem;
height: 45.625rem;
.second-section-circle
position: absolute;
width: 28.4375rem;
height: 28.4375rem;
border-radius: 50%;
transition: all, 1s;
.circle-blue
left: 0rem;
top: 0rem;
background-color: rgba(187, 231, 254, 0.6);
.circle-pink
right: 8.59375rem;
left: 8.59375rem;
bottom: 0rem;
background-color: rgba(255, 212, 219, 0.6);
.circle-purple
right: 0rem;
top: 0rem;
background-color: rgba(211, 181, 229, 0.6);
<div class="circles-container">
<div class="second-section-circle circle-blue"></div>
<div class="second-section-circle circle-purple"></div>
<div class="second-section-circle circle-pink"></div>
</div>
【讨论】:
我建议不要使用 Math.pow() 对数字进行平方。最好只使用例如:((rect.right - rect.left) / 2) * ((rect.right - rect.left) / 2)
。或者预先计算其中一些:let radius = (rect.right - rect.left) / 2
,然后使用radius * radius
。 Math.pow() 往往会慢一些,因为它设计用于处理任何数字,但平方是一个更简单的操作,因此不需要那么多开销。
@DarrelHoffman 我同意你的观点,直接乘法更快。我已经更新了代码。【参考方案3】:
您可以实现这一点,但您需要一点 javascript。别担心,没什么太复杂的。您可以做的是使用element.getBoundingClientRect()
方法获取每个圆圈的尺寸,就像这样......
let blue = document.querySelector(".circle-blue").getBoundingClientRect();
let purple = document.querySelector(".circle-purple").getBoundingClientRect();
let pink = document.querySelector(".circle-pink").getBoundingClientRect();
然后每次用户移动鼠标时,您可以测试鼠标是否在给定元素上,如果是,您可以缩放它,而不管哪个元素与另一个重叠,因此会导致任何圆圈缩放,包括交叉点中包含的圆圈...
let blue = document.querySelector(".circle-blue").getBoundingClientRect();
let purple = document.querySelector(".circle-purple").getBoundingClientRect();
let pink = document.querySelector(".circle-pink").getBoundingClientRect();
window.addEventListener("mousemove", (e) =>
let x = e.pageX,y = e.pageY;
//test blue...
if (x > blue.left && x < blue.right && y > blue.top && y < blue.bottom)
// if mouse is over element, scale it...
document.querySelector(".circle-blue").style.transform = "scale(1.2)";
else
// otherwise, dont scale it...
document.querySelector(".circle-blue").style.transform = "scale(1)";
//test purple...
if (x > purple.left && x < purple.right && y > purple.top && y < purple.bottom)
// if mouse is over element, scale it...
document.querySelector(".circle-purple").style.transform = "scale(1.2)";
else
// otherwise, dont scale it...
document.querySelector(".circle-purple").style.transform = "scale(1)";
//test pink...
if (x > pink.left && x < pink.right && y > pink.top && y < pink.bottom)
// if mouse is over element, scale it...
document.querySelector(".circle-pink").style.transform = "scale(1.2)";
else
// otherwise, dont scale it...
document.querySelector(".circle-pink").style.transform = "scale(1)";
);
.circles-container
position: relative;
width: 45.625rem;
height: 45.625rem;
.circle-blue
position: absolute;
left: 0rem;
top: 0rem;
width: 28.4375rem;
height: 28.4375rem;
background-color: rgba(187, 231, 254, 0.6);
border-radius: 50%;
.circle-purple
position: absolute;
right: 0rem;
top: 0rem;
width: 28.4375rem;
height: 28.4375rem;
background-color: rgba(211, 181, 229, 0.6);
border-radius: 50%;
.circle-pink
position: absolute;
right: 8.59375rem;
left: 8.59375rem;
bottom: 0rem;
width: 28.4375rem;
height: 28.4375rem;
background-color: rgba(255, 212, 219, 0.6);
border-radius: 50%;
.second-section-circle
transition: all, 1s;
<div class="circles-container">
<div class="circle-blue second-section-circle"></div>
<div class="circle-purple second-section-circle"></div>
<div class="circle-pink second-section-circle"></div>
</div>
【讨论】:
这存在碰撞箱问题,因为您将圆圈视为正方形。您可以通过使用欧几里得距离公式来解决此问题 - 如果到圆心的绝对距离小于其宽度的一半,则展开它。 是的,我知道这些盒子稍微限制了它的功能。感谢您的洞察力以上是关于如何触发包含三个重叠 div 元素的 :hover 过渡(维恩图)的主要内容,如果未能解决你的问题,请参考以下文章
css 在optin显示之前,将包含YouTube视频集的div加载到我们手动触发的optin后面进行自动播放。我们将加载重叠