【问题标题】:Expanding Vertical Space Issue with Floated Elements使用浮动元素扩展垂直空间问题
【发布时间】:2023-04-09 08:31:01
【问题描述】:

我有一个布局,需要将项目列表组织成两个垂直列。这些项目位于<div>s 的单个列表中,标记也被重新用于移动设备,所以我不想修改结构。

我在这里遇到的问题是每个项目都有一个用户可以切换的扩展内容区域,当这个内容被扩展时,该列的垂直空间需要向下扩展而另一列保持固定。

现在我有一个浮动项目的基本解决方案,但是当我扩展内容区域时,垂直空间会在 两个 列中扩展,而不仅仅是一个。

Here's a link 是我现在拥有的功能示例,下面是所需行为的屏幕截图。

是否可以对其进行样式设置以支持所需的行为?还是我必须修改项目的结构才能使其正常工作?提前感谢您的帮助!

【问题讨论】:

  • 老实说,如果不更改标记或一些疯狂的 jQuery,我看不出这怎么可能......

标签: html css css-float


【解决方案1】:

你的前提是有缺陷的。文档结构从左到右、从上到下流动。您需要对结构进行一些更改...最简单的方法是为左列和右列添加两个容器。否则,您会遇到一些棘手的绝对定位标记和一些时髦的 jquery,我只能建议为每个面板添加一些唯一 ID。

我个人会根据您的示例添加诸如 panel1panel4 之类的 ID,然后使用此 javascript(或类似内容)作为起点:

for(var i=1; i<=4; i++) {
        $('#panel'+i).css('left', function(index) {
           if(i%2 == 0) return "120px";
           else return "0px"; 
        });
}

$('.more').click(function(e) {
    e.preventDefault();
    $(this).parent().children('p').toggle();
    var id = $(this).parent().attr("id");
    switch( id ) {
        case 'panel1':
          console.log("panel1 found");
          $('#panel3').css('top', function(index) {
            var buffer = $('#'+id).height() + 20 + "px";
            return buffer;
          });
          break;
        case 'panel2':
          $('#panel4').css('top', function(index) {
            var buffer = $('#'+id).height() + 20 + "px";
            return buffer;
          });
          break;
        default: break;
    }
});

在这些面板的 css 中使用默认值:

#panel1 { top:0px; }
#panel2 { top:0px; }
#panel3 { top:56px; }
#panel4 { top:56px; }

您对 html 的调整越少,您在 javascript 中创建的工作就越多。

编辑

假设每行有两个元素,建议删除需要更改 HTML 的替代 Javascript。因为我们知道问题所在的行...

var ct = 1
$('#container > div').each(function(index, domEle) {
  $(domEle).attr('id', 'panel'+ct);
  $('#panel'+ct).css({
     'position': 'absolute',
     'left' : function(index, value) {
        if(ct%2 == 0) return "120px";
        else return "0px"; 
     },
     'top' : function(index, value) {
        return (56 * Math.floor(ct/3)) + "px";
     }
  });
  ct++;
});

$('.more').click(function(e) {
    e.preventDefault();
    $(this).parent().children('p').toggle();
    var id = $(this).parent().attr("id");

    switch( id ) {
        case 'panel1':
          $('#panel3').css('top', function(index) {
            var buffer = $('#'+id).height() + 20 + "px";
            return buffer;
          });
          break;
        case 'panel2':
          $('#panel4').css('top', function(index) {
            var buffer = $('#'+id).height() + 20 + "px";
            return buffer;
          });
          break;
        default: break;
    }
});

现在不需要对 HTML 进行任何更改,但您需要重做 click 函数来处理点击后元素的重新定位。我会让生活变得轻松,并在展开新框之前隐藏所有 .more 项目,因为这意味着必须计算上面所有元素的高度,但你想做多少工作是你的事。

