Salman Arshad
Salman Arshad

Reputation: 272116

Change layout of elements using CSS without changing HTML

I have HTML markup that consists of three divs:

<div class="gallery">Gallery</div>
<div class="content">Content</div>
<div class="sidebar">Sidebar</div>

I want to present it in two different layouts using CSS (would be nicer if I could control whether the sidebar appears on left or right):

+------------------+
| Gallery          |
+------+-----------+
| Side | Content   |
|      |           |
+------+-----------+

+------+-----------+
| Side | Gallery   |
+      +-----------+
|      | Content   |
|      |           |
+------+-----------+

In fact, it would be nicer if I could control whether the sidebar appears on left or right.

I can add additional divs and/or change the source order of divs as long as content appears before sidebar. But the HTML cannot be changed on per-layout basis.

Here is my incomplete attempt to solve the problem using flexbox + order property.

/* for demonstration */
.gallery { height: 100px; background-color: #CCC;  }
.content { height: 200px; background-color: #EEE; }
.sidebar { height: 150px; background-color: #AAA; }
/* common */
.middle { display: flex; flex-direction: row; flex-wrap: wrap; }
/* layout-1 */
.middle.layout-1 .gallery { order: 1; width: 100%; }
.middle.layout-1 .content { order: 3; width:  75%; }
.middle.layout-1 .sidebar { order: 2; width:  25%; }
/* layout-2 */
.middle.layout-2 .gallery { order: 2; width: 75%; }
.middle.layout-2 .content { order: 3; width: 75%; }
.middle.layout-2 .sidebar { order: 1; width: 25%; }
<div class="middle layout-1">
  <div class="gallery">Gallery</div>
  <div class="content">Content (this layout works perfectly)</div>
  <div class="sidebar">Sidebar</div>
</div>
<hr>
<div class="middle layout-2">
  <div class="gallery">Gallery</div>
  <div class="content">Content (should go below gallery)</div>
  <div class="sidebar">Sidebar</div>
</div>

Upvotes: 9

Views: 3586

Answers (3)

Jamie Barker
Jamie Barker

Reputation: 8246

Normally I avoid floats like the plague, but for this case they do what you need.

If you want to switch the side the sidebar is on, just swap the lefts and rights.

This will keep your layout with dynamic sized content:

.gallery {
  background: red;
}
.content {
  background: green;
}
.sidebar {
  background: blue;
}
/* layout1 */
.layout1 .gallery {
  width: 100%;
}
.layout1 .content {
  width: 75%;
  float: right;
}
.layout1 .sidebar {
  width: 25%;
  float: left;
}
/* layout2 */
.layout2 .gallery {
  width: 75%;
  float: right;
}
.layout2 .content {
  width: 75%;
  float: right;
}
.layout2 .sidebar {
  width: 25%;
}
<div class="layout1">
  <div class="gallery">Gallery</div>
  <div class="content">Content</div>
  <div class="sidebar">Sidebar</div>
</div>
<br>
<br>
<br>
<div class="layout2">
  <div class="gallery">Gallery</div>
  <div class="content">Content</div>
  <div class="sidebar">Sidebar</div>
</div>

Upvotes: 3

chatoo2412
chatoo2412

Reputation: 128

Check this demo if you have containing div like .middle.layout-2.

HTML:

<div class="middle layout-1">
  <div class="gallery">Gallery</div>
  <div class="content">Content (this layout works perfectly)</div>
  <div class="sidebar">Sidebar</div>
</div>
<hr>
<div class="middle layout-2">
  <div class="gallery">Gallery</div>
  <div class="content">Content (should go below gallery)</div>
  <div class="sidebar">Sidebar</div>
</div>

CSS:

/* for demonstration */
.gallery { height: 100px; background-color: #CCC;  }
.content { height: 200px; background-color: #EEE; }
.sidebar { height: 200px; background-color: #AAA; }
/* common */
.middle { display: flex; flex-direction: row; flex-wrap: wrap; }
/* layout-1 */
.middle.layout-1 .gallery { order: 1; width: 100%; }
.middle.layout-1 .content { order: 3; width:  75%; }
.middle.layout-1 .sidebar { order: 2; width:  25%; }
/* layout-2 */
.middle.layout-2 { position: relative; }
.middle.layout-2 .gallery { width: 75%; margin-left: 25%; }
.middle.layout-2 .content { width: 75%; margin-left: 25%; }
.middle.layout-2 .sidebar { position: absolute; top: 0; left: 0; width: 25%; height: 100%;}

Upvotes: 5

K K
K K

Reputation: 18099

Let me know if this is what you want:

HTML:

First Layout
<div class="container one">
    <div class="gallery">Gallery</div>
    <div class="sidebar">Sidebar</div>
    <div class="content">Content</div>
</div>
<br/>Second Layout
<div class="container two">
    <div class="gallery">Gallery</div>
    <div class="sidebar">Sidebar</div>
    <div class="content">Content</div>
</div>
<br/>Third Layout
<div class="container three">
    <div class="gallery">Gallery</div>
    <div class="sidebar">Sidebar</div>
    <div class="content">Content</div>
</div>
<br/>

CSS:

html, body {
    width:100%:height:100%:
}
* {
    box-sizing:border-box;
    white-space:nowrap;
}
.container {
    width:500px;
    height:500px;
    position:relative;
}
.container div {
    border:1px solid black;
    padding:20px;
}
/*One*/
 .one.container .sidebar, .one.container .content {
    float:left;
    width:50%;
}
.one.container:after {
    clear:both;
    display:block;
    content:"";
}
/*Two*/
 .two.container .sidebar {
    float:right;
    width:50%;
}
.two.container .content {
    float:left;
    width:50%;
}
.two.container:after {
    clear:both;
    display:block;
    content:"";
}
/*Three*/
 .three.container>div {
    position:absolute;
}
.three.container .gallery {
    top:0;
    left:50%;
    right:0;
    height:50%;
}
.three.container .sidebar {
    top:0;
    left:0;
    bottom:0;
    width:50%;
}
.three.container .content {
    top:50%;
    left:50%;
    right:0;
    height:50%;
    bottom:0;
}

Demo: http://jsfiddle.net/GCu2D/665/

This doesn't have additional div or markup. You need to just toggle the classe in the container.

Upvotes: 1

Related Questions