6

Is there a way to get 2 column layout that is transformed to a 1 column layout with a media query?

Conditions for 2 column layout:

  1. items should flow one after another within columns
  2. items within columns will have different heights
  3. item position (order) can be imposed by html markup element position

Conditions for 1 column layout:

  1. items should flow one after another
  2. items within columns will have different heights
  3. item position (!) cannot be imposed by html markup (should be controlled over css)

layout visualization

I have been considering two separate containers for columns - but that construct blocks me for reordering (mix) elements between columns when layout becomes 1 column. I seems that all elements should be placed within one container - then for 1 column layout flex can be used for reordering, but how to achieve 2 column layout in that case?

To simulate media query behaviour remove class "one-column" from main container.

<div id="container" class="one-column"> -> <div id="container" class="">

In this concept the main problem is that items within columns (2 column layout) are not flowing directly one after another (there are gaps between items in the right column).

Here's what I achieved so far:

* {
  box-sizing: border-box;
}
div {
  width: 100%;
  height: 100px;
  float: left;
}
#container.one-column {
  display: flex;
  flex-direction: column;
  height: auto;
}
#container {
  display: block;
}
.col1 {
  width: 60%;
  background-color: red;
  height:300px;
  float: left;
}
.col2 {
  width: 40%;
  background-color: blue;
  border: 1px solid white;
  float: right;
}
.one-column > div {
  width: 100%;
}
<div id="container" class="one-column">
  <div class="col1" style="order:2;">
    ONE
  </div>
  <div class="col2" style="order:1;">
    TWO
  </div>
  <div class="col1" style="order:4;">
    THREE
  </div>  
  <div class="col2" style="order:3;">
    FOUR
  </div>
</div>

JSFiddle: https://jsfiddle.net/3b6htt1d/40/

TylerH
  • 20,799
  • 66
  • 75
  • 101
IT Man
  • 933
  • 3
  • 12
  • 33
  • Yes. It's possible. Have you tried coding it yourself? If so, please post your code. Otherwise, your question will likely be closed because Stack Overflow is not a free code writing service. – Michael Benjamin Feb 24 '18 at 23:05
  • Do you really want a3 to show above a2 in your one-column layout? Or is that a mistake in your illustration? – TylerH Feb 24 '18 at 23:42
  • @TylerH more important is to be able to put b* items anywhere between a* items. Changing a* positions is less crucial, but it would be nice to. – IT Man Feb 24 '18 at 23:48
  • @ITMan I'm a little confused, what is it that you are wanting to cause a position change? It sounds like you want it to change dynamically (otherwise you would just write the code to position it exactly how you want it), but I don't see where you specify that in one case, B2 is in a given order, and then in another case, B2 is in a different order (for example). – TylerH Feb 24 '18 at 23:50
  • @TylerH i would like to set/change item order for particular resolution (mobile). For "deskop" i have 2 column layout - lets assume items order results from html element order. But when i change to "mobile" i have 1 column layout and items should appear in order different then html markup. – IT Man Feb 25 '18 at 00:02
  • This may provide you with some guidance: https://stackoverflow.com/q/44377343/3597276 – Michael Benjamin Feb 25 '18 at 00:36
  • Thanks very much for your engagement. I'll will study this post! – IT Man Feb 25 '18 at 00:41
  • @ITMan I see, so you just want two specific layouts and not more. In that case basic flexbox layout and the use of the `order` property should suffice for what you seem to be asking for. – TylerH Feb 25 '18 at 01:52
  • @TylerH - right - easy to say, harder to be done :) – IT Man Feb 26 '18 at 06:22
  • You got 2 good answers, one w/o script and one with. Did we miss anything or they simply weren't useful enough? – Asons Mar 05 '18 at 06:43
  • Well, probably i wont use any of this answers. I can pick one which has closest effect. – IT Man Mar 06 '18 at 13:42
  • What's the point posting a question and then not communicate how the given answer doesn't fully solve the expected outcome? ... We know how to achieve almost any possible layout and with which tech. it will take, so why not take advantage of that instead of randomly pick an answer because you were asked too? – Asons Mar 06 '18 at 16:33
  • Both those answers are good enough but have some disadvantages. The chosen one is closest to my needs. Can you post better solution? – IT Man Mar 06 '18 at 16:49
  • Here is a demo (which I also updated my answer with), that reproduce the exact layout your screen shot shows: https://codepen.io/anon/pen/eVqZRg – Asons Mar 06 '18 at 19:45

