React로 광원 효과 만들기

Jiwoo JEONG·2021년 12월 28일
1

Velog를 보다가 LOCKED님의 Flutter로 광원효과 만들기 글을 보았다.
나도 해보고 싶다!

LOCKED님의 글

어떻게 만들것인가!
1. 라이브러리 사용하지말자!
2. styled-component의 css적 요소만 사용하자!

본격적으로 시작!

일단은 styled-component로 div를 하나 만들었다

const Card = styled.div`
    width:200px;
    height:120px;
`;

우선 background-color를 radial-gradient로 채우자!

const Card = styled.div`
    width:200px;
    height:120px;
    background: radial-gradient(
    	farthest-corner at 10% 10%,
    	#ffffff 0%,
    	#f34161 80%
  	);
`;

animation을 넣자! 그 전에.. 마우스가 들어갔을 때를 알기 위해서 eventHandler 처리!

...
const Controller : React.FC = () => {
	const [hover, setHover] = useState<boolean>(false);
    
    	const onMouseEnter = () => {
        	setHover(true);
        }
        const onMouseLeave = () => {
        	setHover(false);
        }
        
        return (
        ...
        <Presenter 
        	hover={hover} 
        	onMouseEnter={onMouseEnter}
        	onMouseLeave={onMouseLeave}
        />
        )
}

interface PresenterProps {
	hover:boolean;
    	onMouseEnter:()=>void;
        onMouseLeave:()=>void;
}

const Presenter : React.FC<PresenterProps> = (props) => {
	const {hover, onMouseEnter, onMouseLeave} = props;
    	return(
    	...
    	<Card onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}/>
    	)
}
          
    

이벤트 핸들러 추가 ! 그리고 애니메이션 추가!

...

const Presenter : React.FC<PresenterProps> = (props) => {
	const {hover, onMouseEnter, onMouseLeave} = props;
    	return(
    	...
    	<Card onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} hover={hover} />
    	)
}
...
const Card = styled.div<{hover:boolean}>`
    width:200px;
    height:120px;
    background: radial-gradient(
    	farthest-corner at 10% 10%,
    	#ffffff 0%,
    	#f34161 80%
  	);
    animation: 0.4s forwrads ${props => props.hover ? 'rotateFrom' : 'rotateTo'};
    
    @keyframes rotateTo {
    	0% {
          background: radial-gradient(
          farthest-corner at 90% 90%,
          #ffffff 0%,
          #f34161 80%);
        }
        100% {
          background: radial-gradient(
          farthest-corner at 10% 10%,
          #ffffff 0%,
          #f34161 80%);
        }
    }
     @keyframes rotateFrom {
    	0% {
          background: radial-gradient(
          farthest-corner at 10% 10%,
          #ffffff 0%,
          #f34161 80%);
        }
        100% {
          background: radial-gradient(
          farthest-corner at 90% 90%,
          #ffffff 0%,
          #f34161 80%);
        }
    }
`;

그런데 ! 이거 애니메이션이 안된다 ... 그래서 찾아봤더니 !

const Card = styled.div<{hover:boolean}>`
  @property --x {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 0%;
  }
  @property --y {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 0%;
  }
    width:200px;
    height:120px;
    background: radial-gradient(
    	farthest-corner at var{--x} var{--y},
    	#ffffff 0%,
    	#f34161 80%
  	);
    animation: 0.4s forwrads ${props => props.hover ? 'rotateFrom' : 'rotateTo'};
    
    @keyframes rotateTo {
    	0% {
           --x: 110%;
      	   --y: 80%;
        }
        100% {
           --x: -20%;
      	   --y: 20%;
        }
    }
     @keyframes rotateFrom {
    	0% {
           --x: -20%;
      	   --y: 20%;
        }
        100% {
           --x: 110%;
      	   --y: 80%;
        }
    }
`;

이렇게 하면 radial-gradient가 애니메이션이 된다! 헤헤
조금 더 나아가서 transform : rotate3d()를 주자!

const Card = styled.div<{hover:boolean}>`
  @property --x {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 0%;
  }
  @property --y {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 0%;
  }
    width:200px;
    height:120px;
    background: radial-gradient(
    	farthest-corner at var{--x} var{--y},
    	#ffffff 0%,
    	#f34161 80%
  	);
    animation: 0.4s forwrads ${props => props.hover ? 'rotateFrom' : 'rotateTo'};
    
    @keyframes rotateTo {
    	0% {
           --x: 110%;
      	   --y: 80%;
 	   transform: rotate3d(0, 1, 0, -30deg) rotate3d(0, 0, 0.2, -5deg)
        rotate3d(1, 0, 0, 5deg);
        }
        100% {
           --x: -20%;
      	   --y: 20%;
           transform: rotate3d(0, 1, 0, 15deg) rotate3d(0, 0, -0.2, 5deg)
        rotate3d(1, 0, 0, 0deg);
        }
    }
     @keyframes rotateFrom {
    	0% {
           --x: -20%;
      	   --y: 20%;
           transform: rotate3d(0, 1, 0, 15deg) rotate3d(0, 0, -0.2, 5deg)
        rotate3d(1, 0, 0, 0deg);
        }
        100% {
           --x: 110%;
      	   --y: 80%;
	   transform: rotate3d(0, 1, 0, -30deg) rotate3d(0, 0, 0.2, -5deg)
        rotate3d(1, 0, 0, 5deg);
        }
    }
`;

이렇게 하면 !!

결과물 두둥탁

참고
LOCKED 님의 velog : https://velog.io/@locked/Flutter-%EA%B7%B8%EB%9D%BC%EB%8D%B0%EC%9D%B4%EC%85%98%EC%9C%BC%EB%A1%9C-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EB%8A%94-%EA%B4%91%EC%9B%90-%ED%9A%A8%EA%B3%BC
MDN transform : https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate3d()
MDN radial-gradietn: https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/radial-gradient()

profile
FE Developer as Efficiency Maker

0개의 댓글