codeheat.org icon indicating copy to clipboard operation
codeheat.org copied to clipboard

Implement Sticky Header on Top of Website

Open Ubayed-Bin-Sufian opened this issue 6 months ago • 10 comments

Description

We need to add a sticky (fixed) header to the top of the website so that the navigation bar remains visible as users scroll down the page. This will improve site usability and enhance the user experience, especially on long pages.

Notes

If using custom CSS/JS, ensure it's added via child theme or via proper enqueuing.

Proposal

Reference from original website:

https://github.com/user-attachments/assets/be8ace22-723a-409e-94d9-efc18314185d

Task

  • [x] Add custom-sticky.js file
  • [x] Add the css to the style.css file
  • [x] Add functions to the functions.php file
  • [x] Add Limitations
  • [x] Change the color of social links on scrolling
  • [x] Change the site logo on scrolling
  • [x] Add Screencast of Demo
  • [x] Change the color of the drop down menu on scrolling

Ubayed-Bin-Sufian avatar Jul 21 '25 08:07 Ubayed-Bin-Sufian

Files added (in the child theme)

  • custom-sticky.js: This new file contains the JavaScript logic that detects scroll position and adds/removes the is-sticky class to your header. It also dynamically adjusts the padding-top of the body to prevent content from jumping.

  • style.css: This file now includes the CSS rules for the is-sticky class, defining how the header looks and behaves when it's fixed at the top of the screen.

  • functions.php: This file ensures that your new custom-sticky.js file and your style.css file are correctly loaded by WordPress.

Ubayed-Bin-Sufian avatar Jul 21 '25 09:07 Ubayed-Bin-Sufian

TASK: Add custom-sticky.js file

Steps to Implement:

  1. Create JavaScript File:

    • Navigate to: wp-content/themes/astra-child/
    • Create a new file named: custom-sticky.js
  2. Add JavaScript Code:

    • Open custom-sticky.js and paste the following code and save the file:
document.addEventListener('DOMContentLoaded', function () {
    const header = document.querySelector('.ast-main-header-wrap');
    if (!header) return;

    function updateStickyHeader() {
        const scrollY = window.scrollY || window.pageYOffset;
        if (scrollY > 50) {
            header.classList.add('is-sticky');
        } else {
            header.classList.remove('is-sticky');
        }
    }

    window.addEventListener('scroll', updateStickyHeader);
    updateStickyHeader(); // Run on load in case page is already scrolled
});

  1. Verify the File Is Active:

    • Go to WordPress Dashboard > Appearance > Theme File Editor.
    • Select the Astra Child theme.
    • Confirm custom-sticky.js is listed.
Image

Ubayed-Bin-Sufian avatar Jul 21 '25 09:07 Ubayed-Bin-Sufian

TASK: Add the css to the style.css file

WordPress Dashboard > Appearance > Customize > Additional CSS (Left sidebar) > Paste the following CSS in the editor > Publish

OR

Admin Dashboard > Themes > Theme File Editor > select style.css (Make sure the astra-child is selected) > paste the following CSS > update file

/*
 * Add these styles to your astra-child/style.css file
 * This replaces any previous sticky header CSS.
 */

/* Base styles for the main header wrap */
.ast-main-header-wrap {
    /* Ensure smooth transitions for all properties that change */
    transition: all 0.3s ease-in-out;
    /* --- KEY CHANGE HERE --- */
    /* Set initial background color to transparent */
    background-color: transparent;
    /* Ensure it has a z-index even when not sticky, to prevent issues with other elements */
    z-index: 99; /* Lower than sticky state, but still above most content */
    position: sticky; /* Fallback for modern browsers */
    /* Optional: If your logo or menu items are not visible on a dark background initially,
       you might need to set their initial color here. For example: */
    /*
    color: #ffffff; // Example: white text/icons initially if header is over a dark hero section
    */
}

/* Styles for the sticky header when the 'is-sticky' class is applied by JavaScript */
.ast-main-header-wrap.is-sticky {
    position: fixed; /* Makes the header stick to the viewport */
    width: 100%; /* Ensures the header spans the full width of the viewport */
    backdrop-filter: blur(5px); /* Optional: for frosted glass effect */
    transform: translateZ(0); /* Hardware acceleration */
    /* Semi-transparent white background when sticky */
    background-color: rgba(255, 255, 255, 0.9); /* 0.9 for 0.X as a good default */
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); /* Adds a more pronounced shadow */
}

