14

I have looked into Flexbox to achieve a responsive layout like pictured below. Unfortunately I still have not figured out how to achieve a desktop layout like Figure 1 which rearranges itself to Figure 2 on viewports smaller than 414 pixel.

Figure 1 (desktop viewports)

Desktop version of the layout

Figure 2 (mobile viewports)

Mobile (less than 414px wide) version of the layout (scaled version)

Click here for image in original size

My code so far :

.flexbox {
  display: -webkit-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  flex-wrap: wrap;
  width: 100%;
  margin: 0;
  flex-direction: row;
}
.content-flexbox.one {
  flex-basis: calc(66% - 1rem);
  order: 2;
}
.content-flexbox.two {
  flex-basis: calc(30% - 1rem);
  order: 1;
}
.content-flexbox.three {
  order: 3;
}
.content-flexbox.four {
  order: 4;
}
.content-flexbox {
  margin: 1rem;
  -webkit-box-flex: 1;
  -webkit-flex: 1;
  -ms-flex: 1;
  flex: 1;
}
@media only screen and (max-width: 959px) {
  .flexbox {
    -flex-direction: column;
    padding-top: 1rem;
  }
  .content-flexbox {
    margin: 1rem;
    flex: 1;
    flex-basis: 100%;
  }
  .content-flexbox.one {
    flex-basis: 100%;
    order: 1;
  }
  .content-flexbox.two {
    flex-basis: 100%;
    order: 2;
  }
}
<div class="flexbox">
  <div class="content-flexbox one">
    <h1 class="posttitle">Lorem ipsum</h1>
    <h2 class="subtitle">dolor sit amet</h2>
  </div>
  <div class="content-flexbox two">
    <img src="http://placehold.it/300x300" />
  </div>
  <div class="content-flexbox three">
    <span>Lorem ipsum dolor</span>
  </div>
  <div id="container-voting" class="content-flexbox four">
    <div class="inner-container set">
      <span>Lorem ipsum dolor</span>
    </div>
    <div class="inner-container get">
      <span>Lorem ipsum dolor</span>
    </div>
  </div>
</div>

My question

Is this even possible with flexbox? Is there a better alternative more suited for this layout?

web-tiki
  • 99,765
  • 32
  • 217
  • 249
Marco
  • 181
  • 1
  • 1
  • 8
  • Please embed small images directly in your question. You can edit your question by clicking on the **edit** link just below the question. Follow the MarkDown given in the edit window. – Martin Zabel Feb 23 '16 at 10:14
  • @Paulie_D Added my code so far. – Marco Feb 23 '16 at 10:38
  • @MartinZabel stackoverflow tells me that I cannot use inline images yet. – Marco Feb 23 '16 at 10:39
  • 1
    I've taken a quick look and my inclination is to say NO (not right now)...You'd need nested flexboxes to achieve some of that and then unwrap them at certain viewports. `display:contents` would solve some of this but it's not here yet....but I'll keep thinking....hmmm, perhaps using flex columns? – Paulie_D Feb 23 '16 at 10:41
  • I tried changing the flex-direction to 'column' for small viewports. This enables me to arrange the items as shown in figure 2, but I still cannot arrange the items as shown in figure 1 for desktop viewports with my current HTML / CSS. – Marco Feb 23 '16 at 10:48
  • Embedding images might require a higher reputation. I have embedded the images for you. If you don't like it, then rollback the edit. You will find a link below your question. – Martin Zabel Feb 23 '16 at 11:18
  • @MartinZabel Yes, you are right. I need a higher reputation for embedding images. So thank you for fixing them for me. I hope this makes things more clear at a glance – Marco Feb 23 '16 at 11:31
  • @wntrmt - Were you able to figure out how to achieve it? – Sunny R Gupta Aug 26 '16 at 10:31
  • @SunnyRGupta, do you require a solution with pure css? – Dekel Aug 29 '16 at 10:55
  • @Dekel, yes please. It would be pretty straightforward with JS involved. – Sunny R Gupta Aug 29 '16 at 11:21

5 Answers5

4

You’re looking for the experimental grid syntax. Flexbox is good for smaller, widget or component layout systems. Grid is for overall page layout, and it’s awesome.

Thing is, grid is only supported in IE, Edge, and the upcoming Safari browsers right now, but Firefox and Chrome support is allegedly just around the corner, and you can start trying it out today by enabling the right developer flag in those browsers.

Here is some sample code, but again, it will only work if your browser supports the new grid syntax.

*{
  box-sizing: border-box;
}

