【问题标题】:How to create two columns without blocking horizontal rows [duplicate]如何在不阻塞水平行的情况下创建两列[重复]
【发布时间】:2018-05-07 12:21:29
【问题描述】:

我有一个 Wordpress 循环的帖子。这会输出某种后列表。为方便起见,我们可以将其视为 ordered-list,如下所示:

<ol>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ol>

每个列表项都有一个独特的、不同的高度。当给定特定的设备宽度时,我希望它们并排显示,而没有“类似行的行为”。因此,每一列都应将下一篇文章放在其正下方,如下图所示(较短的项目下方没有不必要的空白):

使用floatflex-boxcss-griddisplay: inline-block 对我不起作用。

虽然我希望避免在我的 DOM 中出现两个具有相同内容的循环,因为这对屏幕阅读器等来说是一种不良行为。

如果没有大量的 javascript,有没有我看不到的解决方案?互联网上到处都是float: left; 搜索“两列”、“灵活列”的示例,但我没有发现任何有用的信息。

【问题讨论】:

  • 检查砌体masonry.desandro.com
  • 您应该考虑使用网格框架。容易多了。但是,对于 vanilla CSS,您需要设置媒体查询。

标签: javascript html css rows


【解决方案1】:

您可以使用display: flexflex-direction: column;。通过向父容器添加 height(或 max-height),您可以使元素自动转到下一列。然后你可以改变一些元素的order属性,把它们推到第二行。

这个解决方案不是很通用,因为它取决于内容,但它可能会告诉你如何做到这一点。

$('li').each(function() {
  $(this).css('height',Math.floor((Math.random() * 50) + 30)+"px");
})
ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  max-height: 100vh;
  margin:0;
  padding:0;
}

li {
  box-sizing: border-box;
  text-align:center;
  padding: 10px;
  background: red;
  max-width: 50%;
  margin: 5px;
}
li:nth-child(2n) {
  background:green;
  order:1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ol>

重要通知(由@Marian Rick 添加):

  • 这种方法只有在左列大于右列时才有效
  • 需要设置固定高度,不允许动态内容

这两个问题都可以使用 javascript sn-p 来解决,以保持解决方案的动态性。

【讨论】:

  • 非常感谢@TemaniAfif,我一直认为是在flex-direction: row 容器中,而不是column :)
  • @Zvezdas1989 不知道为什么,但是在您的解决方案中,您有一些空格,可能不需要它
  • @TemaniAfif 我们应该包含一个用于基本高度计算的 javascript,这样答案就可以满足所有问题的需要。我正在为自己开发这个解决方案,并会在完成后提供。
  • @MarianRick,是的,你可以添加 JS 来计算高度,这不会影响我所做的,它会一直像现在一样运行......你只需要调整不同的值(最大-height、padding、order 等)并在需要时添加媒体查询
  • @MarianRick 我添加了一个随机计算高度的函数,你可以查看结果;)
【解决方案2】:

如果您出于某种原因希望避免使用 flex,可以使用 inline-block 执行此操作。当您将所有项目放在一列中时,只需使用媒体查询即可。

div {
  width: 95%;
  margin: auto;
}

li {
  background: red;
  width: 49%;
  min-height: 300px;
  display: inline-block;
  text-align: center;
  font-size: 50px;
  margin-top: 10px;
}

@media screen and (max-width: 600px) {
  li {
    width: 98%;
  }
}

.one {
  background: blue;
}

.three {
  background: green;
}
<div>
  <ol>
    <li class='one'>1</li>
    <li>2</li>
    <li class='three'>3</li>
    <li>4</li>
    <li>5</li>
  </ol>  
</div>

【讨论】:

  • 感谢您的建议 :) 但如您所见,您的示例不起作用,因为它分为行,而是将每个项目彼此浮动(每列中没有空格)
  • @MarianRick 当屏幕宽度小于 600 像素时,它会将项目放在一起,我认为这就是您想要在桌面上拥有两列,在移动设备上拥有一列?
  • @Zvezdas1989 是的,但我们不应该有白色的间隙:)
  • @Zvezdas1989 它不是关于创建列,有多种简单的方法可以做到这一点。它更多地是关于创建一个“流动网格”,以避免显示不必要的空白。所以每一列都会忽略另一边的div。很难解释,因为我不知道确切的英文单词。我希望您通过检查正确答案并寻找视觉差异来了解我的意思:) 无论如何感谢您的时间,我很感激。
  • @MarianRick 好吧,如果需要,您仍然可以使用此代码inline-blocks 默认创建空白,但可以轻松修复。
【解决方案3】:

我还有另一个奇思妙想的答案。它使用 flex-direction:coulmn 和 page-break-before 来强制第二列中的每一秒元素。这样,您对完整列表的高度没有限制。 请在单独的选项卡中检查 jsfiddle,以检查我如何使用断点从正常列表切换到两个列。

同时检查它是否在所有目标浏览器中运行:https://caniuse.com/#search=page-break-before

section {
  display: flex;
  flex-wrap: wrap;
}
article {
  box-sizing: border-box;
  border:1px solid grey;
  width: 100%;
  height: 50px;
}

@media (min-width: 500px) {
  section {
    flex-direction: column;
  }
  article {
    width: 50%;
  }
   article:nth-child(even) {
     order: 2;
   }
   article:nth-child(2) {
     /* this breaks into the second column after the 2nd child
     (which is not the first element of the second half of elements) */
     page-break-before: always;
   }
}

