Jakub Narębski
Jakub Narębski

Reputation: 323752

CSS layout for "2 columns + em-width separator in the middle"

How to get the following layout using HTML + CSS:

|                        |x|                          |
|                        |x|                          |

All three columns (two columns and separator) should be touching, i.e. their background colors have to be touching without any gaps.

The problem I have with creating such layout is that I want the "separator" to have width measured in em (i.e. font-width based), while main contents columns are to fit the rest of width of encompassing element (i.e. around 50%). I want this layout preserved, without the separator overlying left or right contents columns independently on font size (i.e. layout should be preserved if I increase or decrease font width).

Note that this layout is inside other container, and these containers can be repeated in the page. Because of this I was not able to use any absolute-positioning solution.

Also container should not use fixed width: think of it as container having width: 100%; or width: auto; (or unset width).

Bonus points if the layout can be created with either left or right column missing (i.e. empty column).

Upvotes: 7

Views: 5825

Answers (10)

PointedEars
PointedEars

Reputation: 14980

You can always use absolute positioning, but you need to position the common ancestor as well (relative). Flexible multi-column layouts can be done best with floats:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>CSS Test Case: 2-Column Layout with Separator</title>
    <style type="text/css">
      .container {
        position: relative;
        float: left;
        background-color: green;
      }

      .container .left {
        float: left;
        width: 50%;
        background-color: red;
      }

      .container .left .padding {
        margin-right: 5em;
      }

      .container .right {
        float: right;
        width: 50%;
        background-color: fuchsia;
      }

      .container .right .padding {
        margin-left: 5em;
      }

      .container .separator {
        position: absolute;
        left: 50%;
        top: 0;
        width: 10em;
        height: 100%;
        margin-left: -5em;
        background-color: blue;
      }

      div.clearBoth {
        clear: both;
        margin: 0;
        padding: 0;
        height: 0;
        line-height: 0;
        font-size: 0;
        overflow: hidden;
      }
    </style>
  </head>

  <body>
    <h1>CSS Test Case: 2-Column Layout with Separator</h1>
    <div class="container">
      <div class="left">
        <div class="padding">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam nulla dolor, tempor ac sollicitudin malesuada, tempus in metus. Nulla eget augue ut velit ullamcorper aliquam. Aliquam in nibh eu arcu tincidunt eleifend et ac justo. Donec mauris orci, tristique et ornare quis, dictum a ante. Suspendisse rhoncus commodo ligula, ac mattis eros dignissim vitae. Morbi pulvinar ultrices aliquam. Praesent tempus velit justo, eget fringilla leo. Aliquam fringilla risus eget justo ornare pellentesque. Duis ullamcorper scelerisque mauris vitae blandit. Morbi et bibendum orci. Sed vestibulum posuere nisi, vitae rhoncus mi laoreet in. Quisque commodo porttitor risus, id ullamcorper libero gravida at. Donec interdum accumsan blandit. Vestibulum ac eros et nisl fermentum cursus. Integer vitae ornare orci. Vestibulum facilisis adipiscing metus a suscipit.
        </div>
      </div>
      <div class="right">
        <div class="padding">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam nulla dolor, tempor ac sollicitudin malesuada, tempus in metus. Nulla eget augue ut velit ullamcorper aliquam. Aliquam in nibh eu arcu tincidunt eleifend et ac justo. Donec mauris orci, tristique et ornare quis, dictum a ante. Suspendisse rhoncus commodo ligula, ac mattis eros dignissim vitae. Morbi pulvinar ultrices aliquam. Praesent tempus velit justo, eget fringilla leo. Aliquam fringilla risus eget justo ornare pellentesque. Duis ullamcorper scelerisque mauris vitae blandit. Morbi et bibendum orci. Sed vestibulum posuere nisi, vitae rhoncus mi laoreet in. Quisque commodo porttitor risus, id ullamcorper libero gravida at. Donec interdum accumsan blandit. Vestibulum ac eros et nisl fermentum cursus. Integer vitae ornare orci. Vestibulum facilisis adipiscing metus a suscipit.
        </div>
      </div>
      <div class="separator"></div>
    </div>
    <div class="clearBoth"><!-- clear --></div>
  </body>
