IE8 中的绝对定位中断

发布于 2024-10-25 12:50:04 字数 5587 浏览 1 评论 0原文

我正在开发一个 ASP.NET 控件,我需要能够将其放入其他应用程序中。该控件基本上是一个自定义下拉列表,当单击另一个元素时,会显示或隐藏 div。

我遇到的问题是试图让动态 div 在被单击的元素下方对齐。我编写了一个 javascript 函数,理论上,它应该允许我指定两个元素和所需的对齐方式,然后将第二个元素移动到相对于第一个元素的正确位置。

我有三个测试用例,与我当前期望使用此控件的位置相关,我当前的标记和 javascript 在 IE7 的所有三种情况下都有效,但在 FF3.5 和 IE8 标准模式下的其中一种情况下失败。我已经研究这个问题有一段时间了,但还没有想出一个答案来解决问题而不破坏其他问题。 (请注意,我的 90+% 的用户使用 IE7,但向 IE8 的迁移速度很慢)

除了向页面添加兼容模式指令之外,我正在寻找任何建议,这确实修复了 IE8 中的问题,但如果有的话,我更喜欢替代方案这是可能的,因为我可能并不总是能够控制它的使用位置。这是一个 HTML 文档,其中说明了相关标记和 javascript 以及测试用例。情况三是有问题的一种,div 不是在输入元素下整齐对齐,而是垂直重叠,并向右侧偏移了等于选择元素宽度的距离。

(请注意,真实页面使用改编自 Eric Meyer 发布的重置样式表,包含/省略此样式表对这些测试用例没有相关影响。)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title></title>
</head>
<body>
<script type="text/javascript">
    var VAlign = { "top": -1, "center": 0, "bottom": 1 };
    var HAlign = { "left": -1, "center": 0, "right": 1 };
    function AlignElements(element1, vAlign1, hAlign1, element2, vAlign2, hAlign2) {
        var List1 = BuildOffsetList(element1);
        var List2 = BuildOffsetList(element2);
        var Index1 = List1.length - 1;
        var Index2 = List2.length - 1;

        while (Index1 >= 0 && Index2 >= 0 && List1[Index1] == List2[Index2]) {
            Index1--;
            Index2--;
        }

        element2.style.top = "";
        element2.style.left = "";

        var OT1 = 0;
        var OL1 = 0;
        var OT2 = 0;
        var OL2 = 0;

        while (Index1 >= 0) {
            OT1 += List1[Index1].offsetTop;
            OL1 += List1[Index1].offsetLeft;
            Index1--;
        }

        while (Index2 >= 0) {
            OT2 += List2[Index2].offsetTop;
            OL2 += List2[Index2].offsetLeft;
            Index2--;
        }

        var top = (OT1 - OT2);
        if (vAlign1 == VAlign.bottom) {
            top += element1.offsetHeight;
        } else if (vAlign1 == VAlign.center) {
            top += (element1.offsetHeight / 2);
        }
        if (vAlign2 == VAlign.bottom) {
            top -= element2.offsetHeight;
        } else if (vAlign2 == VAlign.center) {
            top -= (element2.offsetHeight / 2);
        }

        var left = (OL1 - OL2);
        if (hAlign1 == HAlign.right) {
            left += element1.offsetWidth;
        } else if (hAlign1 == HAlign.center) {
            left += (element1.offsetWidth / 2);
        }
        if (hAlign2 == HAlign.right) {
            left -= element2.offsetWidth;
        } else if (hAlign2 == HAlign.center) {
            left -= (element2.offsetWidth / 2);
        }

        element2.style.top = top + "px";
        element2.style.left = left + "px";
    }

    function BuildOffsetList(elelment) {
        var I = 0;
        var List = new Array();
        var Element = elelment;
        while (Element) {
            List[I] = Element;
            Element = Element.offsetParent;
            I++;
        }
        return List;
    }
</script>
Case 1
<div>
    <div id="control1" style=" display:inline; position:relative;">
        <div id="control1_div1" style="background-color:Blue; height:75px; width:150px; position:absolute;"></div>
        <input id="control1_txt1" type="text" style="width:150px;" />
        <script type="text/javascript">
            AlignElements(document.getElementById("control1_txt1"), VAlign.bottom, HAlign.left, document.getElementById("control1_div1"), VAlign.top, HAlign.left);
        </script>
    </div>