2 Answers2

4

Conditions for 2 column layout:

  1. items should flow one after another within columns
  2. items within columns will have different heights
  3. item position (order) can be imposed by html markup element position

That is exactly what CSS Columns does.

Conditions for 1 column layout:

  1. items should flow one after another
  2. items within columns will have different heights
  3. item position (!) cannot be imposed by html markup (should be controlled over css)

That is exactly what one can do with Flexbox and column direction.


So if one combine the two, for 2 columns they will, as shown in the left image sample, flow from top to bottom, and for 1 columns, you can control their position with order.

With this you avoid fixed heights and get dynamic/flexible sized items.

Updated fiddle

Stack snippet

* {
  box-sizing: border-box;
}
div {
  width: 100%;
  height: 100px;
}
#container.one-column {
  display: flex;
  flex-direction: column;
  height: auto;
}
.col1 {
  width: 60%;
  background-color: red;
  height:300px;
}
.col2 {
  width: 40%;
  background-color: blue;
  border: 1px solid white;
}
.one-column > div {
  width: 100%;
}

@media (min-width: 500px) {
  #container.one-column {
    display: block;
    columns: 2;
  }
  #container.one-column > div {
    -webkit-column-break-inside: avoid;
    page-break-inside: avoid;
    break-inside: avoid;
  }
  .zcol1 ~ .col1 {
    background-color: yellow;
    height:100px;
  }
}
<div id="container" class="one-column">
  <div class="col1" style="order:2;">
    ONE
  </div>
  <div class="col2" style="order:1;">
    TWO
  </div>
  <div class="col1" style="order:4;">
    THREE
  </div>  
  <div class="col2" style="order:3;">
    FOUR
  </div>
</div>

Here is another answer of mine, that might be another option, combining Flexbox with float.


Updated based on a comment

Here is a version combining Flexbox and float, which produce the layout your screen shot shows:

Asons
  • 84,923
  • 12
  • 110
  • 165
0

You 2 column layout should also made using flex.

The only real problem is forcing a wrap at the point that you want it to be.

The best approach is where you can set a definite height to the container. In this case, forcing the wrap can be done with a pseudo element:

* {
  box-sizing: border-box;
}
div {
  width: 100%;
  height: 100px;
  border: 1px solid white;
}
.container {
  display: flex;
  flex-direction: column;
  height: auto;
  margin-top: 5px;
}
.col1 {
  width: 60%;
  background-color: red;
  height:300px;
}
.col2 {
  width: 40%;
  background-color: blue;
}
.one-column > div {
  width: 100%;
}
.two-column {
    flex-wrap: wrap;
    max-height: 800px;
}
.two-column:after {
    content: "";
    width: 10px;
    height: 10px;
    background-color: yellow;
    order: 2;
    margin-top: 1000px;
}
.two-column .col1 {
    order: 1;
}
.two-column .col2 {
    order: 3;
}
<div class="container two-column">
  <div class="col1">
    ONE
  </div>
  <div class="col2">
    TWO
  </div>
  <div class="col1">
    THREE
  </div>  
  <div class="col2">
    FOUR
  </div>
</div>
<div class="container one-column">
  <div class="col1">
    ONE
  </div>
  <div class="col2">
    TWO
  </div>
  <div class="col1">
    THREE
  </div>  
  <div class="col2">
    FOUR
  </div>
</div>
vals
  • 61,425
  • 11
  • 89
  • 138
  • at first sight this seems to be right solution. I have to check this layout behavior in details. Thanks for help. – IT Man Feb 26 '18 at 06:16
  • thats a clever trick with that pseudo element! As i understand i can also calculate pseudo height / margin with javascript if there will be no other choice? – IT Man Feb 26 '18 at 06:57
  • Really, what you need to calculate, at runtime or beforehand, is the container height. The pseudo element height just needs to be greater than this, to force the wrap. – vals Feb 26 '18 at 18:42