如何使用flexbox布局多个列?

时间:2017-06-17 10:52:26

标签: php css css3 flexbox css-grid

我正在尝试以下列方式布局多个列。我正在使用Wordpress但编辑PHP,HTML,CSS等。 site layout

这是HTML。想象一下A B C作为代码块,没有固定的高度和百分比宽度,如图所示。

<div class="flex wrap">
     <div class="main">A</div>
     <div class="optional">B</div>
     <div class="main2">C</div>
</div>

只要我使用flexbox,我就可以使用视口来改变flex的顺序。但是现在我无法获得所需的桌面布局。

我可以使用第二列的嵌套div的列(bootstrap)来创建桌面布局,但是移动布局将是BAC或ACB而不是ABC。

这是我的CSS:

.flex.wrap {
    flex-wrap: wrap;
}

.flex {
    display: flex!important; /* to override display:block */
}

.main {
    order: 2;
    flex: 0 75%;
}

.optional {
    order: 1;
    flex: 0 25%;
}
.main2 {
    order: 3;
    flex: 0 75%
}

我做了我的研究,并且看到了许多这样的问题,但没有任何满足我需要的满意答案。

我不必使用弹性盒子,我也不需要纯css解决方案 - 只要它可以在大多数现代浏览器和移动设备上使用。我只需要一些有用的东西。所以我对任何建议持开放态度。

我也可以在两个代码块上使用display: none,但这会使代码增加67行,我认为不应该这样做。

即使有一个可能像下面这样工作的php解决方案,它也可能有用。

If (code that determines mobile viewport) echo html
else
echo nothing

另一个相同的代码,我想要桌面版本。我知道这不是优雅的,但最后我关心的是结果,包括表现而不是其他任何东西。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:2)

由于您无法设置固定的高度,因此Flexbox无法单独执行此操作,因此要么将其与定位或脚本结合使用,要么使用CSS Grid(尽管浏览器支持少于Flexbox)。 / p>

以下是使用定位的示例,并使用原始代码示例中的类进行更新,以便更容易理解。

&#13;
&#13;
html, body {
  margin: 0;
}
.wrapper {
  position: relative;
}
.flex {
  display: flex;
  flex-direction: column;
}
.flex > div {
  border: 1px solid;
  box-sizing: border-box;
}

/*  for desktop  */
@media screen and (min-width: 600px) {
  .flex > .optional {
    position: absolute;
    left: 0;
    top: 0;
    width: 25%;
    height: 100%;
  }
  .flex .main,
  .flex .main2 {
    margin-left: 25%;    /*  match the width of the "optinal"  */
  }
}
&#13;
<div class="wrapper">
  <div class="flex">
    <div class="main">A</div>
    <div class="optional">B</div>
    <div class="main2">C</div>
  </div>
</div>
&#13;
&#13;
&#13;

<强> 更新

在某些情况下,人们根本无法使用绝对定位,例如当左右列(桌面模式)都可以超越另一列时。

以下是使用小脚本的版本,该脚本模仿媒体查询并将optional元素移入和移出flex容器。