</div>
<div style="height:100px;"></div>
Case 2
<div>
    <div id="Nav" style="float:left; width:200px; height:150px; background-color:Aqua;"></div>
    <div id="Content" style="margin-left:200px; height:150px; background-color:#ddd;">
        <div style="margin-left:100px;">
            <h5 style="float:left; margin-left:-100px; width:90px; margin-right:10px; text-align:right; font-weight:.9em;">Label</h5>
            <div id="control2" style=" display:inline; position:relative;">
                <div id="control2_div1" style="background-color:Blue; height:75px; width:150px; position:absolute;"></div>
                <input id="control2_txt1" type="text" style="width:150px;" />
                <script type="text/javascript">
                    AlignElements(document.getElementById("control2_txt1"), VAlign.bottom, HAlign.left, document.getElementById("control2_div1"), VAlign.top, HAlign.left);
                </script>
            </div>
        </div>
    </div>
</div>
<div style="height:100px;"></div>
Case 3
<div>
    <select><option>something</option></select>
    <br />
    <select><option>something else</option></select>
    <div id="control3" style=" display:inline; position:relative;">
        <div id="control3_div1" style="background-color:Blue; height:75px; width:150px; position:absolute;"></div>
        <input id="control3_txt1" type="text" style="width:150px;" />
        <script type="text/javascript">
            AlignElements(document.getElementById("control3_txt1"), VAlign.bottom, HAlign.left, document.getElementById("control3_div1"), VAlign.top, HAlign.left);
        </script>
    </div>
</div>
</body>
</html>

I am working on developing an asp.net control that I need to be able to drop into other applications. The control is basically a custom dropdown in which a div gets displayed or hidden when another element is clicked.

The problem I am having is in trying to get the dynamic div to align below the element that gets clicked. I wrote a javascript function which should, in theory, allow me to specify two elements and the desired alignment and then move the second element to the correct position in relation to the first element.

I have three test cases which relate to places where I currently expect this control will be used, my current markup and javascript work in all three cases for IE7 but fails for one of the cases in FF3.5 and IE8-standards mode. I have been playing with this for a while and have yet to come up with an answer that fixes the problem case without breaking one of the others. (Note that 90+% of my users are on IE7 with a slow migration towards IE8)

I am looking for any suggestions other than adding a compatibility mode directive to the page, that does fix things in IE8 but I would prefer an alternative if one is possible since I may not always have control over where this is used. Here is an HTML doc which illustrates the relevant markup and javascript along with the test cases. Case three is the one which has problems, instead of aligning neatly under the input element the div is overlapping vertically and offset to the right by a distance equivalent to the width of the select element.

(Note that the real pages utilize a reset style sheet adapted from the one published by Eric Meyer, including/omitting this style sheet has no relevant effect on these test cases.)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title></title>
</head>
<body>
<script type="text/javascript">
    var VAlign = { "top": -1, "center": 0, "bottom": 1 };
    var HAlign = { "left": -1, "center": 0, "right": 1 };
    function AlignElements(element1, vAlign1, hAlign1, element2, vAlign2, hAlign2) {
        var List1 = BuildOffsetList(element1);
        var List2 = BuildOffsetList(element2);
        var Index1 = List1.length - 1;
        var Index2 = List2.length - 1;

        while (Index1 >= 0 && Index2 >= 0 && List1[Index1] == List2[Index2]) {
            Index1--;
            Index2--;
        }

        element2.style.top = "";
        element2.style.left = "";

        var OT1 = 0;
        var OL1 = 0;
        var OT2 = 0;
        var OL2 = 0;

        while (Index1 >= 0) {
            OT1 += List1[Index1].offsetTop;
            OL1 += List1[Index1].offsetLeft;
            Index1--;
        }

        while (Index2 >= 0) {
            OT2 += List2[Index2].offsetTop;
            OL2 += List2[Index2].offsetLeft;
            Index2--;
        }

        var top = (OT1 - OT2);
        if (vAlign1 == VAlign.bottom) {
            top += element1.offsetHeight;
        } else if (vAlign1 == VAlign.center) {
            top += (element1.offsetHeight / 2);
        }
        if (vAlign2 == VAlign.bottom) {
            top -= element2.offsetHeight;
        } else if (vAlign2 == VAlign.center) {
            top -= (element2.offsetHeight / 2);
        }

        var left = (OL1 - OL2);
        if (hAlign1 == HAlign.right) {
            left += element1.offsetWidth;
        } else if (hAlign1 == HAlign.center) {
            left += (element1.offsetWidth / 2);
        }
        if (hAlign2 == HAlign.right) {
            left -= element2.offsetWidth;
        } else if (hAlign2 == HAlign.center) {
            left -= (element2.offsetWidth / 2);
        }

        element2.style.top = top + "px";
        element2.style.left = left + "px";
    }

    function BuildOffsetList(elelment) {
        var I = 0;
        var List = new Array();
        var Element = elelment;
        while (Element) {
            List[I] = Element;
            Element = Element.offsetParent;
            I++;
        }
        return List;
    }
