在相对定位元素内计算居中的绝对定位div

3
我正在使用两种JavaScript方法来定位页面上静态元素内的悬停按钮。居中的按钮被输入到第一个元素中,并使用绝对定位。我使用以下代码获取父元素的尺寸:
// calculate if the element is in the visible window
function elementVisibleRect(element) {
    element = $(element);
    var rect = {
        top: Math.round(element.offset().top),
        left: Math.round(element.offset().left),
        width: Math.round(element.outerWidth()),
        height: Math.round(element.outerHeight())
    };
    var scrollTop = $(window).scrollTop();
    var windowHeight = $(window).height();
    var scrollBottom = scrollTop + windowHeight;
    var elementBottom = Math.round(rect.height + rect.top);

    if (scrollTop < rect.top && scrollBottom > elementBottom) {
        return rect;
    }
    if (scrollTop > rect.top) {
        rect.top = scrollTop;
    }
    if (scrollBottom < elementBottom) {
        rect.height = scrollBottom - rect.top;
    } else {
        rect.height = windowHeight - (scrollBottom - elementBottom);
    }
    return rect;
}

为了使用这些信息并将按钮居中

// center the element based on visible screen-frame
function elementPosition (element) {
    var visibleRect = elementVisibleRect(element);
    $('.editHoverButton').css({
        top: visibleRect.top + ((visibleRect.height / 2) - ($('.editHoverButton').outerHeight() / 2)),
        left: visibleRect.left + (visibleRect.width / 2) - ($('.editHoverButton').outerWidth() / 2)
    });
}

现在我的问题是,第三方库需要将父级DIV的位置从浏览器默认的“静态”更改为“相对”,这会破坏我在第二个函数中的计算。也许已经晚了,但无论我尝试什么,似乎都无法弄清楚如何在父元素的位置设置为相对时使其工作。我似乎无法正确处理数学问题,我的头开始疼了。有什么建议吗?编辑-添加JSFIDDLE。

http://jsfiddle.net/RhTY6/


你可以尝试使用!important声明来覆盖第三方的CSS。但一定要确保正确地定位DOM。 http://www.w3.org/TR/CSS2/cascade.html#important-rules - JerryHuang.me
也许我没有表达清楚,但是我需要它保持相对位置以便其他功能正常运行,不能更改它。 - user45454545
3
您能否将一个包含 HTML 和 CSS 的示例发布到 Fiddle 上? - JerryHuang.me
2个回答

3
使用绝对定位的元素从自然流中移除(例如,它们不会留下原来所在的空间)并相对于第一个非static定位的父元素进行定位。由于右侧框的定位是relative(而不是static),因此您可以使用top: 50%;left: 50%;定位按钮。这将使顶部左侧角位于父元素的中心。然后,您只需使用margin-topmargin-left从位置中减去元素高度和宽度的一半即可。如下所示,这比您之前做的要简单得多:

JavaScript:

function elementPosition() {
    $('.editHoverButton').css('margin-top', 0 - $('.editHoverButton').outerHeight() / 2);
    $('.editHoverButton').css('margin-left', 0 - $('.editHoverButton').outerWidth() / 2);
};

CSS:

.editHoverButton {
  position: absolute;
  z-index: 99;
  font-family: sans-serif;
  font-size: 14px;
  font-weight: normal;
  background-color: #00bb00;
  top: 50%;
  left: 50%;
}

除了从elementPosition()函数中删除this之外,没有其他改变。

演示(请注意,左边的不再起作用。这是因为它被定位为static。)

编辑--使用相同的基本思路,该方法应该可行:

问题在于,在定义rect时,必须考虑元素的上下位置。更改这些位置计算为0(不是最佳方法,但可行),可以解决relative元素的问题。

演示(请注意,左边的现在可以工作。这是因为它已经被定位为0,0。)

编辑--当页面滚动时,此方法将起作用:

将容器设置为变量,以便在页面滚动时可以自动重新定位。

演示


