Sub-headers that stay in place on a webpage alongside a stationary page header

I'm facing a challenge with my website where I have a fixed top-of-page header and I want the sub-headers in the content to be sticky. I've tried two different approaches using CSS, but unfortunately, neither of them is working as expected:

  1. The first approach involves using position: fixed or position: sticky for the page header. This causes the rest of the page to scroll underneath the header, making the sub-headers invisible when they stick. They end up sticking to the top of the page instead of their own visible section. To fix this, I could set the top value to equal the height of the header, but this solution is not ideal as the header's height may vary.

    Another drawback of this method is that the page scrollbar intrudes into the header area rather than being confined to the scrolling section.

  2. The second approach involves using flex or grid to divide the page vertically into two sections - the header and a scrollable main section. While this does make the sub-headers stick correctly to the main section, it brings about other issues. Anchor links with #fragments no longer function reliably due to being inside a nested scrolling block. Additionally, there are significant bugs in mobile Safari where focusing on text input fields leads to the entire page scrolling instead of just the main section. The page becomes stuck, requiring a reload to resolve the issue. Here is someone else's report on this Safari bug and you can view their video showing the problem. (This bug can occur even without the nested scrolling div, but it exacerbates the situation.)

Finding a solution where the main header remains fixed while allowing the sub-headers to stick seems to be a common dilemma for many websites. Upon examining popular mobile sites like Google Docs, reddit, StackOverflow, and MDN, I noticed they opt for the first method mentioned above and sacrifice sticky sub-headers.

Any suggestions on achieving sticky sub-headers without resorting to creating a nested scrolling block? Or perhaps a workaround for Safari's scrolling flaw?

Answer №1

Without reviewing your specific code, it's difficult to provide a definitive answer, but based on the information provided, option #1 seems to be the most suitable choice.

In most cases, using position: sticky for the navigation header bar should automatically adjust the main container. If not, and it ends up overlapping with your subheader and content, you can always add top padding to push down the main section content (including the subheader).

Consider the following example:

<body>
<nav class="navbar" role="navigation">Page Header</nav>
<main class="main-content">Your main content with subheader</main>
</body>

If you opt to use position: fixed:

.navbar {position: fixed; top: 0; height: 100px; z-index: 9999}

.main-content { padding-top: 100px; (if your page header is 100px in height) }

Be sure to adjust your padding accordingly based on your breakpoints.

Answer №2

After much consideration, I decided to implement solution #1, utilizing the position: sticky attribute for the main page header and adding a non-zero value to the top property for the sticky sub-headers. Since the height of the page header can vary, I utilized TypeScript to dynamically set this value:

function handleStickyHeaders() {
    const header = document.querySelector(".pageHeader");
    if (header === null) {
        return;
    }

    let customStyle: HTMLStyleElement | undefined = undefined;

    const resizeObserver = new ResizeObserver(entries => {
        // We are only observing one element.
        if (entries.length !== 1 || entries[0].borderBoxSize.length !== 1) {
            return;
        }

        // Retrieve the height of the page header.
        const headerHeight = entries[0].borderBoxSize[0].blockSize;

        // Create a dynamic stylesheet for all sub-headers.
        if (customStyle !== undefined) {
            customStyle.remove();
        }
        customStyle = document.createElement("style");
        customStyle.innerHTML= `
            .sub-header {
                top: ${headerHeight}px;
            }
        `;
        document.body.append(customStyle);
    });

    resizeObserver.observe(header);
}

The observer initiates immediately, eliminating the need for further manual initialization of the top property.

While this method does have the drawback of causing the scrollbar to jump to the top of the page, it is a minor inconvenience in the grand scheme of things.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Unlocking the Power of jQuery: A Guide to Customizing CSS with Scroll Effects

Many CSS examples include a scrollbar for editing the CSS code. Click here to see an example of the scrollbar I haven't been able to find any instructions on how to do this. Can someone please explain? ...

Having trouble with CSS values not being applied to dynamically injected HTML div elements in Angular 4?

Link to Codepen My Angular calendar application runs smoothly without any errors. However, I am encountering an issue where the CSS styles are not being applied to the page. When I implemented this separately, everything worked fine. But as soon as I inc ...

Utilizing the power of Angular 15 in conjunction with Bootstrap 5's SCSS

After recently updating to Angular 15 with Bootstrap 5, I noticed that none of my utility classes are working (e.g. mb-3, mt-5, etc.) when including bootstrap in my styles.scss as shown below. @import 'bootstrap/scss/bootstrap.scss'; I understan ...

