【问题标题】:Make last element take remaining width with wrapping (and with IE9 support)使最后一个元素采用包装的剩余宽度(并支持 IE9)
【发布时间】:2016-04-13 09:10:20
【问题描述】:

我正在寻找一种将多个项目彼此相邻对齐的方法,让它们在填满一行后自动换行,最后一个项目占据最后一行的剩余宽度

我之前发现过多个关于类似主题的问题,解决方案通常使项目使用float: left 将它们对齐在一条线上,并在最后一个元素上使用overflow: hidden 使其自动占用剩余空间。这些解决方案在一行中运行良好,但是一旦在最后一个元素之前有足够的项目,它们就会停止工作,它们会包装成多行。然后,“最后一个”元素仍然呈现在第一行(如果有足够的空间),使其不再是最后一个元素。

但是,我希望最后一个元素始终保持最后一个元素,将它放在最后一行(无论是哪一行)并自动占用那里的剩余空间。

使用 wrapping flexbox 非常简单,因为您只需将 flex: 0 auto 放在前面的项目上,以使它们占据所需的任何空间(不占用更多空间),并将 flex: 1 放在要制作的最后一个元素上它占据了其余部分。 但是,我需要支持 Internet Explorer 9,所以很遗憾,flexbox 是不可能的。

情况是这样的。运行 sn-p 时,您可以使用“Toggle flex box”按钮来切换 flexbox 模式,以显示它应该的样子。

* { box-sizing: border-box; }
.container {
  width: 300px;
  background: snow;
  padding: 5px;
  overflow: auto;
}
.element {
  float: left;
  margin: 2px 5px 2px 0;
  background: lavender;
}
.last {
  overflow: hidden;
}
.last > input {
  width: 100%;
}

/* Working solution with flex box */
.flex .container {
  display: flex;
  flex-wrap: wrap;
}
.flex .element {
  flex: 0 auto;
}
.flex .last {
  flex: 1;
}
<div class="container">
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>

  <div class="last"><input type="text" /></div>
</div>

<div class="container">
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>

  <div class="last"><input type="text" /></div>
</div>

<button onclick="this.parentNode.classList.toggle('flex')">Toggle flex box</button>

【问题讨论】:

  • 很好的问题,我之前没有尝试使用 css flex,所以我不知道在这种情况下使用 css。您是否考虑过手动计算剩余宽度并使用 js 修复具有该宽度的最后一项?
  • flexbox 解决方案只是为了展示它应该是什么样子(以及如何使用现代浏览器轻松解决这个问题),但由于我正在寻找没有 flexbox 的解决方案,你可以简单地忽略该解决方案。是的,用 JavaScript 解决它是我的后备解决方法,以防万一这被证明是无法解决的。
  • 好吧,因为你仍然需要支持IE9,所以JS可能是一个更好的选择。但我会尝试解决这个问题,我记得我在某处看到它并仅使用 css 修复它
  • 在你的情况下,我发现你没有自然地对待它,因为带有class="last" 的项目不是最后一个,所以强制它适合第一行可能会很棘手
  • @ThoVo 我不确定你的意思?我希望元素.last(如果有帮助,可以放在代码中的任何位置)填满最后一行。尽管有多行,但它在第一行呈现正是我不想要的(但是这个解决方案正在发生什么)。

标签: html css


【解决方案1】:

对于希望使用脚本选项的其他所有人,这里也适合您。

只需将data-calcattr 添加到您希望将其width 属性设置为width: calc(100% - ??px); 的元素中,其中??px 是其当前宽度。

旁注:

脚本可能需要调整以弥补未来的边框、边距等,因此这个脚本更多地是一种方法。

function calcattr() {
  var els = document.querySelectorAll('[data-calcattr]');
  // TODO: add switch to enable calc. different properties like
  //       get the remaining height as well, by checking the 
  //       data-calcattr value, i.e.: data-calcattr='height'
  for (i = 0; i < els.length; i++) {
    els[i].setAttribute("style", "width: 0");    
    var lpos = parseInt(els[i].getBoundingClientRect().left);
    var minw = parseFloat(getComputedStyle(els[i]).getPropertyValue('min-width'));
    var calcwidth = "calc(100% - " + (lpos + 2) + "px)";
    els[i].setAttribute("style", "width: " + calcwidth);
    if ((els[i].getBoundingClientRect().right - lpos) < minw) {
      els[i].setAttribute("style", "width: 100%");
    }
  }
}

window.onload = calcattr;

(function() {
  window.addEventListener("resize", resizeThrottler, false);
  var resizeTimeout;
  function resizeThrottler() {
    if ( !resizeTimeout ) {
      resizeTimeout = setTimeout(function() {
        resizeTimeout = null;
        actualResizeHandler();
      }, 66);
    }
  }
  function actualResizeHandler() {
    calcattr();
  }
}());
* { box-sizing: border-box; }
.container {
  width: 300px; //70%;
  background: snow;
  padding: 5px;
  overflow: auto;
}
.fullwidth {
  width: 100%;
}
.element {
  float: left;
  margin: 2px 5px 2px 0;
  background: lavender;
}
.last > input {
  width: 100%;
}
.last {
  float: left;
  min-width: 20px;
}
<div class="container">
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>

  <div class="last" data-calcattr><input type="text" /></div>
</div>