/* Styles for text and icons within the sticky header */
/* Target common elements like links (menu items, social links) and icons */
.ast-main-header-wrap.is-sticky .main-header-menu a, /* For main menu links */
.ast-main-header-wrap.is-sticky .ast-builder-menu-element a, /* For builder menu links */
.ast-main-header-wrap.is-sticky .ast-social-stack a, /* For social links */
.ast-main-header-wrap.is-sticky .ast-social-stack svg, /* For social icons (SVG) */
.ast-main-header-wrap.is-sticky .ast-social-stack i, /* For social icons (FontAwesome/i tags) */
.ast-main-header-wrap.is-sticky .site-title a, /* For site title link */
.ast-main-header-wrap.is-sticky .site-description { /* For site description */
    color: #333333 !important; /* Change text/icon color to dark gray */
    /* Add transition for color property for smooth change */
    transition: color 0.3s ease-in-out;
}

/* Ensure the default colors also have a transition for when the sticky class is removed */
/* This ensures a smooth transition back to the initial (potentially different) color */
.ast-main-header-wrap .main-header-menu a,
.ast-main-header-wrap .ast-builder-menu-element a,
.ast-main-header-wrap .ast-social-stack a,
.ast-main-header-wrap .ast-social-stack svg,
.ast-main-header-wrap .ast-social-stack i,
.ast-main-header-wrap .site-title a,
.ast-main-header-wrap .site-description {
    transition: color 0.3s ease-in-out;
}

/* Prevent layout shift by reserving space */
body {
    padding-top: 0;
    transition: padding-top 0.3s ease-in-out;
}

/* Logo color change on sticky */
.ast-main-header-wrap .site-logo-img img,
.ast-main-header-wrap .custom-logo {
    transition: filter 0.3s ease-in-out;
}

.ast-main-header-wrap.is-sticky .site-logo-img img,
.ast-main-header-wrap.is-sticky .custom-logo {
    filter: brightness(0) saturate(100%) invert(20%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(20%) contrast(100%);
}

/* Social icons color change on sticky */
.ast-main-header-wrap .ast-header-social-1-wrap svg,
.ast-main-header-wrap .ast-header-social-wrap svg {
    transition: fill 0.3s ease-in-out;
    fill: white; /* Default white color */
}

.ast-main-header-wrap.is-sticky .ast-header-social-1-wrap svg,
.ast-main-header-wrap.is-sticky .ast-header-social-wrap svg {
    fill: #333333 !important; /* Dark color when sticky */
}

/* DROPDOWN MENU STYLES - CONSISTENT FOR BOTH DEFAULT AND STICKY STATES */
.main-header-menu .sub-menu,
.ast-builder-menu-element .sub-menu,
.ast-main-header-wrap.is-sticky .main-header-menu .sub-menu,
.ast-main-header-wrap.is-sticky .ast-builder-menu-element .sub-menu {
    background-color: rgba(255, 255, 255, 0.95) !important;
    backdrop-filter: blur(5px);
    min-width: 200px;
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}

/* Dropdown menu items - consistent styling */
.main-header-menu .sub-menu li,
.ast-builder-menu-element .sub-menu li,
.ast-main-header-wrap.is-sticky .main-header-menu .sub-menu li,
.ast-main-header-wrap.is-sticky .ast-builder-menu-element .sub-menu li {
    background-color: transparent;
}

/* Dropdown menu links - consistent styling */
.main-header-menu .sub-menu a,
.ast-builder-menu-element .sub-menu a,
.ast-main-header-wrap.is-sticky .main-header-menu .sub-menu a,
.ast-main-header-wrap.is-sticky .ast-builder-menu-element .sub-menu a {
    color: #333333 !important;
    padding: 15px 20px;
    display: block;
    text-decoration: none;
    font-weight: 400;
}

.main-header-menu .sub-menu a:hover,
.ast-builder-menu-element .sub-menu a:hover,
.ast-main-header-wrap.is-sticky .main-header-menu .sub-menu a:hover,
.ast-main-header-wrap.is-sticky .ast-builder-menu-element .sub-menu a:hover {
    background-color: rgba(0, 124, 186, 0.1) !important;
    color: #007cba !important;
}

.main-header-menu li:hover .sub-menu,
.ast-builder-menu-element li:hover .sub-menu {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

Ubayed-Bin-Sufian avatar Jul 21 '25 09:07 Ubayed-Bin-Sufian

TASK: Add functions to the functions.php file

Steps to Implement:

  1. Create PHP File:

    • Navigate to: wp-content/themes/astra-child/
    • Create a new file named: functions.php
  2. Add PHP Code:

    • Open functions.php and paste the following code and save the file:
<?php
/**
 * Astra Child Theme functions and definitions
 *
 * This file is where you'll add custom functions for your child theme.
 * It's crucial not to modify the parent theme's files directly, as your
 * changes would be lost during theme updates.
 */

/**
 * Enqueue child theme styles and custom scripts.
 *
 * Note: Astra automatically handles parent theme stylesheets through its
 * sophisticated enqueue system. We only need to enqueue our custom assets.
 */
function astra_child_enqueue_styles() {
    // Get theme version for cache busting
    $theme_version = wp_get_theme()->get('Version');
    
    // Enqueue custom JavaScript for the sticky header
    // Loaded in footer for better performance
    wp_enqueue_script( 
        'astra-child-sticky-header', 
        get_stylesheet_directory_uri() . '/custom-sticky.js', 
        array(), // No dependencies needed for vanilla JS
        $theme_version, 
        true // Load in footer
    );
}

// Hook the enqueue function to the 'wp_enqueue_scripts' action
add_action( 'wp_enqueue_scripts', 'astra_child_enqueue_styles' );
  1. Verify the File Is Active:

    • Go to WordPress Dashboard > Appearance > Theme File Editor.
    • Select the Astra Child theme.
    • Confirm functions.php is listed.
Image

Ubayed-Bin-Sufian avatar Jul 21 '25 09:07 Ubayed-Bin-Sufian

Limitations

I was unable to update the functions.php file directly from the WordPress admin dashboard.

Image

Workaround

As a workaround, I manually edited the functions.php file located in the wp-content/themes/astra-child/ directory.

Ubayed-Bin-Sufian avatar Jul 27 '25 17:07 Ubayed-Bin-Sufian

TASK: Change the color of social links and site logo on scrolling

Added the additional css to https://github.com/fossasia/codeheat.org/issues/368#issuecomment-3095935079 starting with comments /* Logo color change on sticky */

Ubayed-Bin-Sufian avatar Jul 29 '25 06:07 Ubayed-Bin-Sufian

Screencast of Sticky Headers

https://github.com/user-attachments/assets/d91c2cdb-ffb0-4778-afcf-65eaa08c2459

Ubayed-Bin-Sufian avatar Jul 29 '25 06:07 Ubayed-Bin-Sufian

ISSUE: Change color of drop down menu

Change color of the drop-down menu from transparent to white similar to original website

Image

Ubayed-Bin-Sufian avatar Jul 29 '25 16:07 Ubayed-Bin-Sufian

TASK: Change color of drop down menu

Added the additional css to https://github.com/fossasia/codeheat.org/issues/368#issuecomment-3095935079 starting with comments /* DROPDOWN MENU STYLES - CONSISTENT FOR BOTH DEFAULT AND STICKY STATES */

Image

https://github.com/user-attachments/assets/2a37bbe6-0976-45af-bc88-7a74aeb92e90

Screencast of drop down menu

Ubayed-Bin-Sufian avatar Aug 02 '25 17:08 Ubayed-Bin-Sufian

Final Iteration


/* HEADER DEFAULT STATE - FIXED TO TOP FOR INITIAL APPEARANCE AND SMOOTH TRANSITION */
.ast-main-header-wrap {
    /* Merged Properties: Fixed position takes precedence */
    position: fixed; /* Ensures header is always at the top and covers the full width */
    top: 0;
    width: 100%;
    z-index: 999; /* Higher z-index ensures it's above other elements */
    
    /* Existing properties for smooth transition and default look */
    transition: all 0.3s ease-in-out;
    background-color: transparent;
}

/* Use transform for smoother animations - This class is added on scroll by JavaScript */
.ast-main-header-wrap.is-sticky {
    /* 'position: fixed;' is now redundant here but kept for clarity/safety */
    position: fixed; 
    width: 100%;
    background-color: rgba(255, 255, 255, 0.9);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
    backdrop-filter: blur(5px); /* Optional: for frosted glass effect */
    transform: translateZ(0); /* Hardware acceleration */
}

/* Prevent layout shift by reserving space */
body {
    /* You'll need to use JavaScript to add padding-top to the body 
       equal to the header's height when the 'is-sticky' class is *not* present,
       or simply rely on the 'position: fixed' always being active. 
       If 'position: fixed' is ALWAYS on, the body padding is only needed to push 
       the *content* down, not to prevent a 'shift'. */
    padding-top: 0; 
    transition: padding-top 0.3s ease-in-out;
}

/* Text color transitions */
.ast-main-header-wrap .main-header-menu a,
.ast-main-header-wrap .ast-builder-menu-element a,
.ast-main-header-wrap .ast-social-stack a,
.ast-main-header-wrap .ast-social-stack svg,
.ast-main-header-wrap .ast-social-stack i,
.ast-main-header-wrap .site-title a,
.ast-main-header-wrap .site-description {
    transition: color 0.3s ease-in-out;
}

.ast-main-header-wrap.is-sticky .main-header-menu a,
.ast-main-header-wrap.is-sticky .ast-builder-menu-element a,
.ast-main-header-wrap.is-sticky .ast-social-stack a,
.ast-main-header-wrap.is-sticky .ast-social-stack svg,
.ast-main-header-wrap.is-sticky .ast-social-stack i,
.ast-main-header-wrap.is-sticky .site-title a,
.ast-main-header-wrap.is-sticky .site-description {
    color: #333333 !important;
}

/* Logo color change on sticky */
.ast-main-header-wrap .site-logo-img img,
.ast-main-header-wrap .custom-logo {
    transition: filter 0.3s ease-in-out;
}

.ast-main-header-wrap.is-sticky .site-logo-img img,
.ast-main-header-wrap.is-sticky .custom-logo {
    filter: brightness(0) saturate(100%) invert(20%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(20%) contrast(100%);
}

/* Social icons color change on sticky */
.ast-main-header-wrap .ast-header-social-1-wrap svg,
.ast-main-header-wrap .ast-header-social-wrap svg {
    transition: fill 0.3s ease-in-out;
    fill: white; /* Default white color */
}

.ast-main-header-wrap.is-sticky .ast-header-social-1-wrap svg,
.ast-main-header-wrap.is-sticky .ast-header-social-wrap svg {
    fill: #333333 !important; /* Dark color when sticky */
}

/* DROPDOWN MENU STYLES - CONSISTENT FOR BOTH DEFAULT AND STICKY STATES */
.main-header-menu .sub-menu,
.ast-builder-menu-element .sub-menu,
.ast-main-header-wrap.is-sticky .main-header-menu .sub-menu,
.ast-main-header-wrap.is-sticky .ast-builder-menu-element .sub-menu {
    background-color: rgba(255, 255, 255, 0.95) !important;
    backdrop-filter: blur(5px);
    min-width: 200px;
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}

/* Dropdown menu items - consistent styling */
.main-header-menu .sub-menu li,
.ast-builder-menu-element .sub-menu li,
.ast-main-header-wrap.is-sticky .main-header-menu .sub-menu li,
.ast-main-header-wrap.is-sticky .ast-builder-menu-element .sub-menu li {
    background-color: transparent;
}

/* Dropdown menu links - consistent styling */
.main-header-menu .sub-menu a,
.ast-builder-menu-element .sub-menu a,
.ast-main-header-wrap.is-sticky .main-header-menu .sub-menu a,
.ast-main-header-wrap.is-sticky .ast-builder-menu-element .sub-menu a {
    color: #333333 !important;
    padding: 8px 20px;
    display: block;
    text-decoration: none;
    font-weight: 400;
}

/* Force dropdown padding for normal AND sticky states */
.main-header-menu .sub-menu a,
.ast-builder-menu-element .sub-menu a {
    padding: 8px 20px !important;
}


.main-header-menu .sub-menu a:hover,
.ast-builder-menu-element .sub-menu a:hover,
.ast-main-header-wrap.is-sticky .main-header-menu .sub-menu a:hover,
.ast-main-header-wrap.is-sticky .ast-builder-menu-element .sub-menu a:hover {
    background-color: rgba(0, 124, 186, 0.1) !important;
    color: #007cba !important;
}

.main-header-menu li:hover .sub-menu,
.ast-builder-menu-element li:hover .sub-menu {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

Ubayed-Bin-Sufian avatar Oct 10 '25 12:10 Ubayed-Bin-Sufian