</script>
Case 1
<div>
    <div id="control1" style=" display:inline; position:relative;">
        <div id="control1_div1" style="background-color:Blue; height:75px; width:150px; position:absolute;"></div>
        <input id="control1_txt1" type="text" style="width:150px;" />
        <script type="text/javascript">
            AlignElements(document.getElementById("control1_txt1"), VAlign.bottom, HAlign.left, document.getElementById("control1_div1"), VAlign.top, HAlign.left);
        </script>
    </div>
</div>
<div style="height:100px;"></div>
Case 2
<div>
    <div id="Nav" style="float:left; width:200px; height:150px; background-color:Aqua;"></div>
    <div id="Content" style="margin-left:200px; height:150px; background-color:#ddd;">
        <div style="margin-left:100px;">
            <h5 style="float:left; margin-left:-100px; width:90px; margin-right:10px; text-align:right; font-weight:.9em;">Label</h5>
            <div id="control2" style=" display:inline; position:relative;">
                <div id="control2_div1" style="background-color:Blue; height:75px; width:150px; position:absolute;"></div>
                <input id="control2_txt1" type="text" style="width:150px;" />
                <script type="text/javascript">
                    AlignElements(document.getElementById("control2_txt1"), VAlign.bottom, HAlign.left, document.getElementById("control2_div1"), VAlign.top, HAlign.left);
                </script>
            </div>
        </div>
    </div>
</div>
<div style="height:100px;"></div>
Case 3
<div>
    <select><option>something</option></select>
    <br />
    <select><option>something else</option></select>
    <div id="control3" style=" display:inline; position:relative;">
        <div id="control3_div1" style="background-color:Blue; height:75px; width:150px; position:absolute;"></div>
        <input id="control3_txt1" type="text" style="width:150px;" />
        <script type="text/javascript">
            AlignElements(document.getElementById("control3_txt1"), VAlign.bottom, HAlign.left, document.getElementById("control3_div1"), VAlign.top, HAlign.left);
        </script>
    </div>
</div>
</body>
</html>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不奢求什么 2024-11-01 12:50:05

第三种情况是由于父 divinline 显示而导致的 - 据我所知,它导致相对位置不起作用。

要测试这种情况,请使用 float 代替,这里是工作示例:
http://jsfiddle.net/yahavbr/estYF/1/

The third case is breaking apart because of the inline display of the parent div - it cause the relative position to have no effect as far as I know.

To test such case use float instead, here is working example:
http://jsfiddle.net/yahavbr/estYF/1/

七颜 2024-11-01 12:50:05

感谢影子向导让我思考正确的方向。事实证明,问题是当我清除顶部和左侧属性时,我的绝对定位元素不会移动到 0,0 点。如果我在计算偏移差之前更改代码以显式将它们置于 0,0 处,那么一切都会正常工作。

    element2.style.top = "";
    element2.style.left = "";

变成

    element2.style.top = "0px";
    element2.style.left = "0px";

Thanks to Shadow Wizard for getting me thinking in the right direction. Turns out that the issue is that my absolutely positioned elements do not move to their 0,0 point when I clear the top and left properties. If I change the code to explicitly put them at 0,0 before calculating the offset difference then everything works beautifully.

    element2.style.top = "";
    element2.style.left = "";

becomes

    element2.style.top = "0px";
    element2.style.left = "0px";
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文