Challenges arise when utilizing CSS3 animations in conjunction with transitions triggered by toggling a JavaScript class

Struggling to activate an animation while updating a class using JavaScript for a PhoneGap app. Planning on utilizing -webkit- prefixes for compatibility. However, the animations are currently unresponsive in Chrome during testing, both when applied to th ...

Attempting to dynamically resize SVG images based on the size of the window for better scalability

I have a container that contains two SVG images. I want both the container and the images to adjust their height based on a percentage of the viewport size, while staying within a specified min-height/max-height range (and maintaining the aspect ratio of t ...

What are the steps to retrieve dynamic text values using Alpine.js?

<script defer src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f1909d81989f94b82b1c2df89e089">[email protected]</a>/dist/cdn.min.js"></script> <p @click="printThisTextToSpan"&g ...

What is the best way to dynamically change the color of my component depending on the prop passed to it?

I am facing an issue with the color of my component changing based on the value of the prop 'level'. Despite using states to set the backgroundColor, all components end up having the same color due to the state being altered for every comment. I ...

Having trouble with changing the color of an element when the radio input is checked?

Can someone help me troubleshoot this HTML and CSS code? <label class="radio"> <input type="radio" name="plan" value="plan" required> <span> <h6>Plan</h6> <i class="pe-7s-graph1 ...

Reduced resolution decreases image size significantly (bootstrap-5 Fluid)

What's Currently Happening: While using the Chrome browser's device toolbar tool to test my site at various resolutions, I observed that when I shrink the device screen to "Mobile-s" 320px, the content on my page becomes nearly unreadable. Additi ...

Scrolling to the next wrap class in jQuery is not functioning properly with the chatbox and ScrollTop

I have created a chat box using jQuery. However, I am facing an issue where when I click the button multiple times, the scroll returns to the top. My objective is for the scroll to move to the next wrap class when the button is clicked. Here is a snippet ...

How to position two divs to the right of another div, without them being adjacent to each other, using CSS

I am trying to arrange three divs with background colors of Red, Yellow, and Blue. The goal is to have the Red div on the left, followed by the Yellow div next to it, and then the Blue div underneath the Yellow one. However, my current code is not producin ...

Experiencing difficulties with JavaScript/jQuery when encountering the 'use strict' error

I have been working on a small function to change the background of an HTML file, but I keep getting the 'Missing 'use strict' statement' error message from JSLint despite trying multiple solutions. Can anyone suggest how to resolve th ...

Achieving perfect alignment both horizontally and vertically using CSS3's viewport height of 100%

I'm trying to utilize CSS3's Viewport Height to create a fullscreen section with a height of 100vh. However, I am encountering difficulties in centering elements both horizontally and vertically within the section. My goal is to have an image and ...

Expanding the hover state of a Bootstrap button

I am currently working on a website with bootstrap 4 and I am utilizing the bootstrap cards, which includes the primary button (btn-primary). My goal is to trigger the hover state of the button when hovering over the card itself. Is there a way to achieve ...

Replace all occurrences of the text/css style tag with an empty string using

I'm struggling with my PHP code and I need some assistance in removing the style type="text/css" tag. My goal is to replace this tag with an empty string. Here's the code snippet I've tried: if (strpos($inbox_message, '<style type= ...

Utilizing Ajax to dynamically update the color of a button when it is clicked from a different device

Currently, I am developing a program for my own use within my local community theater. The setup will involve a computer in the control room (Sound Booth) and another computer backstage. My plan is to create a grid of around 10 interactive "buttons" on th ...

Using Bootstrap 4 to create a dropdown button with the functionality of a regular

I'm struggling with the layout of my table header buttons. Whenever I add a dropdown button, it messes up the alignment and makes the whole thing look unattractive. Here's the code for my dropdown button: <div class="dropdown"> ...

Change the width of specific <li> elements to create variation

My goal is to configure a ul element with varying widths using flex. Specifically, I want the first two items in the ul to be 60% width while the last two items should be 40%. However, my flex-basis property doesn't seem to be working as expected. ...

CSS and jQuery UI URLs are not resolving properly in MVC framework after deployment

Basically, the issue is that the url for an image in jquery-ui.css file does not resolve once the site is deployed. The website is deployed under the default web site in IIS7, causing the browser console to look for the image in a different location than e ...

Do not apply the css rule to the custom class

I've been attempting to apply a CSS rule to href elements while excluding a specific class (.nolink). .content a { border-bottom: 2px; } I discovered that the :not selector can achieve this, but for some reason I'm having difficulty implementin ...