【讨论】:

  • 感谢您的回复。这种解决方案和@Paul Podlipensky 推荐的解决方案是我想到并希望避免的两种解决方案——很明显,我可能不得不接受其中一种,可能是基于标记的一种。再次感谢。
  • 可以用纯javascript来完成。这不会很有趣。您将必须计算所有子元素,并决定它们是否应该在第 1 列或第 2 列中。这并不吸引人,但它是一种选择。
  • 是的,我最终在标记中选择了浮动“列”divs 的路线。然后,我能够相对容易地渲染第 1 列中的偶数面板和第 2 列中的奇数面板。再次感谢您的努力。
【解决方案2】:

这是 四个 面板的PURE CSS SOLUTION(我不知道您是否打算拥有更多,而我没有六个 [2 宽 3 高]工作还 - 并怀疑这是不可能的)。它适用于 FF 和 IE8/9。见小提琴:http://jsfiddle.net/bEgwB/203/

然而,IE8 遇到了一个重绘错误,导致面板 3 无法移动,因此需要额外的 javascript 帮助(在上面的小提琴中添加),并且 IE7 需要一些边距调整才能正确定位面板 4(但是即使没有额外的 javascript 帮助,也没有重绘问题)。 更新 (11-18-11): 这是 IE7 边距调整的小提琴:http://jsfiddle.net/bEgwB/286/

编辑:我之前的 CSS 版本有 display 不必要的调用。

HTML

<div id="container">
    <div class="panel one">
        Panel 1<br />
        <a class="more" href="#">more</a>
        <p>More Info 1 with some additional content</p>
    </div>
    <div class="panel two">
        Panel 2<br />
        <a class="more" href="#">more</a>
        <p>More Info 2 with some additional content</p>
    </div>
    <div class="panel three">
        Panel 3<br />
        <a class="more" href="#">more</a>
        <p>More Info 3 with some additional content</p>
    </div>
    <div class="panel four">
        Panel 4<br />
        <a class="more" href="#">more</a>
        <p>More Info 4 with some additional content</p>
    </div>
</div>

CSS

a {color:yellow;}
#container {width:0 ; padding: 0 130px;}
.panel {
    background-color:green;
    padding:5px;
    color:#fff;
    width:100px;
}
.panel p {display:none;}

.panel.one {
    float: left;
    margin:10px 0 10px -120px;
}
.panel.two {
    float: right;
    margin: 10px -120px 20px 0;
}
.panel.three {
    float: left;
    clear: left;
    margin:10px 10px 10px -120px;
}
.panel.four {
    clear: right;
    margin: 10px;
}

JAVASCRIPT

$('.more').click(function(e) {
    e.preventDefault();
    $(this).parent().children('p').toggle();
    /* the following fix IE8 */
    $(this).parent().parent().hide();
    $(this).parent().parent().show();
});

【讨论】:

  • 谢谢斯科特。我所拥有的真实场景实际上需要波动数量的项目(从 3 到 12 不等),但这很有帮助。 +1。
  • 是的,我正在尝试解决 6+ 元素的问题。问题是,一旦元素 4 被赋予 float: right(这样潜在的元素 5 将位于 4 的扩展旁边),那么它的行为与您最初遇到的行为相同。
【解决方案3】:

您需要再添加两个 div - 左列和右列,并在这两个 div 之间拆分您的项目。这是使它们独立的方法,这里是jsfiddle

HTML

<div id="container">
    <div class="left">
        <div class="panel">
            Panel 1<br />
            <a class="more" href="#">more</a>
            <p>More Info 1 with some additional content</p>
        </div>
        <div class="panel alt">
            Panel 2<br />
            <a class="more" href="#">more</a>
            <p>More Info 2 with some additional content</p>
        </div>
    </div>
    <div class="right">
        <div class="panel">
            Panel 3<br />
            <a class="more" href="#">more</a>
            <p>More Info 3 with some additional content</p>
        </div>
        <div class="panel alt">
            Panel 4<br />
            <a class="more" href="#">more</a>
            <p>More Info 4 with some additional content</p>
        </div>
    </div>
</div>

CSS

