The forums ran from 2008-2020 and are now closed and viewable here as an archive.

Home Forums CSS Fixed position header hiding headings

  • This topic is empty.
Viewing 15 posts - 1 through 15 (of 20 total)
  • Author
  • #25468

    I’ve been playing around with a layout with a fixed position header. Everything is working nicely except for one thing. When one visits, one does not see the element in question because it is hidden by the header.

    It would be a good idea to provide some visuals at this point. First of all, have a look at Roger Johansson’s CSS Frames. This example does not have any elements with ids within the body copy, so I ran it locally and made two changes for the sake of demonstration:

    1. I added id="background" to the "Background" heading.
    2. I adjusted the opacity of the header to make it clear exactly what’s going on.

    What one hopes to see when one visits

    What one actually sees when one visits

    I’m sure several hours of trial and error would provide a solution to this problem. Rather than (potentially) reinventing the wheel, however, I thought it’d be wise to find out whether this issue has already been encountered and solved by someone else. Fingers crossed!

    Thanks in advance for any help you can provide.


    Link? Code?
    At least give us a clue.


    Here’s the crux of the matter:

    <div id="header"></div>
    <div id="content">
    <h3 id="background">Background</h3>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam imperdiet commodo leo, eu facilisis velit volutpat commodo. Duis nec malesuada nibh. Pellentesque imperdiet luctus hendrerit. Duis porta magna ac nulla auctor eleifend. In eu vulputate diam. Aliquam aliquet rutrum elit, ut aliquam leo rhoncus sed. Donec ultrices magna nec leo malesuada vitae ornare tortor pharetra. Aliquam erat volutpat. Aliquam dapibus, odio eget tempus dapibus, dolor leo placerat erat, ut tristique nisi sapien non urna. Nulla porttitor sem quis turpis consectetur porttitor. Sed vitae diam est.</p>
    <h3 id="recent-developments">Recent developments</h3>
    <p>Praesent sed nisi eu arcu fermentum tempor. Vestibulum quis ante eget lacus ultricies vehicula eget a massa. Quisque congue feugiat volutpat. Curabitur congue convallis nulla. Etiam non nisl magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin nec augue augue. Maecenas et justo libero. Sed fringilla molestie mauris sit amet ullamcorper. Vestibulum ante velit, rhoncus sed rutrum sed, porttitor eu eros. Nunc vel justo sed mauris dapibus aliquam eget a arcu.</p>
    position: fixed;
    height: 100px;
    background-color: #333;
    opacity: 0.5;


    Well, I’ve managed to come up with two possible solutions:

    1. Apply absolute positioning to content div

    position: absolute;
    top: 100px;
    height: 500px;

    This approach involves turning the content div into a frame, essentially, with its own scrollbar. Using absolute positioning creates headaches of its own, such as difficulty ensuring that the div has the correct height, but it certainly passes for proof of concept.


    I don’t want to go down a path that involves giving the content div its own scrollbar. On older browsers this will result in pages with two scrollbars (one active, one inactive) which is not attractive. Also, users are familiar with the location of the scrollbar, and I’m keen to provide a familiar experience for my users.

    2. Apply padding-top and (negative) margin-bottom to all block-level elements within the content div

    h1, h2, h3, h4, h5, h6, p
    padding-top: 100px;
    margin-bottom: -100px;

    With this approach, each block-level element is given padding-top equal to the height of the header. This means that jumping to #background will work as expected, as the top of the "Background" heading can happily align with the top of the viewport, and the 100px of padding plays nicely with the 100px header.

    The big gaps that have been added between block-level elements by the top padding are negated by an equal and opposite bottom margin.

    If anyone has a more elegant solution to this problem, please speak up.


    Thanks very much for taking the time to read this thread. My investigation has revealed a complete lack of discussion on this topic, so I think it’s about time it got some press.

    I’ve created a mock-up, which for the sake of reference I’ve called example 1.

    As you will note, the content div scrolls behind the header div, which is the cause of the problem. Ideally the content div would scroll into nonexistence 100px from the top of the viewport (i.e. at the bottom of the footer) as is the case with the simulated frame option.

    What’s the problem? one might ask. Have a look at and it should become clear.


    I’ve created a second mock-up, which I’ve called example 2 to demonstrate the positive top padding + negative bottom margin solution. Note that while the content div still scrolls behind the header div, the block-level elements within the content div have exactly the right amount of top padding to ensure that they appear exactly where you’d expect them to when you visit, for example.


    When one is taken to #background, for example, one expects to see the element with id="background" at the top of the viewport. With a fixed position header, this behaviour results in the element in question being obscured by the header div, whose z-index ensures that it sits above the content div.

    Here are the two options once again:

    Note that in the second example the "Background" heading is not obscured by the header div.

    p.s. I’ve added "skip to" links to the example pages to remind us why it’s important from a user experience perspective to ensure that an element is immediately visible when it is skipped to.


    Thanks for the suggestion.

    I realise that the issue can be sidestepped?—?at least for internal links?—?by using JavaScript, but I’m interested to find out / work out whether it’s possible to resolve this issue using only HTML and CSS. JavaScript is great, but I like to avoid using it when a "pure" (HTML and/or CSS) solution exists.

    I’ll continue my quest to find out whether a pure solution does indeed exist.


    I’ve given that a try. I don’t think applying top padding to an inline element does what you want it to do.


    What you’re suggesting (if I understand correctly) is having a block-level element with height equal to that of the header above each and every element on the page that could be linked to (internally or externally).

    In this particular case we could get away with assigning the id to another element altogether (the ul), although I am strongly opposed to this as it is far from being semantically correct and is likely to be the source of much confusion if others work with the code at a later date.

    If, then, we assume that we’ll be adding an empty block-level element before each element on the page that could be linked to, I don’t see any advantages over the padding + margin approach, while it has the disadvantages of adding chunks of white space to the page, requiring extra markup, and separating the id assignation from the element to which the id should really be assigned.

    (Good on you for not booting up your PC. I’m in exactly the same boat.)

    Chris Coyier

    Hey David,

    Took me a sec to understand the problem there too, but I get it now. I don’t think it’s a fundamental flaw in CSS or anything. Fixed positioning is just very powerful like that. Those elements are just going to stay put and cover up whatever they cover up. Having a bar across the top that behaves that way is always going to be at risk for covering content.

    I think your solution of adding top padding to each header-level element is a perfect solution to making it work, although I don’t think the negative bottom margin is going to help in the way you want it to.

    This is a great example of a place CSS variables would come in handy, where the HEIGHT of the header should be equal to the TOP PADDING of your headers. A non-intuitive connection, which would need to change in two places if adjustments are made.


    Thanks for having a look at this, Chris!

    I’m not suggesting that CSS is behaving oddly; as you say, it’s doing exactly as it’s told. (The question is how do we tell the browser to behave the way we would like it to in this instance.)

    You’re absolutely right that CSS variables would be handy in this situation. Since using a header height variable is not currently an option, I’ll need to specify both the height of the header div and the top padding of the content div’s block-level elements in pixels (something I avoid doing where possible).

    By the sound of things, this is not a commonly encountered issue. I’ll run with the padding + margin technique for now, but if I manage to come up with something better I’ll make sure to mention it in this thread.

    p.s. Using these forums is a pleasure. It was a great idea to set them up, and the quality of the implementation is impressive.


    For those that are interested, check out to see the live implementation.

    Unfortunately I’ve just realised that there’s a significant problem with my approach: the top padding is making nearby links unclickable. I’ve managed to replace one conundrum with another. :/


    I’ve settled on a final solution very close to one of Apostrophe’s suggestions.

    Previously, I had markup that looked like this:



    I’ve had to add a meaningless div element immediately before each element that has an id:



    The CSS to make it work is very simple:

    position: relative;
    top: -160px;

    My current solution to this problem is explained in a post I’ve just published titled CSS fixed-position headers.

Viewing 15 posts - 1 through 15 (of 20 total)
  • The forum ‘CSS’ is closed to new topics and replies.