Jevon Cochran
Jevon Cochran

Reputation: 1774

changing CSS of element on page scroll

I have a fixed header component as the two pics below illustrate. The current styling that I have is fine for when the page loads and nothing has changed. However, I want the header to have a visible border-bottom of say 1px solid black as soon as the user starts to scroll down the page. So in this case, this styling change would apply to the second pic. How can I accomplish this?

header on page load: enter image description here

header on scroll: enter image description here

Header.js:

const Header = props => {
    return (
        <header className="header-container">

            <div className="logo-container">
                <img className="white-logo" src={logo} alt="Food Truck TrackR logo white" />
            </div>

            <section className="header-section-one">
                <div className="location-sub-div">
                    <i class="fas fa-map-marker-alt"></i>
                    <h3>User Location</h3>
                </div>
                <div className="order-sub-div">
                    <i class="fas fa-store"></i>
                    <h3>Order now</h3>
                </div>
            </section>

            <section className="header-section-two">
                <NavLink to="/dine/search" className="search-sub-div">
                    <i class="fas fa-search search-icon"></i>
                    <h3>Search</h3>
                </NavLink>
                <div className="acct-sub-div">
                    <i class="fas fa-user acct-icon"></i>
                    <h3>Account</h3>
                </div>
            </section>

        </header>
    )
}

Header.scss:

.header-container {
    width: 100%;
    height: 9vh;
    display: flex;
    align-items: center;
    color: black;
    background: white;
    font-size: 0.6rem;
    padding-left: 4%;
    padding-right: 4%;
    position: fixed;
    top: 0;
    // border-bottom: 1px solid black;
    z-index: 99;
}



.logo-container {
    width: 20%;
    margin-right: 6%;

    .white-logo {
        width: 100%;
    }
}

.header-section-one {
    width: 32%;
    display: flex;
    margin-right: 25%;
    justify-content: space-evenly;


    .location-sub-div {
        display: flex;

        h3 {
            width: 100%;
            white-space: nowrap;
        }
    }

    .order-sub-div {
        display: flex;

        h3 {
            white-space: nowrap;
        }
    }
}

.header-section-two {
    width: 32%;
    display: flex;
    justify-content: space-evenly;

    .search-sub-div {
        display: flex;

        .search-icon {
            margin-right: 1%;
        }
    }

    .acct-sub-div {
        display: flex;

        .acct-icon {
            margin-right: 1%;
        }
    }
}

i {
    margin-right: 1% !important;
}

Upvotes: 0

Views: 5797

Answers (2)

JMadelaine
JMadelaine

Reputation: 2964

You can add an event listener to the document, and when a scroll event is fired, you can check to see what the vertical scroll position (scrollTop) of the document is, and conditionally show a border based on that value.

Here's an example:

import React, { useEffect, useState } from "react";

const Header = () => {
  // Store a bool that determines if the border is visible
  const [isBorderVisible, setIsBorderVisible] = useState(false);

  useEffect(() => {
    // Define a function that is called when the scroll event fires
    const handleScroll = e => {
      const scrollTop = e.target.documentElement.scrollTop;
      if (scrollTop > 200) {
        setIsBorderVisible(true);
      } else {
        setIsBorderVisible(false);
      }
    };

    // Add the event listener inside a useEffect
    if (document) {
      document.addEventListener("scroll", handleScroll);
    }

    // Remove the event listener on unmount
    return () => {
      if (document) {
        document.removeEventListener("scroll", handleScroll);
      }
    };
  }, [setIsBorderVisible]);

  return (
    <div
      style={{
        position: "fixed",
        top: 0,
        left: 0,
        right: 0,
        height: "100px",
        background: "hotpink",
        // Conditionally style the border
        borderBottom: isBorderVisible ? "2px solid #000" : "0"
      }}
    />
  );
};

So we have a useEffect, that adds an event listener to the document, listening for the scroll event. Whenever a scroll occurs, the handleScroll function (also defined inside the useEffect) fires.

In this function, we get the scrollTop value, which is the number of pixels that have been scrolled from the top of the document.

In the example, we are setting the state value isBorderVisible to true once we have a scrollTop greater than 200 pixels, but this can be anything you want.

In the header's style, we conditionally set a border, based on the state value of isBorderVisible.

Upvotes: 1

Bodeby
Bodeby

Reputation: 21

This neat CSS trick might help you with the problem:

html:not([data-scroll='0']) {
    .header-container {
       width: 100%;
       height: 9vh;
       display: flex;
       align-items: center;
       color: black;
       background: white;
       font-size: 0.6rem;
       padding-left: 4%;
       padding-right: 4%;
       position: fixed;
       top: 0;
       border-bottom: 1px solid black;
       z-index: 99;
    }
}

Here is a, link further explaining the solution: https://css-tricks.com/styling-based-on-scroll-position/

Good luck.

Upvotes: 2

Related Questions