.flexbox{
  width: 320px;
  display: grid;
  grid-template-columns: calc(50% - 0.5ch) calc(50% - 0.5ch);
  grid-gap: 1ch;
}

.one{
  order: 2;
  background-color: red;
}

.two{
  grid-column: 1 / 3;
  order: 1;
  background-color: green;
}

.three{
  order: 3;
  background-color: pink;
}

.four{
  display: grid;
  grid-column: 1 / 3;
  grid-gap: 1ch;
  order: 4;
  background-color: lavender;
}

.inner-container{
  background-color: violet;
}

@media screen and (min-width: 500px){
  .flexbox{
    width: 500px;
    grid-template-columns: calc(33.333% - 0.333ch) calc(33.333% - 0.333ch) calc(33.333% - 0.333ch);
  }
  
  .one{
    grid-row: 1 / 3;
    order: 1;
  }
  
  .two{
    order: 2;
    grid-column: 2 / 4;
  }
  
  .three{
    order: 3;
  }
  
  .four{
    grid-column: 3 / 4;
    order: 4;
  }
}
<div class="flexbox">
<div class="content-flexbox one">
    <h1 class="posttitle">Lorem ipsum</h1>
    <h2 class="subtitle">dolor sit amet</h2>
</div>
<div class="content-flexbox two">
    <img src="http://placehold.it/300x300" />
</div>
<div class="content-flexbox three">
    <span>Lorem ipsum dolor</span>
</div>
<div id="container-voting" class="content-flexbox four">
    <div class="inner-container set">
        <span>Lorem ipsum dolor</span>
    </div>
    <div class="inner-container get">
        <span>Lorem ipsum dolor</span>
    </div>
</div>
Ragdoll
  • 335
  • 1
  • 8
  • 3
    CSS grid layout is now supported by all [major browsers](https://caniuse.com/#search=grid), so I will accept this answer as the correct one. Thank you! – Marco Nov 21 '18 at 16:15
3

Although this question explicitly asked for a flexbox approach, there is another way to achive it using simple floats.
A media query allows to rearange the elements in the desired order on viewports less than 414px wide:

.wrap {
  background: #d0d0d0;
  padding: 1%;
}
.wrap:after {
  content: '';
  display: block;
  clear: both;
}
.el {
  float: left;
  margin: 1%;
}
.el1 {
  width: 31.33%;
  padding-bottom: 31.33%;
  background: #FF7676;
}
.el2 {
  float: right;
  width: 64.66%;
  padding-bottom: 14.66%;
  background: #C2FF76;
}
.el3 {
  width: 31.33%;
  padding-bottom: 14.66%;
  background: #FF9BF7;
}
.el4 {
  width: 31.33%;
  padding-bottom: 6.33%;
  background: #9BA4FF;
}
@media (max-width: 414px) {
  .el2, .el4 {
    width: 98%;
    padding-bottom: 31.33%;
  }
  .el1, .el3 {
    width: 48%;
    padding-bottom: 48%;
  }
}
<div class="wrap">
  <div class="el el2"></div>
  <div class="el el1"></div>
  <div class="el el3"></div>
  <div class="el el4"></div>
  <div class="el el4"></div>
</div>

Note that I used padding-bottom to keep the aspect ratio of the elements in this example (more info in this answer).
I don't know what content you intend to put in the blocks but you will need to use absolute positionnig for it if you want to stick with the "padding technique". For plain text content, you can check this fiddle.

Community
  • 1
  • 1
web-tiki
  • 99,765
  • 32
  • 217
  • 249
  • It is going to be free flowing content (like plain-text). – Sunny R Gupta Aug 29 '16 at 13:31
  • @SunnyRGupta Do the elements need to keep their aspect ratio or are their height defined by the content? – web-tiki Aug 29 '16 at 13:35
  • They are going to be defined by the content. Only width can be fixed in percentages. – Sunny R Gupta Aug 29 '16 at 17:23
  • @SunnyRGupta that will be very hard if not impossible. How will you keep layout consistency (like the bottom alignment of the elements) without constraining the height of elements in some way? – web-tiki Aug 30 '16 at 13:13
  • It's not more about the bottom alignment that the order. I'm fine with boxes of variable height and not stacking perfectly. But the issue is getting 1 to fall below 2 on mobile and stay on the side in desktop. – Sunny R Gupta Aug 31 '16 at 06:44
  • Good ol Floats :) Well, since there are no answers using flex and your answer is the only one close to what is expected. (Without JS) I'm granting the bounty. Thanks for the help. – Sunny R Gupta Aug 31 '16 at 07:51
  • The only downside of floats is that the items won't stretch to have consistent sizes. You must hardcode heights to make it look nice, but then it's not fluid. – Oriol Aug 31 '16 at 11:32