/* just for demo */  
article:first-child {
  height: 66px;
  background-color: #e0e0fe;
}
article:nth-child(4) {
  height: 80px;
  background-color: #aee0e0;
}
article:nth-child(6) {
  height: 130px;
  background-color: yellow;
}
<section>
  <article>1</article>
  <article>2</article>
  <article>3</article>
  <article>4</article>
  <article>5</article>
  <article>6</article>
  <article>7</article>
</section>

【讨论】:

  • 我们没有看到突破
  • @Fabian 这确实是一种奇特的方法。正如 Caniuse 所说,部分支持应该只影响avoid 和前缀。在使用自动前缀而不使用avoid 时,我仍然在每个浏览器中得到错误的结果。你能检查或确认这一点吗? codepen.io/anon/pen/XzqLoM
  • 没有。我很抱歉。我太信任caniuse了。它只适用于我的 FF。
  • 这里也一样。非常感谢这种方法。除了浏览器支持之外,它是迄今为止最好和最干净的答案:)
【解决方案4】:

基于great idea of @TemaniAfif,我写了一个小的,几乎没有测试过的jQuery sn-p,它实现了以下:

  • 根据其在容器内的位置,每个项目都将尽可能靠近顶部放置
  • 调整浏览器大小时,每个项目都会更新其位置
  • 它的 JavaScript 很少且速度很快,而 CSS 完成了大部分工作

整个概念仍然基于使用order: x 属性将项目推到左侧或右侧的想法。

有一个 CODEPEN DEMO 可以玩。

注意:浏览器支持等同于flex-box的浏览器支持。

"use strict";

// DEMO STYLE - Should be removed
// calculate random heights for each item
$("li").each(function() {
  $(this).css("height", Math.floor(Math.random() * 300 + 2) + "px");
});


///////////////////////
// Calculate columns
//
// 1. loop through each item.
// 2. first get the height of item
// 3. than check which column is shorter
// 4. if left column is shorter or equal, keep item on the left side
// 5. if right column is shorter, push this item to the right side
// 6. check which side will be higher
// 7. if left column is higher, assign height of column to parent container
// 8. if right column is higher, create a margin-bottom equal of the column offset and assign it to the left column
// calculation is finished. test it.

// finally add the height of the bigger column to the div
// if its the left column, assign the height of the right
var container = $("ol");
var items = container.find("li");
var breakPoint = 768; // if equal or bigger, the calculation will be fired

var calcPositions = function calcPositions() {

  // quit function if its a mobile device
  if ($(window).width() < breakPoint) return;

  // reset margin of left column item
  container.find("li.push-left").last().css("margin-bottom", "15px");

  var leftColumnHeight = 0;
  var rightColumnHeight = 0;

  // 1. loop through each item
  items.each(function(i, e) {
  
    // 2. get height of item
    var height = $(this).outerHeight(true);

    // 3. check which column is shorter
    if (leftColumnHeight <= rightColumnHeight) {
    
      // 4. if left column is shorter or equal, keep item on the left side
      leftColumnHeight += height;
      $(this).removeClass("push-right").addClass("push-left");
      return; // skip rest and continue with next item
    }

    // 5. if right column is shorter, push this item to the right side
    // using .push-right { order: 5 } inside css
    rightColumnHeight += height;
    $(this).removeClass("push-left").addClass("push-right");
  });

  // 6. check which side will be higher
  if (leftColumnHeight >= rightColumnHeight) {
  
    // 7. if left column is higher, assign height of column to parent container
    container.height(leftColumnHeight);
    return; // end of function
  }

  // 8. if right column is higher, create a margin-bottom equal of the column offset and assign it to the left column
  // otherwhise the second object can be displayed at the bottom of the left column

  // get offset of columns
  var columnOffset = rightColumnHeight - leftColumnHeight;

  // assign offset to last element of left sidebar
  container.find("li.push-left").last().css("margin-bottom", columnOffset + "px");

  // assign height to container
  container.height(rightColumnHeight);
};

// calculate initially
calcPositions();

// calculate on resize
$(window).resize(function() {
  calcPositions();
});
/* functional classes needed for this grid */


/* keep this breakpoint in sync with "breakPoint" inside the javascript */

@media (min-width: 768px) {
  ol {
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
  }
  
  li {
    max-width: 50%;
  }
  
  li.push-right {
    order: 1;
    margin-right: 0;
  }
}


/* demo styles that can be removed */

* {
  box-sizing: border-box;
}

ol {
  padding: 0;
  max-width: 800px;
  width: 90%;
  margin: 0 auto;
}

li {
  background: red;
  margin-bottom: 15px;
}

@media (min-width: 768px) {
  li {
    max-width: 49%;
    margin-right: 2%;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p>Breakpoint is set to >=768px for two columns:</p>

<ol>
  <li>Lorem.</li>
  <li>Asperiores!</li>
  <li>Illum!</li>
  <li>Perspiciatis!</li>
  <li>Eius.</li>
  <li>Est.</li>
  <li>Quisquam.</li>
  <li>Eaque!</li>
  <li>Vero?</li>
  <li>Iste?</li>
  <li>Provident?</li>
  <li>Ipsum.</li>
</ol>

【讨论】:

  • greate one ;) 顺便说一下,您可以在此处删除 Snippet 上的前缀以使代码轻量级;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
相关资源
最近更新 更多