如何将绝对定位的溢出元素相对于相对定位的父元素固定位置?

4

我制作了一个自定义的下拉框,它被包裹在一个可滚动的 div 中。

我的问题是:下拉列表占据了包装器的空间。也就是说,它看起来像这样:

enter image description here

但是,我希望它相对于父包装器固定,像这样:

enter image description here

我可以通过从 .select_box 中删除 position:relative; 来实现这个结果。但是,它破坏了输入框和列表之间的间距(我不想要),如下图所示:

enter image description here

这是我的代码--

HTML:

<div id="wrapper">
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
    <br/><br/>
    <div class="select_box">
        <input type="text" onMouseDown="show_list(this)" onblur="hide_list(this)" readonly/>
        <ul style="width:200px;">
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
            <li>7</li>
            <li>8</li>
            <li>9</li>
            <li>10</li>
            <li>11</li>
            <li>12</li>
            <li>13</li>
        </ul>
    </div><br/><br/>
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
</div>

jQuery:

function show_list(element) {
    $(element).next().toggle();
    if ($(element).next().css('display') == 'none') $(element).css('background', 'url(select_box_arrow.png) no-repeat 95%');
    else $(element).css('background', 'url(select_box_arrow_inverted.png) no-repeat 95%');
}

function hide_list(element) {
    $(element).next().hide();
    $(element).css('background', 'url(select_box_arrow.png) no-repeat 95%');
}
$(document).ready(function () {
    $("div[class='select_box'] input:text").css("padding", "0 10px");
    $("div[class='select_box'] li").mousedown(function () {
        $(this).parent().prev().attr('value', $(this).text());
    });
});

CSS:

#wrapper {
    height:200px;
    width:400px;
    border:Solid 1px;
    overflow:auto;
}
/* CSS for customized select box */
 .select_box {
    display:inline-block;
    //position:relative;
}
.select_box input[type="text"] {
    width:200px;
    height:25px;
    border: 1px solid #cccccc;
    border-radius:2px;
    background:url(select_box_arrow.png) no-repeat 95%;
    font-size:15px;
    outline:none;
    cursor:pointer;
    vertical-align:middle;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
.select_box input[type="text"]:focus {
    border-color:#FFC59D;
    box-shadow:0 0 10px #FFC59D;
}
.select_box ul {
    list-style:none;
    padding:0;
    margin:0;
    margin-top:2px;
    font-family:Tahoma, Geneva, sans-serif;
    line-height:25px;
    font-size:15px;
    font-weight:normal;
    border:solid 1px #FFC59D;
    width:220px;
    max-height:250px;
    overflow:auto;
    display:none;
    position:absolute;
    background:#fff;
    color:#000000;
    scrollbar-arrow-color: #ff6600;
    scrollbar-track-color: #FFC59D;
    scrollbar-face-color: #ff6600;
    scrollbar-shadow-color: #ff6600;
}
.select_box li {
    padding-left:10px;
}
.select_box li:hover {
    background:#FF9D5B;
    color:#fff;
    cursor:default;
}
.select_box ::-webkit-scrollbar {
    width: 12px;
    border:solid 1px #FFC59D;
    border-left-width:2px;
}
.select_box ::-webkit-scrollbar-thumb {
    -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
    background:#FFC59D;
}
.select_box ::-webkit-scrollbar-thumb:window-inactive {
    -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
    background:#FFC59D;
}

运行的示例。

是否有一个纯CSS的解决方案?我也接受使用jQuery的解决方案。


将列表放在body中,并使用点击事件来定位它。将其附加到body中是避免溢出问题的最常见方法,就像这样。 - charlietfl
@charlietfl 可以尝试这样做。不过,这似乎是一个奇怪的解决方法。难道没有通过简单的css解决这个问题的办法吗? - Nikunj Madhogaria
1
不,如果它是一个具有隐藏溢出的元素的后代,则无法告诉浏览器让其中一些内容流出,但其他内容不流出。 - charlietfl
@charlietfl 你不觉得我需要在scroll事件而非click事件中重新定位列表吗? - Nikunj Madhogaria
可能是,我以为它就像一个下拉菜单,直到用户单击使用它才会显示。 - charlietfl
确实是一个下拉菜单(点击后出现)。但是,由于父级div(包装器)是可滚动的,我认为我需要在滚动包装器时重新定位它。从fiddle中删除.select_box中的position:relative;,然后尝试滚动容器(在点击文本框后)。 - Nikunj Madhogaria
2个回答

1
像这样吗?

scroll demo

你需要将下拉菜单移出#wrapper,然后使用JavaScript相对于input[type=text]计算其位置,并使用position: absolute属性。
工作演示:http://jsfiddle.net/4rv4s3ce/10/ 希望这可以帮到你。

感谢您的帮助! :) - Nikunj Madhogaria