<div class="container">
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>

  <div class="last" data-calcattr><input type="text" /></div>
</div>

<div class="container fullwidth">
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>
  <div class="element">Foo</div>
  <div class="element">Foo bar</div>
  <div class="element">Foo bar baz</div>

  <div class="last" data-calcattr><input type="text" /></div>
</div>

【讨论】:

    【解决方案2】:

    解决办法如下:

    • .last元素前添加&lt;div style="clear:left;margin-top:22px"&gt;&lt;/div&gt;*
    • margin-top: -22px; 添加到.last,其中金额与行高大致相同
    • 如果您不希望它变得太小,请将 min-width 添加到 .last,它会按您的预期工作
      此外,课程中还需要 min-width: 1px;,以避免在特殊情况下它得到 0。

    在 IE8+、Edge、Chrome、Opera、Firefox 中测试和工作

    * { box-sizing: border-box; }
    .container {
      width: 300px;
      background: snow;
      padding: 5px;
      overflow: auto;
    }
    .element {
      float: left;
      margin: 2px 5px 2px 0;
      background: lavender;
    }
    .last {
      overflow: hidden;
      margin-top: -22px;
      min-width: 1px;
    }
    .last > input {
      width: 100%;
    }
    .container .unwrap {
      clear: left;
      margin-top: 22px
    }
    <div class="container">
      <div class="unwrap"></div>
      <div class="last"><input type="text" /></div>
    </div>
    
    <div class="container">
      <div class="element">Foo</div>
      <div class="element">Foo bar</div>
      <div class="element">Foo bar baz</div>
      <div class="unwrap"></div>
      <div class="last"><input type="text" /></div>
    </div>
    
    <div class="container">
      <div class="element">Foo</div>
      <div class="element">Foo bar</div>
      <div class="element">Foo bar baz boo</div>
      <div class="unwrap"></div>
      <div class="last" style="min-width: 100px">
        <input type="text" placeholder="min-width 100px" />
      </div>
    </div>
    
    <div class="container">
      <div class="element">Foo</div>
      <div class="element">Foo bar</div>
      <div class="element">Foo bar baz</div>
      <div class="element">Foo</div>
      <div class="element">Foo bar</div>
      <div class="element">Foo bar baz</div>
      <div class="unwrap"></div>
      <div class="last"><input type="text" /></div>
    </div>
    
    <div class="container">
      <div class="element">Foo</div>
      <div class="element">Foo bar</div>
      <div class="element">Foo bar baz</div>
      <div class="element">Foo baaaaaaaaaaaaaaaaaaaaaaar</div>
      <div class="unwrap"></div>
      <div class="last"><input type="text" /></div>
    </div>
    
    <div class="container">
      <div class="element">Foo bar baz Foo bar baz Foo bar baz Foo bar baz Foo bar baz Foo bar baz Foo bar baz Foo bar baz Foo bar baz Foo bar baz Foo bar baz Foo bar baz</div>
      <div class="unwrap"></div>
      <div class="last"><input type="text" /></div>
    </div>

    * margin-top:22px 只是为了避免输入在容器中没有元素的情况下滑过。应该是输入负边距的绝对值

    【讨论】:

    • 再次感谢您的出色回答并祝贺您获得这些积分;)
    【解决方案3】:

    以下解决方案并不完美,它使用了位置技巧。如果禁用overflow: hidden;,您将看到每个&lt;input&gt; 实际上与容器具有相同的宽度。但是通过一些 CSS 视觉调整,它看起来不错并且可以正常工作。

    问题 1:如果您输入的字符数超出视觉范围,则整个视图会向左移动。

    解决方法 1:maxlength 值设置为 &lt;input&gt; 可能会有所帮助。

    jsfiddle

    * {
      box-sizing: border-box;
    }
    .container {
      width: 300px;
      background: snow;
      padding: 5px;
      position: relative;
      overflow: hidden; /*hide the overflow*/
    }
    span:after {
      content: "\00A0" /*just for one no-break space*/
    }
    input {
      width: 100%;
      position: absolute; /*without any top/right/bottom/left value*/
      border: 2px solid grey;
      border-width: 0 0 2px 0;
    }
    input:focus {
      outline: 0;
    }
    <div class="container">
      <span>FooFoo barFoo bar baz</span>
      <input type="text" />
    </div>
    
    <div class="container">
      <span>FooFoo barFoo bar bazFooFoo barFoo bar baz bla</span>
      <input type="text" />
    </div>

    【讨论】:

    • 不幸的是,如果您输入的字符数超出了文本输入的显示部分的视觉范围,则会中断。到达末尾后,整个视图会在您输入更多内容时向右滚动。
    • 你是对的。这不是完美,但这是我尝试使用纯 CSS 并受您的限制的最佳方式。作为一种解决方法,我想知道设置 maxlength 可能会有所帮助,这也取决于您的要求。
    • 我也很想看到更好的答案,你考虑开始赏金吗?如果没有计划,我可能会这样做。
    • 如果我在接下来的几天内没有收到更多回复,我可能会开始一个。我自己尝试了更多的东西,我担心真的没有任何非 JS 解决方案:/
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-02
    • 2014-06-25
    • 1970-01-01
    • 2017-02-12
    • 2015-12-14
    • 1970-01-01
    • 2010-11-06
    相关资源
    最近更新 更多