响应地将2列布局折叠为单列

时间:2018-01-25 22:42:57

标签: html css flexbox css-grid css-multicolumn-layout

我目前有一个由内容框组成的页面,其布局使得有两个不等宽度的浮动列,每个框具有适合其内容的不同高度,如下所示:



.box {
  padding: 1em;
  border: 1px solid black;
  margin: 3px;
}

.left.col {
  float: left;
  width: 70%;
}

.right.col {
  float: right;
  width: 30%;
}

.b1 {
  background-color: red;
  height: 150px;
}

.b2 {
  background-color: green;
  height: 80px;
}

.b3 {
  background-color: blue;
  height: 80px;
}

.b4 {
  background-color: yellow;
  height: 40px;
}

.b5 {
  background-color: purple;
  height: 30px;
}

.b6 {
  background-color: cyan;
  height: 40px;
}

.b7 {
  background-color: orange;
  height: 40px;
}

<div class="boxes">
  <div class="left col">
    <div class="box b1">1</div>
    <div class="box b2">2</div>
    <div class="box b3">3</div>
  </div>
  <div class="right col">
    <div class="box b4">4</div>
    <div class="box b5">5</div>
    <div class="box b6">6</div>
    <div class="box b7">7</div>
  </div>
</div>
&#13;
&#13;
&#13;

我希望能够将较小屏幕上的布局转换为单个列,但这样我才能控制内容框的排序。 为此,我很高兴将flexbox order与适当的polyfill一起用于不受支持的浏览器,例如flexibility。 像这样:

&#13;
&#13;
/* @media screen and (max-width: 570px) */
.boxes {
  display: flex;
  flex-direction: column;
}

.box {
  padding: 1em;
  border: 1px solid black;
  margin: 3px;
}

.b1 {
  background-color: red;
  height: 150px;
  order: 1
}

.b2 {
  background-color: green;
  height: 80px;
  order: 3
}

.b3 {
  background-color: blue;
  height: 80px;
  order: 5
}

.b4 {
  background-color: yellow;
  height: 40px;
  order: 2;
}

.b5 {
  background-color: purple;
  height: 30px;
  order: 4
}

.b6 {
  background-color: cyan;
  height: 40px;
  order: 6
}

.b7 {
  background-color: orange;
  height: 40px;
  order: 7
}
&#13;
<div class="boxes">
  <div class="box b1">1</div>
  <div class="box b2">2</div>
  <div class="box b3">3</div>
  <div class="box b4">4</div>
  <div class="box b5">5</div>
  <div class="box b6">6</div>
  <div class="box b7">7</div>
</div>
&#13;
&#13;
&#13;

我迄今为止无法做到的是将其作为一种单一的,快速响应的方法来实现。我认为我需要摆脱<div class="col">以便使用flex来控制盒子顺序,但似乎无法使用flexbox和没有浮动来实现相同的2列布局。

是否有单一(CSS)解决方案可以实现和响应切换两种布局?

修改

IE9和Android 4.x在过去一年中每个目前的受众中占2%左右,所以我仍然需要支持它们。因此,使用现代CSS技术(例如Flexbox,CSS网格)的任何解决方案都需要使用polyfill进行备份或优雅地回退/降级。

3 个答案:

答案 0 :(得分:3)

如果您只能使用flexbox,那么使用nested containers or a height or max-height on the container布局很简单。

此布局最有效的CSS解决方案将使用网格技术。

以下解决方案已完成,browser support is quite strong

jsFiddle demo

.boxes {
  display: grid;
  grid-template-columns: 3fr 1fr;
  grid-auto-rows: 10px;
  grid-gap: 5px;
  grid-template-areas:
   " red yellow"
   " red yellow"
   " red yellow"
   " red yellow"
   " red yellow"
   " red yellow"   
   " red purple"
   " red purple"
   " red purple"
   " red purple"
   " red purple"   
   " red cyan"
   " red cyan"
   " red cyan"
   " red cyan"
   " green cyan"
   " green orange "
   " green orange "
   " green orange "
   " green orange "
   " green orange "   
   " green . " 
   " green . " 
   " green . " 
   " blue . " 
   " blue . "  
   " blue . "    
   " blue . "  
   " blue . "  
   " blue . "  
   " blue . "   
   " blue . "     
}

.b1 { grid-area: red;    background-color: red;    }
.b2 { grid-area: green;  background-color: green;  }
.b3 { grid-area: blue;   background-color: blue;   }
.b4 { grid-area: yellow; background-color: yellow; }
.b5 { grid-area: purple; background-color: purple; }
.b6 { grid-area: cyan;   background-color: cyan;   }
.b7 { grid-area: orange; background-color: orange; }

.box {
  padding: 1em;
  border: 1px solid black;
}

@media (max-width: 570px) {
  .boxes { grid-template-columns: 1fr;
           grid-template-areas: 
   " red "
   " red "
   " red "
   " red "
   " red "
   " red "
   " red "
   " red "
   " red "
   " red "
   " red "   
   " red "
   " red "
   " red "
   " red "
   " yellow "
   " yellow "
   " yellow "
   " yellow "
   " yellow "
   " yellow "
   " green "
   " green "
   " green "
   " green "
   " green "
   " green "   
   " green " 
   " green " 
   " green " 
   " purple "
   " purple "
   " purple "
   " purple "
   " purple "
   " blue " 
   " blue "  
   " blue "    
   " blue "  
   " blue "  
   " blue "  
   " blue "   
   " blue "     
   " cyan "
   " cyan "
   " cyan "
   " cyan "
   " cyan "
   " orange "
   " orange "
   " orange "
   " orange "
   " orange " ;}

}
<div class="boxes">
  <div class="box b1">1</div>
  <div class="box b2">2</div>
  <div class="box b3">3</div>
  <div class="box b4">4</div>
  <div class="box b5">5</div>
  <div class="box b6">6</div>
  <div class="box b7">7</div>