</html>

Please notice that

  • the background colors are touching as you can see no horizontal green (but see below);
  • container dimensions are irrelevant (it works with any viewport size and any text content; but see below);
  • it works with any font size;
  • it works with any separator width, provided you adjust the margins as well (see below);
  • it works anywhere, and several times, in a document because it uses CSS classes, not IDs;
  • it works if you set display: none on the left column, the right column, or both. As a result, it works if the left column, the right column, or both, are missing from the markup;
  • it uses a minimum set of selectors, properties, and property values, that are all available since CSS1 or CSS2.

Because of the latter, it should also work in all CSS2-capable browsers as it does not rely on any UA-specific implementation. I have tested this positive in the following browsers:

  • Microsoft Internet Explorer 9.0.8112.16421 for Windows 7
  • Google Chrome 16.0.912.41 beta for Debian GNU/Linux
  • Google Chrome 15.0.874.121 m for Windows
  • Chromium 14.0.835.202 (Developer Build 103287 Linux) Built on Debian unstable, running on Debian 6.0.3
  • Mozilla Firefox 8.0.1 for Windows (on Wine)
  • Iceweasel (Debian Firefox) 8.0
  • Mozilla Firefox 7.0.1 for Windows (on Wine)
  • Mozilla Firefox 6.0.2 for Windows (on Wine)
  • Mozilla Firefox 5.0 for Windows (on Wine)
  • Mozilla Firefox 4.0.1 for Windows (on Wine)
  • Mozilla Firefox 3.6.24 for Windows (on Wine)
  • Mozilla Firefox 3.5.19 for Windows (on Wine)
  • Mozilla Firefox 3.0.19 for Windows (on Wine)
  • Iceape (Debian SeaMonkey) 2.0.14
  • Apple Safari 5.0.2 (7533.18.5) for Windows (on Wine)
  • Apple Safari 4.0.5 (531.22.7) for Windows (on Wine)
  • Opera 11.52.1100 for Linux
  • Konqueror 4.6.5 for GNU/Linux (on KDE 4.6.5)
  • Google Android 2.3.4 Browser
  • Dolphin Browser HD 7.1.0 for Android
  • Mozilla Firefox 8.0 for Android
  • Opera Mobile 11.50 for Android
  • Apple Mobile Safari 5.0.2 (6533.18.5) on iOS 4.2.1 (8C148) on iPhone 3G (MB496FD)

