admin管理员组文章数量:1386760
I have an absolutely positioned tooltip within an ancestor element. The ancestor has overflow: auto
so that if its content overflows, it will provide a scrollbar. But I don't want the tooltip to be included in this content - I want the tooltip to break out of this box and overflow it. I can achieve this by setting it to position: fixed
, but then it won't stay with its immediate parent (the thing I'm hovering over) if the user has scrolled. Absolute positioning stays with the parent, but the tooltip gets clipped.
How can I have the tooltip stay where it belongs, anchored to the hovered element even while scrolling, and yet allow the tooltip to go beyond the boundaries of the scrollable ancestor?
With fixed positioning (tooltip is not aligned iwth the TS$ element my mouse is over, due to the scrollbar offset:
With absolute positioning (tooltip is correctly positioned even with scroll, but the tooltip is clipped):
Update:
I was able to get the behavior I wanted with some inelegant calculations to set left
and top
with values while using position: fixed
. It required recursively traversing up the DOM until hitting a new containing box, and aggregating all the scroll values, and traversing up the offset chain to aggregate the offsets, then subtracting.
export const isFixedContainingBlock = (el) => {
const style = getComputedStyle(el)
return ([style.filter,style.backdropFilter,style.transform,style.perspective].some(v => v !== "none") ||
["layout","paint","strict","content"].includes(style.contain) ||
style.containerType !== "normal" ||
["filter","transform"].includes(style.willChange) ||
style.contentVisibility === "auto")
}
then:
import { isFixedContainingBlock } from ...
let ot=0, ol=0, st=0, sl=0
for (let n=e.target;!isFixedContainingBlock(n); n=n.parentElement) {
sl += n.scrollLeft
st += n.scrollTop
}
for (let n=e.target;!isFixedContainingBlock(n); n=n.offsetParent) {
ot += n.offsetTop
ol += n.offsetLeft
}
let posLeft=ol-sl, posTop=ot-st
node.style.setProperty('left', posLeft+"px")
node.style.setProperty('top', posTop+"px")
This is working, but it shouldn't be this hard to do something so simple. It sure seems as if CSS ought to provide a better way to do this.
I have an absolutely positioned tooltip within an ancestor element. The ancestor has overflow: auto
so that if its content overflows, it will provide a scrollbar. But I don't want the tooltip to be included in this content - I want the tooltip to break out of this box and overflow it. I can achieve this by setting it to position: fixed
, but then it won't stay with its immediate parent (the thing I'm hovering over) if the user has scrolled. Absolute positioning stays with the parent, but the tooltip gets clipped.
How can I have the tooltip stay where it belongs, anchored to the hovered element even while scrolling, and yet allow the tooltip to go beyond the boundaries of the scrollable ancestor?
With fixed positioning (tooltip is not aligned iwth the TS$ element my mouse is over, due to the scrollbar offset:
With absolute positioning (tooltip is correctly positioned even with scroll, but the tooltip is clipped):
Update:
I was able to get the behavior I wanted with some inelegant calculations to set left
and top
with values while using position: fixed
. It required recursively traversing up the DOM until hitting a new containing box, and aggregating all the scroll values, and traversing up the offset chain to aggregate the offsets, then subtracting.
export const isFixedContainingBlock = (el) => {
const style = getComputedStyle(el)
return ([style.filter,style.backdropFilter,style.transform,style.perspective].some(v => v !== "none") ||
["layout","paint","strict","content"].includes(style.contain) ||
style.containerType !== "normal" ||
["filter","transform"].includes(style.willChange) ||
style.contentVisibility === "auto")
}
then:
import { isFixedContainingBlock } from ...
let ot=0, ol=0, st=0, sl=0
for (let n=e.target;!isFixedContainingBlock(n); n=n.parentElement) {
sl += n.scrollLeft
st += n.scrollTop
}
for (let n=e.target;!isFixedContainingBlock(n); n=n.offsetParent) {
ot += n.offsetTop
ol += n.offsetLeft
}
let posLeft=ol-sl, posTop=ot-st
node.style.setProperty('left', posLeft+"px")
node.style.setProperty('top', posTop+"px")
This is working, but it shouldn't be this hard to do something so simple. It sure seems as if CSS ought to provide a better way to do this.
Share Improve this question edited Mar 18 at 20:30 Paul W asked Mar 17 at 16:55 Paul WPaul W 12.2k2 gold badges7 silver badges24 bronze badges 2- 1 I don't think this is possible because if it is absolute, then it will be within the overflow container, which makes it get clipped. The best you can do is use the fixed position but calculate the position using the offset of the hovered element – Pete Commented Mar 17 at 17:13
- Use some library, for example Tippy.js – imhvost Commented Mar 17 at 21:25
1 Answer
Reset to default 0One approach you can take in pure css is wrapping the parent with a "container". First you use position: fixed;
to overcome the overflow and then move the container from the viewport to the parent by setting the contain property. This keeps the overflowed content parked relatively:
ul {
width: 200px;
max-height: 250px;
overflow: auto;
margin: 1em;
color: white;
font-family: sans-serif;
font-size: 16px;
}
li {
position: relative;
padding: 1em;
}
li ul {
position: absolute;
z-index: 10;
display: none;
margin: 0;
cursor: auto;
}
li:hover > ul {
display: block;
}
li:nth-child(2n) {
background: #0E8CE0;
}
li:nth-child(2n+1) {
background: #0064B3;
}
li.parent {
background: #00B99B;
cursor: pointer;
}
.ancestor {
height: 200px;
overflow: auto; /* captures everything not having position:fixed */
border: dashed red;
}
.tooltip {
position: fixed; /* escape the overflow on ancestor */
top: 0;
left: 50px;
}
.contain {
height: fit-content;
background-color: amber;
contain: layout; /* fixed position will be contained here */
}
.buffer {
height: 10rem;
background-color: aqua;
}
<div class="buffer">Some page content</div>
<div class="contain">
<div class="ancestor">
<ul>
<li>Abc</li>
<li>Def</li>
<li>Ghi</li>
<li>Jkl</li>
<li class="parent">TooltipHere >
<ul class="tooltip">
<li>Abc</li>
<li>Def</li>
<li>Ghi</li>
<li>Jkl</li>
<li>Mno</li>
<li>Pqr</li>
<li>Stu</li>
<li>Vw</li>
<li>Xyz</li>
</ul>
</li>
<li>Pqr</li>
<li>Stu</li>
<li>Vw</li>
<li>Xyz</li>
<li>Def</li>
<li>Ghi</li>
<li>Jkl</li>
<li>Mno</li>
<li>Pqr</li>
<li>Stu</li>
<li>Vw</li>
<li>Xyz</li>
</ul>
<div class="buffer">Some page content</div>
</div>
</div>
Hopefully this helps. Nevertheless, it's nice to get minimum reproducible examples so that nuances can be taken into account. Depending on your setup a pure css solution might not be possible.
本文标签:
版权声明:本文标题:css - How to allow absolutely positioned child element (e.g. a tooltip) to overflow an ancestor element with overflow: auto - St 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744544815a2611833.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论