Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Right-floated sidebar with main content flowed around - how?

Tags:

html

css

web

I'd like to create a webpage layout with the sidebar to the right and the main content flowing around the sidebar.

Requirements:

  1. Content below the sidebar should occupy all of the available width
  2. Content below the sidebar should not wrap when it hits the left of the sidebar
  3. Main content should precede the sidebar in the markup
  4. Sidebar has fixed width but unknown/variable height
  5. CSS-only - no JavaScript solutions

This could be achieved without the third requirement: if the sidebar is before the main content in the markup and is within the same containing element, a simple right float does the job. A sidebar before the main content in the markup is not an option here. The sidebar will contain supplemental information and adverts. If this is before the main content in the markup it will be annoying to CSSless browsers and screenreader users (even with 'skip to ...' links).

This could be achieved without the fourth requirement. If the sidebar had a fixed height I could put a containing element before the main content, float it right and give it a suitable width and height and then use absolute positioning to put the sidebar on top of the pre-made space.

Example markup (without CSS, relevant bits only):

<body>
  <div id="content">
    <p>
      Lorem ipsum ....
    </p>
    <p>
      Pellentesque ....
    </p>
    <div id="sidebar">
      /* has some form of fixed width */
    </div>
  </div>
</body>

Example layout:

alt text http://webignition.net/images/layoutexample.png

I'm not sure if this is possible. I'm happy to accept an authoritative answer stating that this cannot be achieved. If this can't be achieved I'd appreciate an explanation - knowing why it can't be achieved is much more valuable than just being told it can't.

Update: I'm happy to see answers that don't meet all of the five requirements, so long as an answer states which requirement is being ignored plus the consequences (pros and cons) of ignoring the requirement. I can then make an informed compromise.

Update 2: I can't ignore requirement 3 - the sidebar cannot precede the content.

like image 406
Jon Cram Avatar asked Nov 06 '08 09:11

Jon Cram


3 Answers

Simple floating w/ opposite source order just can't be done (w/o CSS3 draft specs). The pragmatic approach is to first build a nice layout that supports your desired source order. HTML:

<div id="content" class="noJs">
  <div id="floatSpace"></div>
  <p>Lorem ipsum ....</p>
  <p>Pellentesque ....</p>
  <div id="sidebar">content</div>
</div>

CSS:

#content {position:relative;}
#sidebar {width:150px; position:absolute; top:0; right:0;}
.noJs {padding-right:150px;}
.noJs #floatSpace {display:none;}
.js #floatSpace {float:right; width:150px;}

This satisfies all but 1 and 2. Now, we add the JS:

$(function () {
  // make floatSpace the same height as sidebar
  $('#floatSpace').height($('#sidebar').height());
  // trigger alternate layout
  $('#content')[0].className = 'js';
});

This will make the contents float around #floatSpace, and #sidebar will remain positioned on top of it. This is better than moving #sidebar because source order remains the same (for screenreaders that support Javascript, etc.).

Here's a JSFiddle of this in action. This layout does come with the unfortunate requirement of keeping the floatSpace height in sync with the sidebar height. If the sidebar is dynamic or has lazy-loading content, you must re-sync.

like image 146
Steve Clay Avatar answered Oct 09 '22 22:10

Steve Clay


I believe you're gonna have to change the order for this, putting the sidebar first. Then, use CSS's float property (without changing order, div#sidebar would end up below the paragraphs vs next to them). div#sidebar should stretch as needed for height.

CSS:

#sidebar {
    float: right;
    width: 50px;
}

HTML:

<body>
  <div id="content">
    <div id="sidebar">
      /* has some form of fixed width */
    </div>

    <!-- paragraphs -->
  </div>
</body>

@Jon Cram [comment]

Ok...nvm. You stated your own answer and rejected it at the same time.

You can't float an element around other elements that are defined before it. The browser has to be able to answer "float around what?" And it looks to the next element to start, continuing as far as necessary.

like image 2
Jonathan Lonowski Avatar answered Oct 09 '22 22:10

Jonathan Lonowski


Ok, here's another answer then, since we can ignore one of the requirements, skip out the first requirement where the content wraps underneath the sidebar.

#sidebar {
  float: left;
  width: 100px;
}
#actualContent {
  width: 700px;
  float: left;
}

The only change to your code is that you have to put your actual content in another wrapper.

<div id="content">
    <div id="actualContent">
        <p>...</p>
        <p>...</p>
    </div>
    <div id="sidebar">
        <p>...</p>
    </div>
</div>
like image 2
nickf Avatar answered Oct 09 '22 23:10

nickf