【问题标题】:Div that takes remaining horizontal space and stacked vertically on small screen占据剩余水平空间并在小屏幕上垂直堆叠的 Div
【发布时间】:2013-07-03 01:24:04
【问题描述】:

我需要水平并排堆叠两个div 元素,其中右侧的元素应始终根据其内容自动调整其大小(达到最大给定宽度),而左侧的元素应仅使用空间离开了。

类似这样的:

到目前为止没有问题。我设法通过将右侧的div 浮动到右侧并将左侧的溢出设置为隐藏来做到这一点:

HTML:

<div class="frame">
    <div class="right">
        I adjust my with to my content but still need to know my boundaries if I'm floated right (max-width)
    </div>

    <div class="left">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </div>
</div>

CSS:

.frame {
    background-color: lightgreen;
    width: 80%;
    padding: 12px;
    overflow: hidden;
}

.left {
    overflow: hidden;

    background-color: #709670;
    border: 1px solid black;
}

.right {
    float: right;
    max-width: 200px;

    background-color: #127212;
    color: white;
    border: 1px solid black;
}

挑战是当页面显示在小屏幕(或小浏览器窗口,...)上时,我希望两个 divs 垂直堆叠,如下所示:

基本上我认为这可以通过一个简单的媒体查询来完成:

@media screen and (max-width: 700px) {
    .right {
        float: none;
        max-width: none;
    }
}

唯一的问题是右div(根据其内容调整大小的那个)需要在标记中的左一个之前创建,以使浮动的东西工作。结果,它出现在“小”布局中的左侧上方:

这是一个工作示例(只需使用中间缩放器在“小”和“大”布局之间切换):Example on JSFiddle

我已经尝试使用 display: tabletable-cell 而不是浮动来完成布局,但是这样我无法使右列与其内容一样大,并且仍然有一个有效的最大宽度设置。