好的,但这只能将按钮始终居中于容器div的中心;如果容器div比视口大,则OP希望将其居中于视口。尝试降低小提琴的高度,您会看到这一点。他处于混合状态,必须根据容器的视口包含或视口溢出状态应用固定或绝对位置,或编写更复杂的脚本。 - Andrea Ligios
2
嗯...我明白你的意思。我会处理的。 - Ian
2
好的,我这次明白了。 - Ian
2
抱歉,我的第二个演示链接是错误的(它与第一个相同)。 - Ian
2
是的,但当元素没有定位在滚动轴的开头时,情况就变得非常奇怪——按钮会跑到右边或底部。我仍然无法完全理解这个数学问题,但当你的元素在开始时没有定位在顶部时,滚动时会出现跳跃。演示 - Ian
显示剩余2条评论

1

编辑:通过仅更改脚本,使其与您的CSS和HTML(相对和绝对定位)配合使用。

水平轴计算完全缺失(我已经应用了您应用于垂直轴的相同计算)。

我添加了一些数据和标尺来帮助您完成工作:正如您可以看到的那样,它(在您原始的 fiddle 中也是这样)并不是完美居中的(显然,当容器小于视口时,您需要查看它),但这将很容易解决。

运行演示

尝试调整 fiddle 窗口的大小,并垂直和水平滚动以查看它是否有效。

function elementVisibleRect(element) {
    $("#data").html("");

    element = $(element);
    var rect = {
        top: Math.round(element.offset().top),
        left: Math.round(element.offset().left),
        width: Math.round(element.outerWidth()),
        height: Math.round(element.outerHeight())
    };
    var scrollTop = $(window).scrollTop();
    var windowHeight = $(window).height();
    var scrollBottom = scrollTop + windowHeight;
    var elementBottom = Math.round(rect.height + rect.top);

    var scrollLeft = $(window).scrollLeft();
    var windowWidth = $(window).width();
    var scrollRight = scrollLeft + windowWidth;
    var elementRight = Math.round(rect.width + rect.left);


    addData("rect.top", rect.top);
    addData("rect.left", rect.left);
    addData("rect.width", rect.width);
    addData("rect.height", rect.height);
    addData("scrollTop", scrollTop);
    addData("windowHeight", windowHeight);
    addData("scrollBottom", scrollBottom);
    addData("elementBottom", elementBottom);
    addData("scrollLeft", scrollLeft);
    addData("windowWidth", windowWidth);
    addData("scrollRight", scrollRight);
    addData("elementRight", elementRight);


    if (rect.top < scrollTop) {
        rect.top = scrollTop;
    }
    if (scrollBottom < rect.top < scrollTop) {
        rect.top = scrollTop;
    }
    if (scrollBottom < elementBottom) {
        rect.height = scrollBottom - rect.top;
    } else {
        rect.height = windowHeight - (scrollBottom - elementBottom);
    }

    if (rect.left < scrollLeft) {
        rect.left = scrollLeft;
    }
    if (scrollRight < rect.left < scrollLeft) {
        rect.left = scrollLeft;
    }
    if (scrollRight < elementRight) {
        rect.width = scrollRight - rect.left;
    } else {
        rect.width = windowWidth - (scrollRight - elementRight);
    }

    return rect;
}

还不错,真没想到我错过了尝试它的机会。但仍然存在很多问题,就像在这个fiddle中可以看到的那样:它并不能始终保持在可视区域的中心位置。http://jsfiddle.net/RhTY6/2/ - user45454545
是的,你应该调整你的脚本。如果你的 div 比可视区域大,那么 fixed 就会起作用(没有任何脚本,只需 CSS 居中),因为它与视口一起工作。如果你的 div 小于可视区域,则你的脚本将起作用,因为它能正确计算位置。灰色区域是当你的 div 在一个轴(如水平)上比可视区域大,在另一个轴(如垂直)上较小时。这是棘手的部分... - Andrea Ligios
3
fixed的问题在于它是相对于可滚动窗口的,这意味着如果您在按钮可见时滚动页面,按钮不会随页面一起滚动。 DEMO - Ian
我知道,但由于他总是希望它居中(如果较小,则相对于容器;如果较大,则相对于视口),因此这可以满足他的需求(我在回答中的意思是这个)。 - Andrea Ligios
2
我不知道为什么会这样,但你可以通过在elementPosition(element)函数中使用var width = $('.editHoverButton').width();width: width来修复它。演示 - Ian
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接