它还会切换body上的一个类,在这种情况下为mobileview,它在CSS中用于切换wrapper作为flex容器,并在optional上设置适当的属性{1}}当它是wrapper而不是flex的弹性项目子时。{/ p>

使用脚本中的minwidth = 600变量,可以控制布局应切换的宽度。

以下是fiddle demo也可以使用

&#13;
&#13;
(function(d, w, timeout) {

  /* custom variables */
  var flexcontainer = '.flex',
    flexitem = '.optional',
    minwidth = 600,             /* if null, then when viewport is portrait */
    classname = 'mobileview';
    
  /* here happens the magic */
  function resizeing() {
    if ((minwidth && (minwidth < w.innerWidth)) ||
        (!minwidth && (w.innerHeight < w.innerWidth))) {
      if (!(d.body.classList.contains(classname))) {
        /* move it outside the main flexcontainer */
        d.body.classList.add(classname);
        var fca = qSA(flexcontainer);
        for (var i = 0; i < fca.length; i++) {
          fca[i].parentNode.appendChild(qS(flexitem, fca[i]))
        }
      }
    } else {
      if (d.body.classList.contains(classname)) {      
        /* move it back inside the main flexcontainer */
        d.body.classList.remove(classname)
        var fca = qSA(flexcontainer);
        for (var i = 0; i < fca.length; i++) {
          fca[i].appendChild(qS(flexitem, fca[i].parentNode))
        }
      }      
    }
  }
  
  /* run at page load init resize */
  w.addEventListener("load", function() {
    resizeing();
  }, false);
  
  /* grab when viewport resize */
  w.addEventListener("resize", function() {
    if (!timeout) {
      timeout = setTimeout(function() {
        timeout = null;
        resizeing();
      }, 66);
    }
  }, false);
  
  /* helper variables */
  var qSA = function(s, el) {
      return (el) ? el.querySelectorAll(s) :
        d.querySelectorAll(s)
    },
    qS = function(s, el) {
      return (el) ? el.querySelector(s) :
        d.querySelector(s)
    };
}(document, window));
&#13;
html, body {
  margin: 0;
}
.wrapper .flex {
  flex-grow: 1;
  display: flex;
  flex-direction: column;
}
.wrapper .flex > div {
  flex-grow: 1;
  border: 1px solid;
  box-sizing: border-box;
}
.wrapper .flex .optional {
  order: 1;
}
.wrapper .flex .main2 {
  order: 2;
}

/*  for desktop  */
.mobileview .wrapper {
  display: flex;
}
.mobileview .wrapper .optional {
  flex-basis: 25%;
  order: -1;
  border: 1px solid;
  box-sizing: border-box;
}
&#13;
<div class="wrapper">
  <div class="flex">
    <div class="main">A</div>
    <div class="optional">
      B as a lot more content<br>
      B as a lot more content<br>
      B as a lot more content<br>
      B as a lot more content<br>
      B as a lot more content<br>
    </div>
    <div class="main2">C</div>
  </div>
</div>

<h5>More than one container and other text etc.</h5>

<div class="wrapper">
  <div class="flex">
    <div class="main">
      A as a lot more content<br>
      A as a lot more content<br>
      A as a lot more content<br>
      A as a lot more content<br>
      A as a lot more content<br>
    </div>
    <div class="optional">B</div>
    <div class="main2">C</div>
  </div>
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

更多信息用于提供有效答案此时

您可以从flex切换到grid,其中

  • grid允许设置行和&amp;列,订购也可以跨越的元素,
  • flex允许重新排序:

实施例

body {
  display: grid;
  grid-template-columns: 25% 1fr;
  grid-gap: 10px
}

.opt {
  grid-column: 1;
  grid-row: 1 / span 2;
  background: gold
}

div {
  background: turquoise
}

@media all and (max-width: 360px) {/* set here width where you need to switch layout */
  body {
    display: flex;
    flex-flow: column
  }
  .a {
    order: -2
  }
  .opt {
    order: -1
  }
  div {
    margin: 5px 10px
  }
}
<div class="a">A of any height</div>
<div class="c">C of any height</div>
<div class="opt">B of any height</div>

如果网格看起来很有趣:https://css-tricks.com/snippets/css/complete-guide-grid/

答案 2 :(得分:1)

实现此布局的最有效方法是使用 CSS网格布局

.container {
  display: grid;
  grid-template-columns: 25% 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  grid-gap: 5px;
  grid-template-areas: " B A " 
                       " B C ";
}

.A { grid-area: A; }
.B { grid-area: B; }
.C { grid-area: C; }

@media ( max-width: 800px ) {
  .container {
    grid-template-columns: 1fr;
    grid-template-areas: "A" "B" "C";
  }
}

/* non-essential styles; for demo only */
.container { height: 200px; }
.A { background-color: aqua; }
.B { background-color: gold; }
.C { background-color: lightgreen; }
.container > div { display: flex; align-items: center; justify-content: center; }
<div class="container">
  <div class="A">A</div>
  <div class="B">B</div>
  <div class="C">C</div>
</div>

jsFiddle demo

以下是它的工作原理:

  • grid-template-columns中的值数确定了列数。 grid-template-rows的相同概念。
  • grid-template-areas属性允许您使用ASCII视觉艺术排列布局。将网格区域名称(为每个元素定义)放置在您希望它们出现的位置。
  • fr单位告诉列/行消耗可用空间。它类似于flex-grow

此外,原始HTML结构没有变化。它保持尽可能简单。并且不需要使用order属性。

CSS网格的浏览器支持

  • Chrome - 完全支持截至2017年3月8日(第57版)
  • Firefox - 完全支持截至2017年3月6日(第52版)
  • Safari - 完全支持截至2017年3月26日(版本10.1)
  • Edge - 截至2017年10月16日(第16版)的全面支持
  • IE11 - 不支持当前规范;支持过时版本

以下是完整图片:http://caniuse.com/#search=grid

Flexbox问题

如果您可以在容器上设置固定高度,则可以使用flexbox 实现所需的桌面布局。

使用flex-flow: column wrap,这将允许一个项目占用第一列中的所有空间。然后,第二个和第三个项目可以包装并共享第二列中的空间。您可以使用order属性重新排列每个项目的位置。

但是,如上所述,容器上的固定高度是必要的,因为否则项目没有断点并且不会换行。

在行方向上,无法使用flexbox进行桌面布局,因为您要求项目包装在同一行中的另一个项目下。换句话说,“B”确定行的高度,然后您希望“C”包裹在该行的“A”下。这不是flexbox的工作方式。

以下是一个更完整的解释: