23

I'm trying set up a layout that will look like this: enter image description here

I want to use twitter bootstrap for the project, but I understand it may not be the best way to go for the basic layout that looks like this. I know how to setup the header and footer to be fixed at the top and bottom, but I have a hard time having my sidebar constant width and independently scrollable.

My current implementation is here: http://jsfiddle.net/Mwkrw/3/.

I tried setting up the fixed sidebar using Fixed sidebar navigation in fluid twitter bootstrap 2.0 and a couple of other similar answers on stack overflow, but they all break when the sidebar is longer than the content and as far as I know there is no way to give it an independent scroll.

I would ideally like to do this with pure css - no javascript. I'm sure it's possible and it's my lack of skill and knowledge that prevents me form doing it properly, so there may be no point in unnecessarily adding javascript code. (I'm still adding a javascript tag in case it's not possible)

Thanks for all the help!

EDIT: So my header clearly did not need to be position fixed. Here is the new and improved version: http://jsfiddle.net/Mwkrw/4/ I'm still struggling with the two scrollable divs though.

Community
  • 1
  • 1
mck
  • 2,040
  • 3
  • 19
  • 29

3 Answers3

15

The magic is in box-sizing:border-box;. For compatibility with Firefox, chrome<10, and safari<5.1, add the -webkit- and -moz- prefixes. IE supports it as of 8.0.

<!doctype html>
<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <title>very structured layout</title>
        <style type='text/css'>
            *      {margin:0; padding:0;}
            body   {background:#fff; position:absolute; width:100%; height:100%;}
            #main  {background:#888; height:100%; padding:60px 0 40px; box-sizing:border-box;}
            #head  {background:#f8f; position:absolute; width:100%; height:60px;}
            #left  {background:#ff8; float:left; width:250px; height:100%; overflow:scroll;}
            #right {background:#8f8; height:100%; overflow:scroll;}
            #foot  {background:#f88; position:absolute; bottom:0; width:100%; height:40px;}​
        </style>
    </head>
    <body>
        <div id='head'>header: width = 100%, height = 40px</div>
        <div id='main'>
            <div id='left'>left: width = 250px, height = 100%</div>
            <div id='right'>right: width = 100% - 250px, height = 100%</div>
        </div>
        <div id='foot'>foot: width = 100%, height = 60px</div>​
    </body>
</html>

fiddle

edit: after Andres' solution made me realize I could achieve greater compatibility, I messed around a bit and came up with an alternate solution, which I think is more intuitive as well. It doesn't work in IE7, but it does work in IE8.

The page is the same as the above, with the only change being that the CSS is replaced with this:

*      {margin:0; padding:0;}
body   {background:#fff;}
#main  {background:#888; position:absolute; top:40px; bottom:60px; width:100%;}
#head  {background:#f8f; position:absolute; width:100%; height:40px;}
#left  {background:#ff8; position:absolute; width:250px; height:100%; overflow:scroll;}
#right {background:#8f8; margin-left:250px; height:100%; overflow:scroll;}
#foot  {background:#f88; position:absolute; bottom:0; width:100%; height:60px;}

fiddle

Note that, for both versions, #head and #foot need to have an overflow property other than visible if their content would otherwise extend off the page.

st-boost
  • 1,877
  • 1
  • 14
  • 17
  • Oh man. That looks perfect! I'll test this properly at tomorrow and accept. Thank you! I've never even heard of `box-sizing` before. – mck May 07 '12 at 06:45
  • no problem. if you think box-sizing is useful, just wait until we've got support for the box layout. give it a few years and we might even be writing css that *isn't* a bunch of hacks. – st-boost May 07 '12 at 07:33
  • That would be nice. I'm still baffled by a lot of things in css. Twitter-bootstrap does a lot of things that seem like they should have been there from the start. (the way to build layouts for instance) – mck May 07 '12 at 07:35
9

I managed to get the layout you mocked up in your post by first creating a main container class that is stretched 100% both vertically and horizontally, this way we can fully stretch the content within to the full height of your viewport. Within this container div i created another container and positioned it absolutely while stretching it in all directions, top, left, bottom, right, i felt that this method was cleaner cause this way i can easily position the header and footer without the need for negative margins (tried it like that but it didn't work).

Here is a demo of the layout: http://jsfiddle.net/andresilich/gbzTN/1/show, edit here.

And the code:

CSS

html, body {
    height: 100%;
}

.main {
    *zoom:1;
}

.main, .row-fluid {
    height: 100%;
}

.main:before, .main:after,
.column:before, .column:after {
    content: "";
    display: table;
}

.main:after,
.column:after {
    clear: both;
}

.column {
    height: 100%;
    overflow: auto;
    *zoom:1;
}

.column .padding {
    padding: 20px;
}

.box {
    bottom: 40px;
    left: 0;
    position: absolute;
    right: 0;
    top: 40px;
}

.span9.full {
    width: 100%;
}

.footer {
    height: 40px;
    width: 100%;
    z-index: 100;
    background-color: red;
    bottom: 0;
    left:0;
    right:0;
    position: fixed;
}

HTML

<div class="navbar navbar-fixed-top">
  <div class="navbar-inner">
    <div class="container-fluid">
      <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </a>
      <a class="brand" href="#">Project name</a>
      <div class="btn-group pull-right">
        <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
          <i class="icon-user"></i> Username
          <span class="caret"></span>
        </a>
        <ul class="dropdown-menu">
          <li><a href="#">Profile</a></li>
          <li class="divider"></li>
          <li><a href="#">Sign Out</a></li>
        </ul>
      </div>
      <div class="nav-collapse">
        <ul class="nav">
          <li class="active"><a href="#">Home</a></li>
          <li><a href="#about">About</a></li>
          <li><a href="#contact">Contact</a></li>
        </ul>
      </div><!--/.nav-collapse -->
    </div>
  </div>
</div>
<div class="main clearfix">
    <div class="box">
        <div class="row-fluid">
            <div class="column span3">
                <div class="padding">
                    .. content ..
                </div>
            </div>
            <div class="column span9">
                <div class="padding">
                    <div class="full span9">
                        .. content ..
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<div class="footer clearfix">
    <h3>footer</h3>
</div>

Edit: noticed that this solution does not work as expected in IE7 (works perfect in IE8 and above) so here is a conditional comment targeting everything below IE8 that should fix the issue and make it work as expected:

CSS

<!--[if lt IE 8]>
    <style type="text/css">
        html {
            margin: 40px 0px;
            overflow: hidden
        }

        .main {
            zoom:1;
        }

        .column {
            overflow-x: hidden !important;
            overflow-y: scroll !important;
            zoom: 1;
        }

        .box {
            position: relative !important;
            min-height: 100%;
            height:100%;
            zoom: 1;
            top:0 !important;
        }

        .main {
            margin: 40px 0px;
        }
    </style>
<![endif]-->
Andres I Perez
  • 75,075
  • 21
  • 157
  • 138
  • Hey, thanks for this! It looks good especially that you went with twitter bootstrap on the whole thing. However I have decided to use boost's solution. It just seemed like it's easier to implement. Thanks for this though! – mck May 10 '12 at 06:20
  • @MaciekAlbin yeah it was a good solution, my ony quarrel with it was support, `box-sizing` is only supported by IE8+. – Andres I Perez May 10 '12 at 10:32
  • Fortunately these are my requirements :) – mck May 12 '12 at 07:35
1

Now that Bootstrap 4 is out I thought some may benefit from this layout which is now a little easier thanks to flexbox.

Bootstrap 4 Demo

<body class="container-fluid d-flex flex-column h-100 align-items-center px-0">
 <div class="row grow w-100">
    <div class="header col-12 bg-primary py-2">
        Header
    </div>
    <div class="side col-3 bg-light py-3 pl-0">
        Menu
    </div>
    <div class="main col bg-warning py-3">
        Main
    </div>
 </div>
 <div class="row w-100 footer bg-danger">
    <div class="col-12 py-3">
        Footer
    </div>
 </div>
</body>

.grow {
    flex: 1;
    overflow: hidden;
}

.main,.side {
    overflow-y: auto;
    height:calc(100% - 55px);
}

.footer,.header {
    height: 55px;
}
Carol Skelly
  • 351,302
  • 90
  • 710
  • 624