1

最简单的实现方式是尽可能使用本地 select 框。然而,如果必须使用自定义列表作为输入框,可以尝试以下示例。

Fiddle(您将看到我在文本输入框旁边添加了本地选择框,以展示其默认操作方式)

HTML

<ul class="list-box" style="width:200px;">
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
            <li>7</li>
            <li>8</li>
            <li>9</li>
            <li>10</li>
            <li>11</li>
            <li>12</li>
            <li>13</li>
        </ul>
<div id="wrapper">
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
    <br/><br/>
    <select><option>test</option><option>test</option><option>test</option><option>test</option><option>test</option><option>test</option><option>test</option><option>test</option><option>test</option><option>test</option><option>test</option></select>
    <div class="select_box">
        <input class="list_input" type="text" onMouseDown="show_list(this)" onblur="hide_list(this)" readonly/>
    </div><br/><br/>
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
</div>

JavaScript(JavaScript)
function show_list(element) {
    var pos = $(element).offset();
    var input_height = $(element).height();
    $('.list-box').css('top', pos.top + input_height);
    $('.list-box').css('left', pos.left);
    $('.list-box').toggle();
    if ($('.list-box').css('display') == 'none') $(element).css('background', 'url(select_box_arrow.png) no-repeat 95%');
    else $(element).css('background', 'url(select_box_arrow_inverted.png) no-repeat 95%');
}

function hide_list(element) {
    $(element).next().hide();
    $(element).css('background', 'url(select_box_arrow.png) no-repeat 95%');
}
$(document).ready(function () {
    $("div[class='select_box'] input:text").css("padding", "0 10px");
    $("ul.list-box li").mousedown(function () {
        $('.list_input').attr('value', $(this).text());
        $('.list-box').toggle();
    });

    $('#wrapper').on('scroll', function(){
        var pos = $('.list_input').offset();
        var input_height = $('.list_input').height();
        $('.list-box').css('top', pos.top + input_height);
        $('.list-box').css('left', pos.left);
    });
});

CSS
#wrapper {
    height:200px;
    width:400px;
    border:Solid 1px;
    overflow:auto;
}
/* CSS for customized select box */
 .select_box {
    display:inline-block;
    position:relative;
}
.select_box input[type="text"] {
    width:200px;
    height:25px;
    border: 1px solid #cccccc;
    border-radius:2px;
    background:url(select_box_arrow.png) no-repeat 95%;
    font-size:15px;
    outline:none;
    cursor:pointer;
    vertical-align:middle;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
.select_box input[type="text"]:focus {
    border-color:#FFC59D;
    box-shadow:0 0 10px #FFC59D;
}
.select_box ul {
    list-style:none;
    padding:0;
    margin:0;
    margin-top:2px;
    font-family:Tahoma, Geneva, sans-serif;
    line-height:25px;
    font-size:15px;
    font-weight:normal;
    border:solid 1px #FFC59D;
    width:220px;
    max-height:250px;
    overflow:auto;
    display:none;
    position:absolute;
    background:#fff;
    color:#000000;
    scrollbar-arrow-color: #ff6600;
    scrollbar-track-color: #FFC59D;
    scrollbar-face-color: #ff6600;
    scrollbar-shadow-color: #ff6600;
}
.select_box li {
    padding-left:10px;
}
.select_box li:hover {
    background:#FF9D5B;
    color:#fff;
    cursor:default;
}
.select_box ::-webkit-scrollbar {
    width: 12px;
    border:solid 1px #FFC59D;
    border-left-width:2px;
}
.select_box ::-webkit-scrollbar-thumb {
    -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
    background:#FFC59D;
}
.select_box ::-webkit-scrollbar-thumb:window-inactive {
    -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
    background:#FFC59D;
}

对所做更改的快速说明:

正如@charlietfl所提到的,列表需要附加到body而不是滚动元素内部。从那里开始,我为输入类型文本和列表添加了类,因为父级jquery选择器将不再起作用,因为它们不相邻或在同一父容器中。当单击输入或滚动#wrapper div时,我将列表放置在点击的文本框正下方。


谢谢帮助! :) - Nikunj Madhogaria

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