【问题标题】:Allow element's after and before content to override parent overflow restriction允许元素的前后内容覆盖父溢出限制
【发布时间】:2015-07-04 03:12:53
【问题描述】:

我有一个div,其overflow 属性设置为scroll,以便在不占用太多页面空间的情况下查看所有包含的字段。每个字段都有一个跨度(字段的标题)和关联的输入。我为用户提供了将鼠标悬停在跨度上并查看一些有用信息作为工具提示的可能性。我在跨度悬停上使用跨度afterbefore 伪元素以添加自定义工具提示。但是,工具提示的显示受到父div溢出限制。

这是一个呈现的 HTML 示例:

<div id="ContentPlaceHolder1_leftDiv" class="l-custom-left">     
    <div class="personalizedFields">
        <table>
            <tr>
                <td>
                    <span title="Champ associé: Prenom" class="tooltip">Prénom</span>
                </td>
            </tr>
            <tr>
                <td>
                    <input name="ctl00$ContentPlaceHolder1$ucPF$ucCustomField36$field36" type="text" id="field36" />

                </td>
            </tr>

            <tr>
                <td>
                    <span title="Champ associé: Nom" class="tooltip">Nom</span>
                </td>
            </tr>
            <tr>
                <td>
                    <input name="ctl00$ContentPlaceHolder1$ucPF$ucCustomField37$field37" type="text" id="field37" />

                </td>
            </tr>
        </table>
    </div>
</div>

父div和span的css:

.l-custom-left
{
    overflow-x: hidden;
    width: 250px;
    height: 50vh;
}

.tooltip:hover:after{
    background: #333;
    background: rgba(0,0,0,.8);
    border-radius: 5px;
    bottom: 26px;
    color: #fff;
    content: attr(title);
    left: 20%;
    padding: 5px 10px;
    position: absolute;
    z-index: 98;
}

.tooltip:hover:before{
    border: solid;
    border-color: #333 transparent;
    border-width: 6px 6px 0 6px;
    bottom: 20px;
    content: "";
    left: 50%;
    position: absolute;
    z-index: 99;
}

如何让内容前后的 span “覆盖” div 父级溢出限制?

JSfiddle

【问题讨论】:

  • “覆盖”是什么意思?您希望实现什么目标?
  • @Vucko 我希望我的跨度的前后内容溢出,但不是我的跨度,如果这有意义的话。如果您查看我的 JSFiddle,我希望可以滚动字段以保持不变,但正确显示所有“工具提示”。如果您悬停第一个,例如,您可以看到它没有显示,因为overflow-x: hidden;
  • 好吧,我明白问题所在,但我怀疑是否有办法覆盖父母 overflow。但是,我会将前两个元素的工具提示放在输入下方,其余的工具提示放在输入上方 - example

标签: javascript jquery html css


【解决方案1】:

如果你真的想让它起作用,有两种方法。第一种是使用JavaScript(我将不再赘述)将一个元素放置在容器外元素的位置。这是一个令人讨厌的修复,在 CSS3 出现之前,我不得不实现它太多次了。

第二个更优雅,但确实破坏了 HTML 的语义。您的 :before:after 伪不会从滚动容器中弹出的原因是它们被视为 .tooltip 元素的子元素,因此是滚动容器文档流的一部分,即使它们'绝对定位。

那么我们该如何处理呢?我们作弊,简单明了。

span 之后添加第二个元素,如下所示:

<span class="tooltip">Prénom</span>
<span title="Champ associé: Prenom" class="tooltip-hovershim">Prénom</span>

我们保持相同的内容,以便元素大小相同。

然后,像这样改变你的 CSS:

.tooltip, .tooltip-hovershim
{
    display: inline;
}

.tooltip:hover:after, .tooltip-hovershim:hover:after{
    background: #333;
    background: rgba(0,0,0,.8);
    border-radius: 5px;
    bottom: 26px;
    color: #fff;
    content: attr(title);
    left: 20%;
    padding: 5px 10px;
    position: absolute;
    z-index: 98;
}
.tooltip-hovershim { 
    position: absolute;
    transform: translateX(-100%);
    color: transparent;
}