【问题讨论】:

    标签: html css css-float


    【解决方案1】:

    正如in this stackoverflow post 所说,如果您不想求助于 jQuery,Flexbox 可以为您提供帮助,因为您只需要 to support 一个现代浏览器:Mobile Safari(编辑我也发现 IE 中 left 框的高度在我的 Fiddle 中不起作用,我不知道为什么;它应该)。

    对你来说是: This awesome fiddle!

    编辑因为你想要正确的div 来适应它的内容,你想要this example 来代替

    CSS:

    .frame {
        position:relative;
        background-color: lightgreen;
        width: 80%;
        padding: 12px;
        overflow:hidden;
        flex-flow:row wrap;
    
        -webkit-justify-content: flex;
        -moz-justify-content: -moz-flex;
        justify-content: flex;
    
        display: -webkit-box; /* Safari */ 
        display: -moz-box; /* Firefox 21- */
        display: -ms-flexbox; /* IE 10+ */
        display: -webkit-flex; /* Chrome */
        display: flex; /* Standard (Firefox 22+) */
    
        -webkit-box-orient: horizontal;
        -moz-box-orient: horizontal;
        -webkit-box-direction: normal;
        -moz-box-direction: normal;
        -ms-flex-direction: row;
        -webkit-flex-direction: row;
        flex-direction: row;
    }
    
    .left {    
        -ms-flex-order: 1;     
        -webkit-order: 1;
        order:1;
    
        -webkit-box-flex: 2;      /* OLD - iOS 6-, Safari 3.1-6 */
        -moz-box-flex: 2;         /* OLD - Firefox 19- */
        -webkit-flex: 2;          /* Chrome */
        -ms-flex: 2;              /* IE 10 */
        flex: 2;                  /* NEW, Spec - Opera 12.1, Firefox 20+ */
    
        background-color: #709670;
        border: 1px solid black;
        width: auto;
    }
    
    .right {    
        -ms-flex-order: 2;
        -webkit-order: 2;
        order:2;
    
        -webkit-box-flex: 1;      /* OLD - iOS 6-, Safari 3.1-6 */
        -moz-box-flex: 1;         /* OLD - Firefox 19- */
        -webkit-flex: 1;          /* Chrome */
        -ms-flex: 1;              /* IE 10 */
        flex: 1;                  /* NEW, Spec - Opera 12.1, Firefox 20+ */
    
        background-color: #127212;
        color: white;
        border: 1px solid black;
        width: auto;
    
        -webkit-box-ordinal-group: 2;   /* OLD - iOS 6-, Safari 3.1-6 */
        -moz-box-ordinal-group: 2;      /* OLD - Firefox 19- */
        -ms-flex-order: 2;              /* TWEENER - IE 10 */
        -webkit-order: 2;               /* NEW - Chrome */
        order: 2;                       /* NEW, Spec - Opera 12.1, Firefox 20+ */
    }
    
    @media screen and (max-width: 700px) {
        .frame {
            -webkit-box-orient: vertical;
            -moz-box-orient: vertical;
            -webkit-box-direction: normal;
            -moz-box-direction: normal;
            box-orient: vertical;
            -ms-flex-direction: column;
            -webkit-flex-direction: column;
            flex-direction: column;
        }
    }
    

    我对我的结果非常满意,我觉得你会的!我相信它几乎完全支持(Mobile Safari 不支持它)!

    【讨论】:

    • 现已更新至功能齐全!您可能只想添加 .left.right 类的最大高度,但这取决于您并且易于添加
    • 首先感谢您的意见。以前没有听说过 flexbox,很高兴知道它!不幸的是,在您的示例中,正确的 div 并没有真正适应它的内容,而是固定大小为 200。如果它的内容较少,它会自动变小。请参阅您的小提琴的此更新以了解我的意思:jsfiddle.net/3vgng/10
    • 编辑:我之前的评论最后一句应该是:“如果内容较少,它应该自动变小。”
    • 简单,here 是。只是更改了几个值
    • @Zeaklous 完美。你的最后一个例子似乎正是我想要的。我必须在我的“现实生活”场景中检查它并接受你的回答!非常感谢
    【解决方案2】:

    基于 CSS/jQuery 的方法

    假设 HTML 和内容可以如下调整,.left 元素出现在 .right 元素之前:

    <div class="frame">
        <div class="left">Lorem ipsum dolor sit amet, c...</div>
        <div class="right">
            <div class="color-wrap">I adjust my width ...</div>
        </div>
    </div>
    

    您可以将以下 CSS 用于宽屏:

    .frame {
        background-color: lightgreen;
        width: 80%;
        padding: 12px;
        overflow: auto;
    }
    .left {
        background-color: #709670;
        border: 1px solid black;
        display: table-cell;
    }
    .left .color-wrap {
    }
    .right {
        display: table-cell;
        width: 200px;
        vertical-align: top;
    }
    .right .color-wrap {
        background-color: #127212;
        color: white;
        border: 1px solid black;
        display: inline-block;
    }
    

    对于较小的屏幕:

    @media screen and (max-width: 700px) {
        .left {
            display: block;
        }
        .right {
            display: block;
            width: auto;
        }
        .right .color-wrap {
            display: block;
            width: auto;
            color: yellow;
        }
    }
    

    对于大屏幕,您可以使用display: table-cell 并为.right 元素设置宽度或使用最大宽度和最小宽度的组合,具体取决于您要如何处理一行文字。

    如果您需要背景颜色以仅绘制文本区域,则使用包装元素(例如 .color-wrap)并为其应用背景颜色,而不是 table-cell 父元素。

    对于较小的屏幕,将 display 属性重置为 block,对于 .right 设置 width: auto

    这是一种相对简单的方法,只有一个约束与处理 .right 具有单行文本的情况有关。

    处理右侧的短线 - 调整宽度

    要允许.right 块缩小以适应单行内容,您需要调整.right 表格单元格的宽度。

    这可以使用以下 jQuery 来完成:

    var rightCellMaxWidth = parseInt($(".right").css("width"));
    
    function fixRightCellWidth() {
        $(".right .color-wrap").each(function () {
            var rightCellWidth = $(this).outerWidth();
            var rightCellType = $(this).css("display");
            if (rightCellWidth < rightCellMaxWidth 
                && rightCellType == "inline-block") {
                $(this).parent().width(rightCellWidth);
            } else {
                $(this).parent().removeAttr("style");
            }
        });
    }
    
    $(window).resize(function () {
        fixRightCellWidth();
    });
    
    fixRightCellWidth();
    

    诀窍是获取元素.right .color-wrap 的宽度。您还需要检查显示类型以查看您处于哪种媒体模式,inline-block 用于大屏幕,block 用于小屏幕。

    对于较大的屏幕,将右侧表格单元格元素的宽度设置为.color-wrap 子元素的宽度。对于单行文本,这将小于 200px,对于多行,宽度将是 200px 的最大宽度值。

    您还需要删除内联样式以清除多行情况或小屏幕情况的宽度设置。

    演示小提琴:http://jsfiddle.net/audetwebdesign/N4KE2/

    设计评论

    没有 JavaScript/jQuery,页面将优雅地降级为固定宽度的右侧元素,页面仍然可用。

    【讨论】:

    • OP 希望 right div 声明在左侧之前,但出现在小屏幕上,您的解决方案根本没有解决这个问题
    • @Zeaklous 感谢您提出相关问题。我不清楚 OP 是否必须以这种方式构建内容。但是,我决定将答案放在那里以获得一些反馈。其他人可能会觉得它很有用。
    • @Zeaklous 这是一个误解:我不希望在左边的 div 之前声明右边的 div。这只是使我的布局工作所必需的。实际上,我更希望有一个布局,它的元素以“正确”的顺序声明并且仍然可以工作
    • @Marc Audet 不幸的是,在您的示例中,右侧 div 并未真正根据内容调整其宽度,而是具有 200 像素的固定宽度。如果内容较少,它应该会自动变小。请参阅您的小提琴的此更新以了解我的意思:jsfiddle.net/N4KE2/3
    【解决方案3】:

    我想不出任何纯 CSS 的解决方案,但如果你倾向于使用 jquery,你可以像这样使用 append 方法:

    $('.frame').append($('.right'));
    

    这只会将您的“右”块移动到“框架”子项的末尾。

    有很多解决方案可以获得屏幕/窗口/框架宽度,具体取决于您的浏览器。

    【讨论】:

    • 感谢您的提示。如果我没有找到解决这个问题的其他方法,我想我会选择 JQuery。但是我仍然更喜欢仅使用 CSS 的解决方案,因为我的页面上可能有很多块(带有左右元素)我必须切换,而且我担心这么多 dom 操作会花费很多性能...