我的问题涉及以下演示http://jsfiddle.net/legrass/ca22L/和http://jsfiddle.net/legrass/eER66/2/。
简而言之,我需要突出显示页面上的一些元素(例如,通过红色边框),但不要触及实际元素(以避免影响原始页面的布局)。 为此,在JS中我创建绝对位于元素上的'overlay'元素,以使用top,left坐标突出显示。它们被附加到body并通过CSS设置样式(请参阅第一个JSFiddle)。 例如:
<body>
<div class='overlay'>
<span class="a" style="top: 14px; left: 321px; width: 200px; height: 140px;"> </span>
<span class="b" style="top: 52px; left: 351px; width: 140px; height: 63px;"> </span>
<span class="c" style="top: 72px; left: 400px; width: 8px; height: 16px;"></span>
<span class="c" style="top: 74px; left: 420px; width: 8px; height: 16px;"></span>
</div>
....
工作正常。但是,为了允许更灵活的css选择器(例如,子),我需要通过嵌套来构建上面的叠加,如:
<body>
<div class='overlay'>
<span class="a" style="top: 14px; left: 321px; width: 200px; height: 140px;">
<span class="b" style="top: 52px; left: 351px; width: 140px; height: 63px;">
<span class="c" style="top: 72px; left: 400px; width: 8px; height: 16px;"></span>
<span class="c" style="top: 74px; left: 420px; width: 8px; height: 16px;"></span>
<span/>
<span/>
</div>
....
嵌套可以在任何深度。不幸的是现在定位不正确,(见第二个JSFiddle)。
我知道这是因为每个跨度现在都是绝对定位的,但是相对于它的父级,而不再是单个容器div。我尝试过相对定位,但当然不行。
问题:有没有办法像第一个JSfiddle那样获得布局,但是维护跨度层次结构?
更新 从下面的答案,使用offsetLeft和offsetTop调整坐标确实有帮助。我计算了DOM上的总偏移量,并添加了offsetLeft(offsetTop),直到offsetParent存在。 然而,结果仍然是几个像素移位,似乎还有其他事情需要考虑。任何的想法?
解决 如下面评论中所述,还需要考虑边框宽度。
答案 0 :(得分:2)
您可以使用轮廓添加边框而不会影响框模型。
答案 1 :(得分:1)
目前,CSS 不有一种方法来定位元素,而不是相对于其相对或绝对定位的最近的祖先。但是由于您使用JS,您可以根据其祖先元素的偏移量更改每个元素的偏移量(left
,top
)并获得所需的结果。
Quirks模式function的改进版本(考虑边界):
function getCssPropertyValue(elem, prop) {
return window.getComputedStyle
// Modern browsers.
? window.getComputedStyle(elem, null).getPropertyValue(prop)
// IE8 and older.
: elem.currentStyle.getAttribute(prop);
}
function findPos(obj) {
var curleft = curtop = 0;
if (!obj.offsetParent) {
return;
}
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
// If not Opera and not IE8 (see http://tanalin.com/en/articles/ie-version-js/ )
// Opera and IE8 return incorrect values otherwise.
if (!window.opera && (!document.all || document.addEventListener || !document.querySelector)) {
var blw = parseInt(getCssPropertyValue(obj, 'border-left-width'), 10),
btw = parseInt(getCssPropertyValue(obj, 'border-top-width'), 10);
if (blw) {
curleft += blw;
}
if (btw) {
curtop += btw;
}
}
}
while (obj = obj.offsetParent);
return [curleft, curtop];
}
更新:更加清晰,紧凑,快速,准确,面向未来且防弹的解决方案是使用element.getBoundingClientRect()
:
function getElementCoords(elem) {
var root = document.documentElement,
body = document.body,
sTop = window.pageYOffset || root.scrollTop || body.scrollTop,
sLeft = window.pageXOffset || root.scrollLeft || body.scrollLeft,
cTop = root.clientTop || body.clientTop || 0,
cLeft = root.clientLeft || body.clientLeft || 0,
rect = elem.getBoundingClientRect(),
top = Math.round(rect.top + sTop - cTop),
left = Math.round(rect.left + sLeft - cLeft);
return {
top : top,
left : left
};
}
顺便说一句,考虑使用jQuery的offset()
,其中crossbrowser的不一致性已经开箱即用。
答案 2 :(得分:0)
position: absolute
使元素相对于第一个非静态定位的祖先定位(换句话说,“绝对”实际上是相对的!)。由于您的包含跨度不是静态定位(它们是绝对定位的),因此包含的跨度相对于其父项定位,而不是.overlay
。获得相同效果的唯一方法是考虑所有祖先的累积偏移量,并相应地设置顶部,左侧等。
PS:对于矩形使用跨度有点奇怪,因为它们是内嵌元素,而不是块元素。为什么不使用div呢?不应该改变结果,但div似乎是你正确使用的东西。