.tooltip:hover:before, .tooltip-hovershim:hover:before {
    border: solid;
    border-color: #333 transparent;
    border-width: 6px 6px 0 6px;
    bottom: 20px;
    content: "";
    left: 50%;
    position: absolute;
    z-index: 99;
}

瞧! Vous avez votre élément flottant。就这么简单。

JSFiddle Example

为简洁起见,仅应用于前两个元素。


只是为了搞笑,这里是 Javascript 变体

JSFiddle with the JS variant

这是 Javascript 的关键部分:

var span_labels = document.querySelectorAll('.personalizedFields td span'),
    label_house = document.createElement('div');

document.body.appendChild(label_house);
label_house.setAttribute('class', 'tooltip-hoverer');

for (var i=0,l=span_labels.length;i<l;i++){
  var curr_label = span_labels[i];
    curr_label.addEventListener('mouseover', function(e) {
       e.preventDefault();
       label_house.innerHTML = e.target.getAttribute('title');
       var xy = getOffset(e.target);
       label_house.style.top = (xy.top - 26) + 'px';
       label_house.style.left = (xy.left) + 'px';
       label_house.style.display = 'block';
    });
    curr_label.addEventListener('mouseout', function() {
       label_house.style.display = 'none'; 
    });
}
                                
function getOffset(el) {
    var elementRectangle = el.getBoundingClientRect();
    var _x = elementRectangle.left;
    var _y = elementRectangle.top + el.offsetParent.scrollTop;
    return { top: _y, left: _x };
}

【讨论】:

  • 可能需要用到JS。恰好我也添加了一个 JS 解决方案。
  • 部分问题在于,一旦您给容器一个relative 位置,这个解决方案就不再有效。这只是文档流的现实。当您只是想逃避overflow: hidden,但忘记了overflow: scrollposition: absolute 交互的细微差别时,这是一个非常有用的解决方案。
  • 谢谢,你让我明白了很多点。我将使用 JS 解决方案来满足我的需求。
  • 最后一个问题乔希。如何找到跨度(在可滚动的 div 内)相对于窗口的位置?或者也许我没有正确的逻辑?在您的小提琴中,如果您向下滚动 div,您会看到工具提示的位置不太正确,因为它们是相对于 div 的。我已经尝试了很多事情,但我觉得我从错误的角度看事情。
  • 新的一天,新的头脑......我找到了一种解决方案,无论您在 div 内滚动多少以及在页面中滚动多少都有效。 JSFiddle here。如果你愿意,你可以把它放在你的答案中。非常感谢您的帮助。
【解决方案2】:

由于我想做的事情仅使用 CSS 是不可行的,因此我决定使用 JavaScript 和 JQuery 的组合,灵感来自 Josh Burgess 的 JS 解决方案。因此,如果您正在寻找更面向 JQuery 的解决方案,这里是:

var tooltip;

$(document).ready(function() {
    $('span.tooltip').on({
        mouseenter: function (e) {
            tooltip = document.createElement('div');
            document.body.appendChild(tooltip);
            $(tooltip).addClass('tooltip-hoverer');
            $(tooltip).text($(this).attr('data-tooltip'));
            var x = e.clientX - (($(tooltip).outerWidth()) / 2); // "($(tooltip).outerWidth() / 2)" is required to show the tooltip's down arrow next to the mouse's left position
            var y = this.getBoundingClientRect().top + this.offsetParent.scrollTop;
            $(tooltip).css({
                top: y - 32,
                left: x,
                display: 'block'
            });
        },
        mouseleave: function () {
            document.body.removeChild(tooltip);
        }
    });                       
});

请注意,与 Josh 的解决方案不同,我不会在加载时创建所有工具提示,而是每次悬停跨度时只创建一个,然后在光标离开跨度时将其删除。

JSFiddle can be found here

【讨论】:

    猜你喜欢
    • 2022-01-17
    • 1970-01-01
    • 2016-05-17
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多