It does not work in:

  • Mozilla Firefox 2.0 for Windows (on Wine): Floats are not supported.
  • Mozilla Firefox 1.5.0.12 for Windows (on Wine): Floats are not supported.
  • Mozilla Firefox 1.0.8 for Windows (on Wine): Floats are not supported.
  • Microsoft Internet Explorer 6.0.2800.1106 for Windows 98 (on Wine): The separator is not always displayed, and if the viewport width changes, the layout falls apart. Probably you can work around this with a stylesheet triggered by Conditional Comments. (See also tereško's answer.)

Test case

Explanation:

  1. With floats, you can have columns of 50% width, but you cannot have horizontal margins or paddings on them, because in the W3C (standard) CSS box model the box width equals the width plus horizontal padding. So any (horizontal) paddings must be created by child elements.
  2. In order to have the content of a column end at the separator box's boundaries, you need margin-right and margin-left for the child (DIV) elements within the left and right column half the width of the separator (5em), respectively. padding-right and padding-left might work as well if no further width is involved.
  3. In order to position the separator absolute between the left and right column, the container must be positioned relative. The separator has a negative margin (margin-left: -5em) so that its box shifts left half its width: 10em from the middle (left: 50%).
  4. The container must float: left so that it provides the stacking context for the separator to be displayed on top of the columns (and to always have the correct width). Therefore, you need clear: left before and clear: both after the container (the latter with a zero-height DIV element here).

Caveats:

  1. If the height of the left and right columns differ, you will see vertical green. Use the usual tricks to emulate equal height. (See also tereško's answer.)
  2. If the viewport grows shallower, content in the columns may overflow horizontally if it cannot be wrapped; especially replaced inline elements like images, and long words. Declare an overflow or overflow-x value different from the default (visible) to prevent that.

Update: Validates as HTML 4.01 Strict and CSS2 now; clearing BR as child of BODY, and magenta color name did not, respectively. Also, the position property was introduced with CSS2.

Upvotes: 5

frozenkoi
frozenkoi

Reputation: 3248

Have a look at http://jsfiddle.net/gjQVW/4/

<div class="container">
    <div>left</div>
    <div>right</div>
    <!--div>3rd</div>
    <div>4th</div-->
</div>

With these styles

.container {display: table; width: 100%; margin-left: 0; margin-right: 0; margin-top: 3em; background: red}

.container > DIV {border: 1px dashed red; display: table-cell; width: 1%; border-left: 0.5em solid black; border-right: 0.5em solid red; background: yellow}
.container > DIV:first-child {background: pink; border-left: 1px solid lime}
.container > DIV:last-child {background: teal; border-right: 1px solid yellow}

Using display: table and table-cell lets you have both columns keep the same height and make sure they are one right next to the other. You also are able to add more columns or just leave 1. You might need to tweak the width: 1%. For only two columns 50% should suffice, but as you add columns you have to start lowering it to keep the columns the same width, etc. You can also use padding for the separator, but margin and table-cell don't get along.

Also note that :last-child css selector is not supported in IE 8 and you'll need to use class or id on the column DIVs.

EDIT: Added another fiddle to cover the DIV that needs to be in the middle, since it needs to hold somecontent

http://jsfiddle.net/frozenkoi/RfzWb/ HTML:

<div class="mightyContainer">
    <div class="container3">
        <div>lefty<br><br><br>more lefty</div>
        <div class="divider">i</div>
        <div>right</div>
        <!--div>3rd</div>
        <div>4th</div-->
    </div>
</div>

CSS:

.mightyContainer {position: relative; background: magenta; margin-top: 3em}
.container3 {display: table; width: 100%; margin-left: 0; margin-right: 0; background: red; -k-position: relative}

.container3 > DIV {border: 1px dashed red; display: table-cell; width: 50%; border-left: 0.5em solid yellow; border-right: 0.5em solid black; background: yellow}
.container3 > DIV:first-child {background: pink; border-left: 1px solid lime}
.container3 > DIV:last-child {background: teal; border-right: 1px solid yellow}
.container3 .divider {text-align: center; width: 1em; background: lime; border: none; opacity: 0.5;
    display: block; position: absolute; top: 0px; bottom: 0px; left: 50%; margin-left: -0.5em; /*height: 100%*/;
}

The separator is positioned in the middle with absolute positioning. Note that the additional DIV with the mightyContainer class is necessary because in FireFox the DIV with divider class uses the whole page as the parent for positioning instead of the conteiner3. RockMelt (webkit) and IE 8/9 didn't seem to need it if you move the styles from .mightyContainer to .container3 and remove the mightyContainer DIV (for an example of how FireFox behaves without that extra DIV see http://jsfiddle.net/frozenkoi/3zhsv/).

Upvotes: 3

Šime Vidas
Šime Vidas

Reputation: 185963

One possibility:

HTML:

<div class="container">
    <div> Column A </div>
    <div> Column B </div>
</div>

CSS:

.container {
    overflow: auto;
}

.container > * {
    float: left;
    width: 50%;        
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

.container > :first-child {
    border-right: 0.5em solid COLOR;
}

.container > :last-child {
    border-left: 0.5em solid COLOR;
}

where COLOR is the color of the background-color of the separator column.

Live demo: http://jsfiddle.net/3XHSu/show/

Upvotes: 5

Wojciech Bednarski
Wojciech Bednarski

Reputation: 6373

Here you go - http://jsfiddle.net/wbednarski/w97ax/5/

Solution works with one column as well. The trick is in the .separator class.

Upvotes: 2

tereško
tereško

Reputation: 58444

Assuming i understood you right:

The basic idea is this:

  1. you take a 50-50% floated layout
  2. stick a fixed width element <div class="main"> between sides
  3. adjust both initial elements, so that they use less space then before

As for ability to remove right side - it works in the original version, but to remove left side, there is require a placeholder <div class="fix">, which takes up the space, because all the elements are floated and page would collapse otherwise.

P.S. the fluid-fixed-fluid layout is sometimes affectionately called: the unholy grail.

P.P.S the layout might have the 3px gap bug on IE6 (but i am not sure about that .. the ie6fix.css file was in the folder, but it was not included in the original testcase).

Upvotes: 3

Vlad Stratulat
Vlad Stratulat

Reputation: 1296

I really hope this would help you http://jsfiddle.net/EzfAs/

Upvotes: 2

ScottS
ScottS

Reputation: 72261

I don't know if you expect equal height columns (there are plenty of places that talk about that if you want to implement them), but this fiddle http://jsfiddle.net/TNpnh/11/ shows some variations. This avoids Sime's box-sizing if IE7 and lower is needing to be supported. The basic structure is:

HTML

<div class="container">     
    <div class="LC"> Left </div> 
    <div class="RC"> Right<br/>Taller </div> 
</div>

CSS

.container {
    padding: 0 0 0 1em; /*this creates the extra space */
    border: 1px solid red;
    overflow: auto;
    margin: 10px 0; 
}


.container .LC {
    width: 50%;
    margin: 0 -1em; /* this allows all to fit */
    float: left;
    background-color: yellow;
    border-right: 1em solid blue;
}

.container .RC {
    width: 50%;
    float: left;
    background-color: cyan;
    border-left: 1em solid blue; /* this is duplicated so it fills the tallest column */
}

Upvotes: 3

sandeep
sandeep

Reputation: 92813

You can do it with combination of :after & text-indent. It's work till IE8 for IE7 & below you can use css :after hack http://css-tricks.com/snippets/css/clear-fix/. In this example i didn't use hack for IE7 for if you want you can use.

check this:

http://jsfiddle.net/3XHSu/4/

OR

For modern browsers you can use css3 box-flex property there is no need to define width:50% Check this:

http://jsfiddle.net/XMg2h/2/

Upvotes: 3

kizu
kizu

Reputation: 43234

Using the inline-blocks you could create a lot of different non-trivial layouts.

I've made two examples, the first, with the faux equal heights: http://jsfiddle.net/kizu/nMWcG/

And the second variant, with the physical gap separator: http://jsfiddle.net/kizu/nMWcG/5/

They are somewhat different (and there could be even more layouts based on the inline-blocks that solve your problem), hope at least one of them would work for you :)

The whole idea is to use the white-space: nowrap on wrapper, so the columns won't drop if the sum of their widths is greater than wrappers' and then add a padding on a wrapper with a width: auto that would be equal to the desired gap.

If you'll need only one column, you could have one of the columns empty (without the .column-content), or remove them and have an extra class on them. Well, it depends on how you want the lonely column to behave etc.

Upvotes: 5

MikeyKennethR
MikeyKennethR

Reputation: 608

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:svg="http://www.w3.org/2000/svg"
      xml:lang="en">
  <head> <title>CASH REGISTER</title>
  <style type="text/css">
        @media all {
        body              { margin:0 ; padding:0 ; background:#000000 ; color:white }
        div               { margin:0 ; padding:0  ; font-size:2em       }
        }
  </style >
  </head>
  <body>
<div style="background-color: #888 ; width: 51em">
<div style="background-color:red;float:left;width:25em">1</div>
<div style="background-color:green;float:left;width:1em">2</div>
<div style="background-color:blue;float:left;width:25em">3</div>
</body>
</html>

Upvotes: 3

Related Questions