views:

468

answers:

4
+15  Q: 

Tricky CSS Layout

So I am making a website with quite a problematic layout. There are four corner images TL, TR, BL and BR indicated by black blocks. The dark orange area is the main content (to a width of 960px), with the outside area denoted by the green arrow as the browser window. See diagram:

Diagram

The top image represents the site at its narrowest possible - it shouldn't be allowed to be narrower than this (960px) if it is larger than the defined area there should be no scrollbars. The bottom two images represent different widths of browser.

The bottom left and right black blocks (images) should be at the bottom left and right of the screen at all times, unless the width falls to 960px, in which case the BL and BR images should poke into the main area slightly. If the site is shrunk to, say 200px, the BR image should not still be poking in the right corner.

At this point I don't really care about it working exactly in IE6 (I can get it roughly working) but I can't even figure out how to do it fully without Javascript or extremely experimental CSS. Currently I am using absolutely positioned div's which sort of work, but don't work quite right.

I think I'd be willing to accept a bit of JS if there is no other way but I'd rather not.

Answer very appreciated!

+1  A: 

The only really tricky part is the bottom. Th rest of it is pretty straightforward:

<body>
    <div id="container">
        <div id="header">
            <div class="right"></div>
            <div class="left"></div>
        </div>

        <div id="footer">
            <div class="right"></div>
            <div class="left"></div>
        </div>
    </div>
</body>

CSS:

#container {
    margin: 0 auto;
    width: 960px;
}

#header {
    position: relative;
}

#header .right, #header .left {
    position: absolute;
    width: 100px;
}

#header .right {
    left: 940px; /* leaves 20px inside the #header */
    background: url(images/header_right.gif) no-repeat;
}

#header .left {
    left: -80px; /* leaves 20px inside the #header */
    background: url(images/header_left.gif) no-repeat;
}

And some similar stuff for the #footer, but you'll need to use a little bit of javascript to detect the window width and adjust the lefts slightly.

davethegr8
I have something similar to that - the problem is that the positive absolute positioned #header .right causes scrollbars. I could probably even live with that, but the footer just doesn't play ball. :(
Meep3D
@meep3d - I can't test this, but try and set `overflow-x: hidden;` on the body tag. It *might* get rid of the scroll bar problem, by hiding elements (or parts of elements outside the body element). It sounds counter-intuitive, but it might work. If not, post some code so we can take a crack at it.
davethegr8
Wont that hide all the horizontal scrollbars?
Meep3D
yeah, but it'll get rid of the left and right adding scrollbars problem. If the view port is smaller than the container width it could cause problems. Or you could not set it, but you'd have to not mind the scrollbars that get added.If the images are just backgrounds, why not just combine them into one background, and set it directly on the #header?
davethegr8
The distance between the BL and BR images varies depending on the viewport - meaning I can't comine them that way. :(
Meep3D
Oh, I was referring to the top. The bottom will probably require some javascript.
davethegr8
+2  A: 

Something like this? You may replace the JavaScript code with similar JQuery code if you like, just wanted to give the idea how this could work.

<html>
<head>
  <title>....</title>

  <style type="text/css">
  html
  { height: 100%; margin: 0; background: white; }
  body
  { height: 100%; width: 960px; margin: 0 auto; background: gray; overflow: hidden; }
  #main
  { margin: 0px; padding: 5px 20px; position: relative; }

  #headLeft
  { position: absolute; top: 0px; left: -80px;
    width: 100px; height: 35px; background: green; }
  #headRight
  { position: absolute; top: 0px; right: -80px;
    width: 100px; height: 35px; background: green; }
  #footLeft
  { position: absolute; bottom: 0px; left: 0px;
    width: 100px; height: 35px; background: green; }
  #footRight
  { position: absolute; bottom: 0px; right: 0px;
    width: 100px; height: 35px; background: green; }
  </style>

  <script type="text/javascript">
  function checkSize ( event )
  {
    var contentWidth = 960;
    var minOuterBoxSize = 60; // maximum 100-60=40 px will be displayed inside the main area

    if ( window.innerWidth - contentWidth < minOuterBoxSize * 2 )
    {
      var pos = ( ( minOuterBoxSize * 2 ) - window.innerWidth + contentWidth ) / 2;
      document.getElementById( 'footLeft' ).style.left = '-' + pos;
      document.getElementById( 'footRight' ).style.right = '-' + pos;
    }
    else
    {
      document.getElementById( 'footLeft' ).style.left = '0px';
      document.getElementById( 'footRight' ).style.right = '0px';
    }
  }
  </script>
</head>

<body onload="checkSize( event );" onresize="checkSize( event );">
 <div id="main">
  <div id="headLeft">TL</div>
  <div id="headRight">TR</div>

  <p>Normal content</p>
 </div>

 <div id="footLeft">BL</div>
 <div id="footRight">BR</div>