a {color:yellow;}
#container {width:300px; position:relative;}
.panel {background-color:green;padding:5px;color:#fff;width:100px;margin:10px;}
.panel p {display:none;}
.left {
    width: 50%;
    float: left;
}
.right {
    width: 50%;
    float: right;
}

【讨论】:

  • 感谢您的回复。是的,这是我希望避免的。我正在使用 ASP.NET 转发器来呈现这些,我需要找到一些方法来交替将项目放置在“左”和“右”&lt;div&gt;s 中。我不能只把前半部分放在右边,剩下的放在左边——它们需要从左到右排列。
  • 您可以根据需要渲染它们,然后在客户端使用javascript重新排列成列(如果您找不到在服务器端拆分它们的方法)。
【解决方案4】:

也许你可以这样做column-count 属性是这样的:

a {color:yellow;}
#container {
    width:300px;
    -moz-column-count: 2;
        -moz-column-gap: 50%;
        -webkit-column-count: 2;
        -webkit-column-gap: 50%;
        column-count: 2;
        column-gap: 50%;

}
.panel p {display:none;}
.panel {background-color:green;padding:5px;color:#fff;width:100px;margin:10px;}
.alt{
    margin-bottom:90px;
}

检查这个小提琴http://jsfiddle.net/bEgwB/87/

更新

检查一下:

http://jsfiddle.net/bEgwB/276/

【讨论】:

  • 看起来还不错,虽然它在 chrome 中似乎有一些奇怪的显示怪癖(不确定是 -webkit 还是什么)。它仍然存在必须将面板重新排序为 1,3,2,4 而不是 1,2,3,4 的问题。我想使用需要按顺序排列的单列布局(用于移动设备)来双重目的。
  • 当我展开面板 2 和 4 时,2 的一部分低于 3。因此,此解决方案存在一个问题,即 alt 类上的 margin-bottom 相当随意,需要考虑2 和 4 中的可变高度。如果有办法强制面板 2 不跳转到第一列,那么这可能是一个好的解决方案(ataddeini 指出的 html 重新排序除外)。
  • 更新的 jsfiddle 是我见过的最接近的,而且 CSS 也最少。 IE 有一些怪癖(当然),但不像我期望的那样——IE7 工作正常,IE8 工作正常,除了面板 1(它向下推左列)和所有版本中,IE9 完全落在它的face——甚至从一开始就不能正确渲染。 Chrome 和 Firefox 都可以完美运行。是的,我会说这是最接近的。 +1。
  • 仍然不适用于 6+ 面板(就像我的面板一样)。见jsfiddle.net/bEgwB/277 虽然代码比我的更干净更苗条,但我的代码在 IE 8 和 9 中适用于四个面板。
  • @Scott:是的,好点子。没有完全意识到这些影响。
【解决方案5】:

有一个样式解决方案。要将两列绑定在一起,它们需要额外的绑定级别,您可以通过将样式属性添加到“容器”、“显示:表”和带有“显示:表单元”的面板来实现。

这将使高度保持同步。 “容器”和“面板”类都必须有一个声明的宽度,否则它们真的会弄乱布局。 IE 对这些属性的支持很弱,因此这可能是解决方案的问题。

【讨论】:

  • 我实际上不希望高度同步,我希望它们被抵消。标准浮动解决方案也使它们保持同步,但这不是所需的行为。不过感谢您的回答。
【解决方案6】:

如果我理解正确的话,你想要的是这样的 http://jsfiddle.net/bEgwB/275/

您需要同时使用 css 属性 display:inline-blockfloat:left 来实现类似 jpg 的效果。如果我的标记正确并且看起来符合预期,我可以用 javascript 帮助你,如果现在不行的话

祝你好运。

【讨论】:

  • 感谢您的回答。这似乎有时会独立地向下推面板,但是当面板 1 展开时,面板 3 会跳到第二列——这需要留在第 1 列(也许clear:left 会处理这个问题?)看起来当面板 2 展开时,第 1 列也会展开。这些需要独立扩展。