2

I'm trying to make a Sticky Header that can change its background-color based on his position on the page. To do that, I'm trying to add a className "active" to my Styled Component "StyledHeader" that will appears when the scrollPositionY is above 400px and disappear when below.

In other words, what I want to do is something like this but using React.JS, JSX syntax and Styled Components.

Here's what I have for now:

import { Link } from '@reach/router';

import DuskLogo from '../images/dusk_logo.svg';

import { 
    StyledHeader, 
    StyledDuskLogo
} from '../styles/StyledHeader';

const Header = () => (
<StyledHeader>
  <div className="header-content">
    <Link to="/">
    <StyledDuskLogo src={DuskLogo} alt="dusk-logo" />
    </Link>
  </div>
</StyledHeader>
)

export default Header;

Do you know a simple way to do it ?

2 Answers 2

2

add an event listener in your useEffect. when you scroll down the value of window.scrollY will increase such as 1, 2, ...100 .. (in px) and update your color in useState as per the window.scrollY. try something like this

const StyledBody = window.styled.div`
  background: lightgray;
  height: 5000px;
`;

const StyledText = window.styled.h4`
  text-align: center;
  width: 250px;
  margin: auto;
  line-height: 40px;
`;

const StyledHeader = window.styled.div`
  background-color: ${props => props.color};
  width: 100%;
  height: auto;
  position: fixed;
  top: 0;
  left: 0;
  right: 0px;
  padding: 0;
  z-index: 10000;
  transition: all 1s ease-in-out;
`;

const Header = () => {
  const [color, setColor] = React.useState("rgba(17, 42, 107, 0.7)");

  const handleScroll = React.useCallback((event) => {
    let scrollTop = window.scrollY;

      //console.log(scrollTop );  //1,2,...100,...200...etc (in px)

      if (scrollTop >= 20 && scrollTop < 50) {
        setColor("yellow");
      }

      if (scrollTop >= 50 && scrollTop < 90) {
        setColor("red");
      }

      if (scrollTop >= 90 && scrollTop < 120) {
        setColor("green");
      }
      if (scrollTop >= 120 && scrollTop < 150) {
        setColor("blue");
      }
      if (scrollTop >= 150 && scrollTop < 180) {
        setColor("violet");
      }
      if (scrollTop >= 180 && scrollTop < 210) {
        setColor("purple");
      }
});

  React.useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => {
      window.removeEventListener("scroll", handleScroll, false);
    };
  }, []);

  return (
    <StyledBody>
      <StyledHeader color={color}>
        <StyledText>My background color changes</StyledText>
      </StyledHeader>
    </StyledBody>
  );
};

export default Header;

here is a working demo ..change the code as per your need.demo

Edit: I have added styled-components for you. check it out and let me know whether it works for you. to know more about these hooks go to useEffect and useCallback

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for this detailled answer, but I can't get it to work on my project. I do not see how I could target Header or "StyledHeader" instead of "#app". Mainly because Header become a div with only a random generated class. I've also tried to apply a class to the Header and target it, but it doesn't seems to work too. I'm doing something wrong here
@Dabu I have updated my code. let me know whether it works
0

haven't run this code myself but could be something like:

const Header = () => {
  const headerEl = React.useRef();
  const [offsetTop, setOffsetTop] = React.useState(0);

  React.useEffect(() => {
    window.addEventListener("scroll", onScroll, false);
    return () => {
      window.removeEventListener("scroll", onScroll, false); // to remove scroll event on unmount
    };
  }, []);

  const onScroll = () => setOffsetTop(headerEl.current.offsetTop);

  return (
    <StyledHeader ref={headerEl} className={offsetTop > 400 ? "active" : ""}>
      ...
    </StyledHeader>
  );
};

export default Header;

1 Comment

This doesn't seems to work unfortunately, offsetTop keeps returning 0 for me

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.