1

The problem is that, if you want to be able to rearrange all items, they must be flex items of the same flex container. But Flexbox does not provide any direct way to make an element occupy more than one flex line.

However, you can use multiple containers and display: contents:

The element itself does not generate any boxes, but its children and pseudo-elements still generate boxes as normal. For the purposes of box generation and layout, the element must be treated as if it had been replaced with its children and pseudo-elements in the document tree.

/* Desktop */
.container {
  display: flex;
  flex-wrap: wrap;
}
.container > * {
  flex-grow: 1;
}
.item {
  margin: 2px;
}
.column {
  flex-direction: column;
}
.fill {
  width: 100%;
}
/* Mobile */
@media (max-width: 414px) {
  .container > .container {
    display: contents;
  }
  .i2 {
    order: -1;
  }
  .i4 {
    width: 100%;
  }
}
/* Pretty */
.i1 { background: #FF7676; }
.i2 { background: #C2FF76; }
.i3 { background: #FF9BF7; }
.i4 { background: #9BA4FF; }
<div class="container">
  <div class="item i1">1</div>
  <div class="container">
    <div class="item i2 fill">2</div>
    <div class="item i3">3</div>
    <div class="container column">
      <div class="item i4">4a</div>
      <div class="item i4">4b</div>
    </div>
  </div>
</div>

The only problem is that display: contents is not widely supported yet, but you can see it working on Firefox.

Oriol
  • 274,082
  • 63
  • 437
  • 513
0

I don't think this is possible to do with pure css, but you could use some js and change html structure on resize with wrapAll() and unwrap(). You also need to use media queries to change order and some css when window is < 414px.

$(window).on("resize", function() {
  var windowW = $(window).width();

  if (windowW < 414) {
    if ($('.right, right-inner').length) $('.two, .four').unwrap();
    if (!$('.top').length) $('.one, .two, .three').wrapAll('<div class="top"></div>');
  } else {
    if ($('.top').length) $('.one, .two, .three').unwrap();
    if (!$('.right, .right-inner').length) {
      $('.three, .four').wrapAll('<div class="right-inner"></div>');
      $('.two, .right-inner').wrapAll('<div class="right"></div>');
    }
  }
}).resize();
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
body,
html {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
}
.flexbox {
  display: flex;
  min-height: 100vh;
  color: white;
  font-size: 50px;
}
.one {
  flex: 1;
  background: #FF7676;
  margin: 10px;
}
.right {
  flex: 2;
  display: flex;
  flex-direction: column;
  margin: 10px;
}
.two {
  height: 40%;
  display: flex;
  margin-bottom: 20px;
  margin-right: 10px;
}
.two img {
  width: 100%;
  margin: 0;
}
.right-inner {
  display: flex;
  flex: 2;
}
.three,
.four {
  flex: 1;
}
.three {
  background: #FF9BF7;
  margin-right: 10px;
}
.four {
  display: flex;
  flex-direction: column;
}
.set,
.get {
  background: #9BA4FF;
  flex: 1;
  margin: 5px;
}
.set {
  margin-top: 0;
}
.get {
  margin-bottom: 0;
}
@media(max-width: 414px) {
  .flexbox {
    flex-direction: column;
  }
  .flexbox > * {
    flex: 1;
    margin: 10px;
  }
  .get,
  .set {
    margin: 0;
    margin-bottom: 10px;
  }
  .two {
    order: -1;
    flex: 0 0 100%;
    margin-bottom: 0;
  }
  .two img {
    height: 100px;
  }
  .one,
  .three {
    width: 50%;
    margin: 0;
  }
  .one {
    margin-right: 10px;
  }
  .top {
    display: flex;
    flex-wrap: wrap;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<div class="flexbox">
  <div class="content-flexbox one">
    <span class="posttitle">1</span>
  </div>
  <div class="right">
    <div class="content-flexbox two">
      <img src="http://placehold.it/300x300/C2FF76" />
    </div>

    <div class="right-inner">
      <div class="content-flexbox three">
        <span>3</span>
      </div>
      <div id="container-voting" class="content-flexbox four">
        <div class="inner-container set">
          <span>4a</span>
        </div>
        <div class="inner-container get">
          <span>4b</span>
        </div>
      </div>
    </div>
  </div>
</div>
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
-1

I see that you can make two containers with floats and like mentioned before use liquid style page with width %. If you aproche mobile viewport use media querys to declair breakpoints.

MrVitaminasG
  • 5
  • 1
  • 5