</body>
</html>
poke
Put the JavaScript in an `window.onload` event.
musicfreak
Uhm... it is in an onload event..
poke
+17  A: 

No need for Javascript. At least in most modern browsers. Using simple positioning and one @media query I pulled it off:

<head>
  <style type="text/css" media="screen">
    body {
      margin: 0;
      padding: 0;
      font-family: sans-serif;
      background: orange;
      text-align: center;
      color: black;
      overflow-x: hidden;
    }
    #content {
      width: 960px;
      margin: 0 auto;
      padding: 20px 0;
      min-height: 800px;
      background: #cc6600;
      z-index: 0;
    }
    .image {
      background: black;
      color: white;
      height: 60px;
      width: 100px;
      padding: 20px 0;
      z-index: 1;
      opacity: .95;
    }
    #top {
      width: 960px;
      margin: 0 auto;
      position: relative;
      overflow: visible;
    }
    #top .image {
      position: absolute;
    }
    #top .left {
      left: -80px;
    }
    #top .right {
      right: -80px;
    }
    #bottom {
      position: fixed;
      bottom: 0;
      width: 100%;
      height: 100px;
    }
    #bottom .image {
      position: absolute;
    }
    #bottom .left {
      left: 0;
    }
    #bottom .right {
      right: 0;
    }

    @media all and (max-width:1120px) {

      #container {
        width: 960px;
        margin: 0 auto;
        position: relative;
        overflow: visible;
      }
      #bottom .left {
        left: -80px;
      }
      #bottom .right {
        right: -80px;
      }    

    }
  </style>
</head>
<body>
  <div id="top">
    <div class="left image">left image</div>
    <div class="right image">right image</div>    
  </div>
  <div id="content">
    content
  </div>
  <div id="bottom">
    <div id="container">
      <div class="left image">left image</div>
      <div class="right image">right image</div>
    </div>
  </div>
</body>

That may fall under your description of "extremely experimental CSS", but I think you'd be surprised by how much support it does have, and how easy it would be to bootstrap that with a touch of JS - simply check browser width on re-size and add the extra CSS when the width falls under 1120px.

Eric Meyer
Yep, media queries are the way to go. Support is all modern browsers aside from IE, but as mentioned, it's easy enough to check for media-query support, and then add the js.
Rich Bradshaw
Really cool, but how would you make it work under IE?
van
Here's one option: http://www.protofunc.com/scripts/jquery/mediaqueries/ -- Another option is to add some JS in a conditional comment that checks the browser window width (e.g. something like: `$(window).resize(function() { if $(window).width() > 1120px {...do this...}; });` with jQuery) and changes the CSS as necessary (e.g. `$('#container').css('width' : '960px', 'margin' : '0 auto');` again with jQuery). http://api.jquery.com/css/
Eric Meyer
*Another* Eric Meyer that's good at CSS? http://meyerweb.com/eric
Josh Stodola
A: 

You could try something like the below, if you don't need to support IE (or you can find a min-width workaround that works in this case) and you don't mind having rather a lot of divs.

Test page: http://jsbin.com/imeyi

<html>
<head>
    <title></title>
    <style type="text/css">
        body {
            margin: 0;
        }
        .left, .right {
            background: #000;
            height: 100px;
            position: absolute;
            top: 0;
            width: 100px;
        }
        .left {
            left: 0;
        }
        .right {
            right: 0;
        }
        #page {
            position: relative;
        }
        #content {
            background: #ddd;
            height: 1000px;
            margin: 0 auto;
            width: 960px;
        }
        #header-outer {
            left: 0;
            height: 100px;
            min-width: 960px;
            overflow: hidden;
            position: absolute;
            top: 0;
            width: 100%;
        }
        #header {
            margin: 0 auto;
            position: relative;
            width: 960px;
        }
        #header .left {
            left: -50px;
        }
        #header .right {
            right: -50px;
        }
        #footer-outer {
            bottom: 0;
            left: 0;
            height: 100px;
            min-width: 960px;
            overflow: hidden;
            position: absolute;
            width: 100%;
        }
        #footer {
            left: 50%;
            min-width: 1060px; /* 960 + 50 cropped for each corner div */
            position: absolute;
            width: 100%;
        }
        #footer-inner {
            position: relative;
            left: -50%;
            width: 100%;
        }
    </style>
</head>
<body>
    <div id="page">
        <div id="header-outer">
            <div id="header">
                <div class="left"></div>
                <div class="right"></div>
            </div>
        </div>
        <div id="content">
        </div>
        <div id="footer-outer">
            <div id="footer">
                <div id="footer-inner">
                    <div class="left"></div>
                    <div class="right"></div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>
Richard M