Search code examples
reactjsscrollblurstyled-components

Reactjs Howto Blur Background image on scroll?


I'm new to reactjs and I would like understand how to reproduce this jquery example in Reactjs styled-components : Blurring background image on event "Scroll" https://jsfiddle.net/BinaryMoon/8jhw2/

$(document).ready(function() {
    $(window).scroll(function(e) {
        var s = $(window).scrollTop(),
            opacityVal = (s / 200);

        $('.blurred-image').css('opacity', opacityVal);
    });
});
.img-src { 
    position: absolute;
    background:url(http://bromleydemo.files.wordpress.com/2013/10/blossom.jpg?w=600) center center;
    background-size: cover;
}

as you've seen the background url is set into css prop I've tried something in reactjs but each time I scroll, the image background is reloaded. Can somebody help me ?

ps : If the solution can be implemented with styled-components it will be awesome

ps2 : this is another page of the effect i'm trying to implement https://codepen.io/zrichard/pen/wEFBd

Thank you


Solution

  • You can bind an event listener to the window using the useEffect hook.

    Live sandbox.

    import React, { useState, useEffect } from "react";
    import styled, { css } from "styled-components";
    import { hydrate, render } from "react-dom";
    
    function App() {
      const [opacity, setOpacity] = useState(0);
    
      useEffect(() => {
        const onScroll = () => setOpacity(window.scrollY / 200);
    
        window.addEventListener("scroll", onScroll);
    
        return function cleanup() {
          window.removeEventListener("scroll", onScroll);
        };
      }, []);
    
      return (
        <React.Fragment>
          <BlurredImageContainer>
            <ImgSrc />
            <ImgSrc blurred opacity={opacity} />
          </BlurredImageContainer>
          <Content>
            <Avatar src="https://pbs.twimg.com/profile_images/378800000748837969/bd8e553e5cae83ef488c6b15166bdd55.png" />
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
            <p>This is some test content</p>
          </Content>
        </React.Fragment>
      );
    }
    
    const BlurredImageContainer = styled.div`
      display: block;
      padding: 0;
      position: fixed;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      z-index: -1;
    `;
    
    const ImgSrc = styled.div`
      position: absolute;
      background: url("http://bromleydemo.files.wordpress.com/2013/10/blossom.jpg?w=600") center center;
      background-size: cover;
      top: -10%;
      bottom: 10%;
      left: -10%;
      right: 10%;
      width: 120%;
      height: 120%;
    
      ${props => props.blurred && css`
        opacity: ${props.opacity};
        filter: blur(20px) brightness(0.7);
      `};
    `;
    
    const Content = styled.div`
      padding: 150px 50px;
      color: #fff;
      text-align: center;
    `;
    
    const Avatar = styled.div`
      height: 120px;
      width: 120px;
      border-radius: 100%;
      border: 5px solid #fff;
      margin: 0 auto 50px;
    `;
    
    const rootElement = document.getElementById("root");
    if (rootElement.hasChildNodes()) {
      hydrate(<App />, rootElement);
    } else {
      render(<App />, rootElement);
    }