How do I use CSS to position a fixed variable height header and a scrollable content box?

Viewed 40389

I'm trying to make a web page with a fixed header and a scrollable content area. This is trivial when the header has a known height but I'm struggling to find a solution for when the header is fluid.

The layout I want is:

--------------
head
--------------
content
--------------

where "head" is whatever height its content needs it to be and "content" has no minimum height but will reach a maximum height of the bottom of the viewport before becoming scrollable.

Is this possible these days in pure CSS? I'm targeting IE8+.

To clarify what I want, here is what I would do if I knew the height of the header:

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">

body {
    margin: 0;
}

#head {
    background: yellow;
    height: 20px; /* I can't rely on knowing this. */
}

#content {
    background: red;
    position: absolute;
    top: 20px; /* here also */
    bottom: 0;
    width: 100%;
    overflow: auto;
}

        </style>
    </head>
    <body>
        <div id="head">some variable height content</div>
        <div id="content">
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
        </div>
    </body>
</html>
8 Answers

The easiest way is to simply replace position: fixed; with position: sticky;

header {
  position: sticky;
  top:0;
  background-color: red;
  color: #fff;
}

main {
  background-color: green;
  color: #fff;
  min-height: 150vh;
}

DEMO: https://jsfiddle.net/4zndve6p/

I solved this problem using getComputedStyle. This method allows you to take all CSS styles. And based on them, change the style of another element. Here is all the code using native JS:

<style>
#head {
    position: fixed;
    width: 100%;
    top: 0;
    left: 0;
    background: rgb(170, 170, 170);
    /* height: 50px; for example no fixed height*/
    z-index: 2;
}

#content {
    position: relative;
    width: 100%;
    background: rgb(180, 37, 37);
  }
<body>
<div id="head">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim, quisquam.</div>
<div id="content">
    Some content text<br />

</div>
<script>
    const header = document.querySelector('#head'),
        content = document.querySelector('#content');
    //Now get all possible CSS styles from #head using getComputedStyle
    const marginTopOffset = getComputedStyle(header);
//Resize event is for autosearch width of a browser window
window.addEventListener('resize', ()=> {
    function marginOffset() {
        content.style.marginTop = marginTopOffset.height;
        // you can add changes to another CSS style 
        // content.style.backgroundColor = marginTopOffset.backgroundColor;
    };
    marginOffset();
    // You can see how changes margin-top in console on the fly
    console.log(content);
});
</script>
</body>

Here is my simple and working solution with just four lines of code.

Description

  • getBoundingClientRect calculates the effective properties of an element, including the margins. I use this to get the effective bottom value.
  • This value is assigned to the marginTop property of the content element.
  • An event listener for onResize is required to react to changes in the window size, which can effect the header height.

See it working

My fiddle (adjust width to see the effect): https://jsfiddle.net/z1uac3Lw/

function adjustHeaderHeight() {
   let header = document.getElementById('head');
   let rect = header.getBoundingClientRect();
   document.getElementById('content').style.marginTop = rect.bottom + 'px';
}

window.addEventListener('resize', function() {
   adjustHeaderHeight();
});
body {
    margin: 0;
}

#head {
    background: yellow;
//    height: 20px; /* I can't rely on knowing this. */
}

#content {
    background: red;
    position: absolute;
    top: 0px;
    bottom: 0;
    width: 100%;
    overflow: auto;
}
<!DOCTYPE html>
<html>
    <head>
    </head>
    <body onLoad='adjustHeaderHeight();' >
        <div id="head">some variable height content ... with a very long long long long long long long long long long long long long long long long long long long long long line to show the effect</div>
        <div id="content">
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
        </div>
    </body>
</html>

Code with inline javascript / CSS

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">
body {
    margin: 0;
}

#head {
   background: yellow;
//    height: 20px; /* I can't rely on knowing this. */
}

#content {
   background: red;
   position: absolute;
   top: 0px;
   bottom: 0;
   width: 100%;
   overflow: auto;
}

        </style>
        <script type="text/javascript" type="text/javascript">        
    
function adjustHeaderHeight() {
   let header = document.getElementById('head');
   let rect = header.getBoundingClientRect();
   document.getElementById('content').style.marginTop = rect.bottom + 'px';
}

window.addEventListener('resize', function() {
   adjustHeaderHeight();
});

      </script>        
        
   </head>
   <body onLoad='adjustHeaderHeight();' >
      <div id="head">some variable height content ... with a very long long long long long long long long long long long long long long long long long long long long long line to show the effect</div>
      <div id="content">
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
      </div>
   </body>
</html>
Related