</div>

特点:

  • 现代CSS3技术
  • 包含两列(3fr1fr)(more about the fr unit
  • 的容器
  • 根据需要自动创建行;每行高10px ......
  • 所以跨越四行的网格区域是40px(加上任何grid-row-gap
  • 网格区域使用grid-template-areas属性
  • 中的字符串值进行布局
  • 网格区域可以使用其他方法(例如line-based placement
  • 进行布局

答案 1 :(得分:1)

由于唯一的纯CSS解决方案是CSS Grid,并且考虑到您需要支持i.a. IE9,您还需要一个脚本/后备来完成此任务。

由于Flexbox无法做到这一点,动态(需要固定高度或脚本),绝对最简单和最容易维护的解决方案,是保持包装器,只需简单地来回移动元素脚本。

结合脚本向body添加一个类,我们可以使用CSS来控制元素。

注1;为了使其更加动态,可以优化脚本并利用例如元素的一个set属性,它应该放在哪里,虽然我没有在这里走得那么远。

注2;该脚本根据方向切换布局,但可以更新为使用宽度。

注3; resize事件使用了我最初found at MDN的限制器,以避免昂贵的操作,例如DOM修改。

Stack snippet

(function(d, timeout) {

  function resizing() {
    if (window.innerHeight < window.innerWidth) {
      if (!(d.body.classList.contains('landscape'))) {
        d.body.classList.add('landscape');
        var target = d.querySelector('.right.col');
        target.appendChild(d.querySelector('.b4'));
        target.appendChild(d.querySelector('.b5'));
        target.appendChild(d.querySelector('.b6'));
        target.appendChild(d.querySelector('.b7'));
      }
    } else {
      if (d.body.classList.contains('landscape')) {
        d.body.classList.remove('landscape')
        var target = d.querySelector('.left.col');
        target.insertBefore(d.querySelector('.b4'), d.querySelector('.b2'))
        target.insertBefore(d.querySelector('.b5'), d.querySelector('.b3'))
        target.appendChild(d.querySelector('.b6'));
        target.appendChild(d.querySelector('.b7'));
      }
    }
  }

  /* event handlers */
  window.addEventListener("load", function() {
    resizing();
  }, false);

  window.addEventListener("resize", function() {
    if (!timeout) {
      timeout = setTimeout(function() {
        timeout = null;
        resizing();
      }, 66);
    }
  }, false);

}(document));
.box {
  padding: 1em;
  border: 1px solid black;
  margin: 3px;
}

.left.col {
  float: left;
  width: 100%;
}
.landscape .left.col {          /*  added rule  */
  width: 70%;
}

.right.col {
  float: right;
  width: 30%;
}

.b1 {
  background-color: red;
  height: 150px;
}

.b2 {
  background-color: green;
  height: 80px;
}

.b3 {
  background-color: blue;
  height: 80px;
}

.b4 {
  background-color: yellow;
  height: 40px;
}

.b5 {
  background-color: purple;
  height: 30px;
}

.b6 {
  background-color: cyan;
  height: 40px;
}

.b7 {
  background-color: orange;
  height: 40px;
}
<div class="boxes">
  <div class="left col">
    <div class="box b1">1</div>
    <div class="box b2">2</div>
    <div class="box b3">3</div>
  </div>
  <div class="right col">
    <div class="box b4">4</div>
    <div class="box b5">5</div>
    <div class="box b6">6</div>
    <div class="box b7">7</div>
  </div>
</div>

答案 2 :(得分:0)

嵌套flexbox似乎可行,但我不确定在这个SO嵌入式HTML引擎中调试响应模式。看起来像下面的东西应该这样做。基本上是3个flexbox,其中外部flexbox在行和列/ 100%宽度之间切换...

.boxes{
display:flex;

justify-content:center;
align-content:center;
align-items:center;
}

.col{
display:flex;
flex-flow: column nowrap;
justify-content:center;
align-content:center;
align-items:center;
}

.left{
flex: 0 1 auto;
min-width: 70%;
}
.right{
flex: 0 1 auto;
align-self:flex-start;
min-width: 30%;
}

.box{
flex: 0 1 auto;
min-width:100%
}


.b1{ background-color: red; height: 150px;}
.b2{ background-color: green; height: 80px;}
.b3{ background-color: blue; height: 80px;}
.b4{ background-color: yellow; height: 40px;}
.b5{ background-color: purple; height: 30px;}
.b6{ background-color: cyan; height: 40px;}
.b7{ background-color: orange; height: 40px;}

@media screen (max-width: 639px) {
.boxes{
flex-flow: column nowrap;
}
.left{
min-width: 100%;
}
.right{
min-width: 100%;
}
}
@media screen (min-width: 640px) {
.boxes{
flex-flow: row nowrap;
}
}
   
<div class="boxes">
<div class="left col">
    <div class="box b1">1</div>
    <div class="box b2">2</div>
    <div class="box b3">3</div>
</div>
<div class="right col">
    <div class="box b4">4</div>
    <div class="box b5">5</div>
    <div class="box b6">6</div>
    <div class="box b7">7</div>
</div>
</div>