如何在响应的3列结构中对齐中间列?

时间:2013-09-06 16:14:23

标签: html css html5

我有一个带有几个英文句子的HTML表单,每行可视化显示一个句子。在每个句子的中间有一个<select>下拉列表,其左右边缘需要在多行之间对齐,以使其看起来更干净:

<div class="row">
    <div class="column col1"> <p> Choose something: </p> </div>
    <div class="column col2"> <select name="dropdown"> ... options ... </select> </div>
    <div class="column col3"> <p> and finish the sentence.</p> </div>
</div>
<div class="row">
    <div class="column col1"> <p> Choose something else: </p> </div>
    <div class="column col2"> <select name="dropdown2"> ... options ... </select> </div>
    <div class="column col3"> <p> and finish another sentence.</p> </div>
</div>
<div class="row">
    <div class="column col1"> <p> Choose last thing: </p> </div>
    <div class="column col2"> <select name="dropdown3"> ... options ... </select> </div>
    <div class="column col3">
        <p>
            and all dropdowns should be left- and right-aligned if
            there is space.  This longer third column should get broken
            onto a second line below the second dropdown if it can't fit
            immediately to the right of the other two.
        </p>
    </div>
</div>

然而,这是一个响应式布局,我只想修复中间列的宽度,并根据以下设计标准自动扩展/收缩第1列和第3列:

  • 每个column中尽可能多的row个元素应该左右放置,具体取决于视口宽度。
  • 尽可能多的col2元素应左对齐。

在上面,第一个优先考虑第二个;换句话说,如果我们从足够宽的浏览器视口开始,以适应两个标准:

  1. 随着浏览器视口宽度的减小,要缩小的第一个宽度应该是第3列,保留col2对齐并保持所有三个column元素并排。
  2. 如果将第3列缩小到最小宽度是不够的,第1列应该开始收缩,这会在某些时候断开对齐但仍然保持元素并排。
  3. 如果仍然不够,任何行中仍然过宽的整个col3块应移动到col1col2块之下。现在col3不再与col1col2并排,但这种牺牲意味着我们可以恢复col2对齐。 (此时col1的{​​{1}}将防止句子开头与下拉列表之间出现意外差距。)
  4. 根据前两条规则,显然任何使用百分比的东西都不会起作用。并且可能是由于第3条规则,使用max-width的任何内容都不起作用。

    可以假设任何边距/填充都是固定的。 <table>会破坏英文句子,因此overflow: hidden元素不会有高度限制。

    我已经浏览了无数的HTML / CSS文章和SO问题,但到目前为止还没有找到解释如何实现这一目标的任何内容。以下是您玩游戏的起点:

    在CSS中涉及HTML5或更新功能的解决方案比基于JavaScript的黑客更受欢迎。改变HTML的解决方案是可以的,虽然我很想知道它是否只能通过CSS实现。谢谢!

2 个答案:

答案 0 :(得分:1)

采用JavaScript / JQuery方法,我会提供一个想法,但不是代码本身。 我的代码部分不是真正的代码,而是说明需要做什么。 (CSS部分除外)

首先,我们将页面中所有元素的框大小设置为边框,因为它更容易以这种方式计算元素的大小。

*
{
    -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
    -moz-box-sizing: border-box; /* Firefox, other Gecko */
    box-sizing: border-box; /* Opera/IE 8+ */
}

这意味着.col2的宽度必须增长10px才能支持10px填充并保持不变。

.col2
{
    width: 120px;
}

如果第二列始终位于第一列的旁边,那将是最好的, 所以我们将设置.col1的最大宽度以支持该行为。

.col1
{
    max-width: calc(100% - 136px); /*136 = 120 + 2*5 + 2*3*/
}

在整个过程中,我们不会将任何内容设置为.row&amp; .col3宽度。 行可以缩小或增长,而.col3将始终占用所需的确切空间量 (无论他是否与.col1&amp; .col2或在不同的行中对齐),实际上我们只改变.col1宽度。

当页面首次加载时,每次主体调整大小时,我们都会调用一个找到最佳布局的javaScript函数。

function adjustToBestLayout()
{
    1.
    2.
    3.
    4.
}

在这个过程中,我们需要知道.col1&amp;的实际大小是多少。当前视口大小中的.col3元素(.col2是固定的,所以它有帮助) 如果我们不应用脚本,因为它们的宽度取决于它们的内容,并且可能会在不同的视口大小中发生变化。

所以,如果我们第一次进入该功能,我们将“保存”我们的干净布局,而不是脚本干预。 然后,每次我们进入该功能时,我们将用干净的布局替换旧的调整后的布局,并从头开始重新调整。

所以它是这样的:

1 带回“干净”的布局。 现在我们在每行中都有以下内容: .col1&amp; .col2是对齐的,每个都取其内容的大小, 和.col3(也完全取其内容的大小)可以处于两种可能的状态之一, 他可以与两个第一列对齐,也可以换成新行。

2 每个列元素都会将其实际宽度保存在名为ActualWidth的属性中供以后使用

每行

3 ,我们将计算AvailableWidth并将其保存为属性供以后使用,计算结果如下:

if(row.width >= row.col1.ActualWidth + row.col2.ActualWidth + row.col3.ActualWidth)
{
    //in this case, all columns are in the same line, and we possibly have space left
    row.AvailableWidth = row.width - (row.col1.ActualWidth + row.col2.ActualWidth + row.col3.ActualWidth);
}
else
{
    //in this case, the third column is in a different line,
    row.AvailableWidth = row.width - (row.col1.ActualWidth + row.col2.ActualWidth);
}

当我们将.col1元素拉伸到相同宽度时,将找到最佳布局, 所以我们将尝试将.col1拉伸到布局中更大的.col1元素的大小。 但是没有导致任何.col3元素到达新行, 所以我们只能通过他的row.AvailableWidth或更少来拉伸每个.col1元素。

4 通过此计算找到给予.col1元素的最佳宽度: 对于每个.col1,如果我们将另一个.col1拉伸到他的大小,我们将计算将对齐多少行。 并且我们将采用得分最大的那个。 所以,对于每个.col1.ActualWidth(= CurrentWidth):有多少行对此语句返回true

0 <= CurrentWidth - row.col1.CurrentWidth <= row.AvailableWidth

之后,我们将.col1元素的宽度固定为获胜宽度 (仅在返回true的行中返回前一个语句)

Etvoilà!

Finnaly:如果我是你,我会选择“像桌子一样”的“固定”布局。

答案 1 :(得分:0)

我终于想出了以下CoffeeScript解决方案:

fixSizes = ->
    col1_min = parseInt $(".col1").css("min-width")
    col1_max = parseInt $(".col1").css("max-width")
    console.log "min #{col1_min}, max #{col1_max}"
    $(".row").each (i, row) =>
        debug = false
        r = $(row)
        row_width   = r.width()
        col1_width  = r.find(".col1").width()
        col1_outer  = r.find(".col1").outerWidth(true)
        col2_outer  = r.find(".col2").outerWidth(true)
        col3_outer  = r.find(".col3").outerWidth(true)
        col1_spacing = col1_outer - col1_width
        space_for_col1 = row_width - col1_spacing - col2_outer - col3_outer
        if i == 1
            debug = true
        if debug
            console.log "row#{i} #{row_width}, col1 #{space_for_col1}, col1s #{col1_spacing}, col2 #{col2_outer}, col3 #{col3_outer}"
        col1 = r.find(".col1")
        col3 = r.find(".col3")
        if space_for_col1 < col1_min
            # Can't shrink col1 enough to fit all onto one line; break
            # col3 onto new line.
            col1.css("width", "#{col1_max}px")
            col3.css("clear", "left")
            if debug
                console.log "    break into two lines"
        else if space_for_col1 < col1_max
            # Shrink col1 to fix all onto one line.  Annoyingly we
            # need to shrink by an extra pixel in order to ensure that
            # col3 has enough room to go on the top line and doesn't
            # float directly underneath col2.  This is presumably due
            # to rounding errors, since the row width is a float (in
            # Chrome at least).
            col1.css("width", "#{Math.floor(space_for_col1)-1}px")
            col3.css("clear", "")
            if debug
                console.log "    shrink col1"
        else
            # No shrinking required, ensure col2 is aligned.
            col1.css("width", "#{col1_max}px")
            col3.css("clear", "")
            if debug
                console.log "    fix col1 to align col2"

jQuery ->
    fixSizes()
    $(window).resize ->
        fixSizes()

当缩小Chrome中的窗口宽度时,除了令人讨厌的闪烁之外它是有效的 - 在Javascript缩小col3之前,col2会立即浮动col1。向后漂移到col2的右侧。

但这感觉很难看。我不能不觉得必须有更优雅的东西。