5

I have a responsive website with a two-column layout in large browser windows. The two-column layout is currently implemented using float. On smaller screens I'd like to have just one column. The content of the other column should be displayed between the two elements of the main column, like shown here:

mockup

<div class="two-columns">
  <div class="main-column">
    <div class="red-element"></div>
    <div class="yellow-element"></div>
  </div>
  <div class="sidebar-column">
    <div class="green-element"></div>
  </div>
</div>

I tried using a flex-box-based approach, basically the one described in this question, but flex-basis still seems to be unsupported in Safari when flex-direction is column. Proper Safari support is a must as Safari is the main browser of my visitors.

Is there a way this can be achieved using CSS only without having to place the green element twice in my markup?

Community
  • 1
  • 1

4 Answers4

3

Here's a general solution using one flex container:

<div class="container">
    <div class="box"> ... </div><!-- red box -->
    <div class="box"> ... </div><!-- green box -->
    <div class="box"> ... </div><!-- yellow box -->
</div>

Starting with small screens (for no particular reason), stack them in a column:

.container {
    display: flex;
    flex-direction: column;
}

.box {
    height: 100px;
    width: 100%;
}

Re-arrange the layout for wider screens:

@media (min-width: 800px) {

   .container {
        flex-direction: row;
        flex-wrap: wrap;
    }

    .box {
        flex-basis: 45%;
    }
}

On screens wider than 800px, the container lines the items in a row and enables wrapping. Each box is given a large enough width (flex-basis) for only two to fit on a line.


Full demo:

* {
    box-sizing: border-box;
}

.container {
    display: flex;
    flex-direction: column;
    padding: 5px 0;
    background-color: #f5f5f5;
    border: 1px solid #aaa;
}

.box1 { background-color: red; }
.box2 { background-color: lightgreen; }
.box3 { background-color: yellow; }

.box {
    height: 100px;   /* `flex-basis: 100px` would also work */
    width: calc(100% - 20px);
    margin: 5px 10px;
    border: 1px solid #ccc;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 1.2em;
}

@media (min-width: 800px) {
    .container {
        flex-direction: row;
        flex-wrap: wrap;
    }
    .box {
        flex-basis: 45%;
    }
}
<div class="container">
    <div class="box box1"><span>1</span></div>
    <div class="box box2"><span>2</span></div>
    <div class="box box3"><span>3</span></div>
</div>

jsFiddle


From your question:

...but flex-basis still seems to be unsupported in Safari when flex-direction is column

I'm not sure this is correct (caniuse.com).

However, you can always use width or height properties instead of flex-basis (more details: What are the differences between flex-basis and width?).

Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
1

Using Bootstrap,

<div class="row">
    <div class="col-md-8">
        <div class="red-element"></div>
    </div>

    <div class="col-md-4">
        <div class="green-element"></div>
    </div>

    <div class="col-md-8">
        <div class="yellow-element"></div>
    </div>
    <div class="clearfix"></div>
</div>

This uses float methods and works on all browsers.

Giri
  • 565
  • 2
  • 9
0

you should using @media via margin-top.on specific screen width (via @media), change margin-top of the green-element to -200%. and change margin-top of yellow-element to 100%.they change their position very nice :) please see this link:

http://jsbin.com/xozeviseka/edit?html,output

  • Media queries are definitely necessary, but using the float-based implementation I can only place the green element above the red element or below the yellow one. –  May 01 '16 at 13:28
  • i complete my answer. so please see my answer again. – farhad goodarzi May 01 '16 at 14:15
0

You need to change some html structure so then you can do this.

*,*:after,*:before {
 box-sizing:border-box;
}
.two-columns {
 position:relative;
 background:#EFEFEF;
 border:1px solid #000;
}
.red-element,
.green-element,
.yellow-element {
 margin-bottom:30px;
}
.red-element {
 height:70px;
 background:#FF0004;
}
.green-element {
 height:70px;
 background:#7ED321;
}
.yellow-element {
 height:100px;
 background:#F8E71C;
}
@media (min-width:767px) {
 .main-column {
  width:70%;
  padding:10px;
 } 
 .sidebar-column {
  position:absolute;
  right:0;
  top:0;
  width:30%;
  padding:10px;
 }
}
<div class="two-columns">
    <div class="main-column">
        <div class="red-element"></div>
            <div class="sidebar-column">
                <div class="green-element"></div>
            </div>
        <div class="yellow-element"></div>
    </div>
</div>

Or if you don't want to change html structure you have to take another element that only show in mobile for example

*,*:after,*:before {
 box-sizing:border-box;
}
.two-columns {
    background: #EFEFEF;
    border: 1px solid #000;
    overflow: hidden;
}
.red-element,
.green-element,
.yellow-element {
 margin-bottom:30px;
}
.red-element {
 height:70px;
 background:#FF0004;
}
.green-element {
 height:70px;
 background:#7ED321;
}
.yellow-element {
 height:100px;
 background:#F8E71C;
}
.hideMobile{
 display:none;
}
@media (min-width:767px) {
 .main-column {
  width: 70%;
  float: left;
  padding: 10px;
 }
 
 .sidebar-column {
  float: right;
  width: 30%;
  padding: 10px;
 } 
 .showMobile {
  display:none;
 }
 .hideMobile {
  display:block;
 }
}
<div class="two-columns">
  <div class="main-column">
    <div class="red-element"></div>
    <div class="green-element showMobile"></div><!--only for mobile-->
    <div class="yellow-element"></div>
  </div>
  <div class="sidebar-column hideMobile"><!--hide in mobile-->
    <div class="green-element"></div>
  </div>
</div>
Ismail Farooq
  • 6,309
  • 1
  • 27
  • 47