19

I am trying to achieve the following:


My first attempt was to use a helper div (green):

JSFiddle

What I could do here, is using JavaScript to move the puple and orange elements out of the helper on mobile screens. But there has to be a plain css way.


My second attempt was to remove the helper and build the Mobile Layout:

JSFiddle


Is there a way to place two elements on top of each other in flex-direction: row? (second attempt)

Marc
  • 3,683
  • 8
  • 34
  • 48
  • 1
    No, not really, that's why we have column layout. CSS can sort of do this *with* the helper using `display:contents` but its only supported by FF. – Paulie_D Aug 02 '16 at 19:57
  • 1
    Is there any reason you have to use flexbox? It could be done with traditional positioning. – 4castle Aug 02 '16 at 20:00
  • 1
    I think that responsive css and traditional positioning will work well for what you need to do. – Taylor Aug 02 '16 at 20:02
  • @Paulie_D: Okay, didn't know `display: contents` before. Definitely something to watch. @4castle: I don't actually have to use flexbox. I was using it a lot lately and intuitively tried to do this with it as well. @Taylor: Thanks, I probably was a bit too focussed on that shiny flexbox stuff :) – Marc Aug 02 '16 at 20:06

3 Answers3

10

You could do this with Flexbox but you need to use fixed height on flex container. Here is Fiddle

Basically you use flex-wrap: wrap with flex-direction: column and make first item take 100% height and set width in %. Then you change order with media queries and height.

* {
  box-sizing: border-box;
}
main,
div {
  display: flex;
  padding: 1rem;
}
.desktop {
  flex-direction: column;
  flex-wrap: wrap;
  height: 400px;
  width: 100%;
}
div {
  flex: 1;
  width: 30%;
}
[orange] {
  background-color: #FFAD77;
  flex: 0 0 70%;
}
[yellow] {
  background-color: #FFE377;
  flex: 0 0 100%;
  width: 70%;
}
[purple] {
  background-color: #FF77C8;
}
@media(max-width: 480px) {
  .desktop div {
    flex: 1;
    width: 100%;
  }
  div[orange] {
    order: -1;
    flex: 2;
  }
  div[yellow] {
    flex: 5;
  }
  div[purple] {
    flex: 1;
  }
}
<div class="desktop">
  <div yellow>lorem</div>
  <div orange>lorem</div>
  <div purple>lorem</div>
</div>
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • 2
    This does not answer the question.. *"Is there a way to place two elements on top of each other in flex-direction: **row**"* – Paulie_D Aug 02 '16 at 20:07
  • yes if the sum of their width greater than the widht of the parent and the parent has flex-wrap: wrap – Marouen Mhiri Aug 02 '16 at 20:08
  • I guess this is as far as you can get with rows https://jsfiddle.net/89z21rq3/10/ – Nenad Vracar Aug 02 '16 at 20:32
  • Sometimes I will probably have to take no as an answer. And as there are very good alternatives, I willingly do in this case :) Thanks for your efforts. – Marc Aug 02 '16 at 20:39
3

No, but the alternative isn't deadly. If you use absolute positioning, you will have much more control over the layout at different screen sizes.

function toggleLayout() {
  document.querySelector('main').classList.toggle('mobile');
}
main {
  position: relative;
  width: 600px;
  height: 400px;
}

main div {
  position: absolute;
  top: 0; bottom: 0;
  left: 0; right: 0;
}

main.mobile div {
  position: static;
  width: 100%;
  height: 33.3%;
}

[orange] {
  background-color: #FFAD77;
  bottom: 40%;
  left: 66.6%;
}

[yellow] {
  background-color: #FFE377;
  right: 33.3%;
}

[purple] {
  background-color: #FF77C8;
  top: 60%;
  left: 66.6%;
}
<main>
  <div orange></div>
  <div yellow></div>
  <div purple></div>
</main>
<button onclick="toggleLayout()">toggleLayout</button>
4castle
  • 32,613
  • 11
  • 69
  • 106
3

The problem is that if you use a helper wrapper, then you will only be able to reorder the items inside it, but not mix them with their uncles.

And if you don't use a helper wrapper, you need a column layout. And the only widely supported way to break columns is hardcoding a height to the contaner, as Nenad Vracar suggested. But sometimes you can't do that.

I will suggest two better alternatives, but they have poor support (basically, Firefox):

  • Use a helper wrapper for desktop and get rid of it with display: contents in mobile

    document.querySelector('button').addEventListener('click', function() {
      document.querySelector('main').classList.toggle('mobile');
    });
    main {
      display: flex;
      width: 600px;
      height: 400px;
    }
    .wrapper {
      display: flex;
      flex-direction: column;
    }
    div {
      flex: 1;
    }
    [data-color=orange] {
      background-color: #FFAD77;
    }
    [data-color=yellow] {
      background-color: #FFE377;
    }
    [data-color=purple] {
      background-color: #FF77C8;
      order: 3;
    }
    main.mobile {
      flex-direction: column;
    }
    main.mobile .wrapper {
      display: contents;
    }
    main.mobile [data-color=orange] {
      order: -1;
    }
    <main>
      <div data-color="yellow"></div>
      <div class="wrapper">
        <div data-color="orange"></div>
        <div data-color="purple"></div>
      </div>
    </main>
    <button>toggleLayout</button>
  • Use forced line breaks

    document.querySelector('button').addEventListener('click', function() {
      document.querySelector('main').classList.toggle('mobile');
    });
    main {
      display: flex;
      flex-flow: column wrap;
      width: 600px;
      height: 400px;
    }
    div {
      flex: 1;
    }
    [data-color=orange] {
      background-color: #FFAD77;
      page-break-after: always;
      break-after: always;
    }
    [data-color=yellow] {
      background-color: #FFE377;
    }
    [data-color=purple] {
      background-color: #FF77C8;
      order: 3;
    }
    main.mobile {
      flex-wrap: nowrap;
    }
    main.mobile [data-color=orange] {
      order: -1;
    }
    <main>
      <div data-color="yellow"></div>
      <div data-color="orange"></div>
      <div data-color="purple"></div>
    </main>
    <button>toggleLayout</button>
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • 1
    Well that's neat, but as you said something that is probably a possible solution for the future :) Thanks – Marc Aug 03 '16 at 14:29