🎞️ 롤링 슬라이드
주식이나 뉴스같은 곳에서 한줄로 끊임없이 텍스트가 물처럼 한방향으로 흐르거나 요즘 트렌드의 스타일로 작성된 사이트들을 구경하다 보면 자주 접할 수 있는 스타일의 UI이다.
텍스트뿐만 아니라 관련된 이미지를 통해서도 좀 더 인터렉티브하고 동적으로 움직이다보니 시각적으로 집중이 되는 효과를 확인 할 수 있다.
대표적으로 찾은 기능으로 네이버의 vibe사이트에서 추천 플레이리스트 부분에 아티스트들의 앨범 정보가 끊임없이 흐르는 애니메이션도 볼 수 있는데, 해당 기능을 참고하여 구현하고자 한다.
바이브 url: https://vibe.naver.com/about/.
🤔 동작 방식
구현하기 전 구현에 대한 설명이 필요하다.
- 먼저 슬라이드 형태로 흘러가야할 요소들을 한줄로 세워준다.
- 똑같은 요소들을 하나 더 만들어준다.
- css 속성을 통해 한줄로 이어서 붙여준다. (부모속성에 flex와 nowrap처리를 통해 쉽게 구현이 가능하다.)
- 한줄이 된 슬라이드를 각기 다른 옵션으로 애니메이트를 처리한다.
- 첫번째 원본 영역을 10초간 이동하면 그동안 빈 공백의 10초를 기다려야 하는데, 이때 복사 영역으로 똑같이 붙여서 10초간 이동시키고 무한으로 돌린다.
- 슬라이드 영역에 마우스를 올리면
animation-play-state
의 값을paused
처리 하는 클래스를 토글 형태로 처리하면 된다..stop{ animation-play-state: paused; }
⚙️ 구현에 필요한 기술
css 레이아웃 개념과 animation
의 개념, @keyframe
사용법 익히면 별다른 라이브러리 없이 구현이 가능하다.
hook또한 useState하나만 사용하여 처리 할 예정이다.
아래 구현 예시를 확인해보자.
🪄 구현 시작
HomePage.tsx
import { useState } from "react";
import "./Homepage.scss";
const slides = [
{ color: "red", target: "#" },
{ color: "orange", target: "#" },
{ color: "yellow", target: "#" },
{ color: "green", target: "#" },
{ color: "blue", target: "#" },
{ color: "navy", target: "#" },
{ color: "purple", target: "#" },
];
export default function Homepage() {
const [animate, setAnimate] = useState(true);
const onStop = () => setAnimate(false);
const onRun = () => setAnimate(true);
return (
<div className="wrapper">
<div className="slide_container">
<ul
className="slide_wrapper"
onMouseEnter={onStop}
onMouseLeave={onRun}
>
<div
className={"slide original".concat(
animate ? "" : " stop"
)}
>
{slides.map((s, i) => (
<li
key={i}
className={i % 2 === 0 ? "big" : "small"}
>
<div
className="item"
style={{ background: s.color }}
></div>
</li>
))}
</div>
<div
className={"slide clone".concat(animate ? "" : " stop")}
>
{slides.map((s, i) => (
<li
key={i}
className={i % 2 === 0 ? "big" : "small"}
>
<div
className="item"
style={{ background: s.color }}
></div>
</li>
))}
</div>
</ul>
</div>
</div>
);
}
Homepage.scss
* {
padding: 0;
margin: 0;
}
ul,
li {
list-style: none;
}
.wrapper {
.slide_container {
overflow: hidden;
.slide_wrapper {
display: flex;
flex-wrap: nowrap;
}
.slide {
display: flex;
align-items: center;
flex-wrap: nowrap;
position: relative;
border-top: 1px solid #bbb;
border-bottom: 1px solid #bbb;
padding: 40px 0;
&::before {
content: "";
display: block;
width: 100%;
height: 1px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #bbb;
z-index: 1;
}
&.original {
animation: 10s linear infinite normal none running
infiniteAnimation1;
}
&.clone {
animation: 10s linear infinite infiniteAnimation2;
}
&.stop {
animation-play-state: paused;
}
li {
margin: 0 80px;
cursor: pointer;
z-index: 2;
transition: 0.3s;
transform: scale(1);
&:hover {
transform: scale(0.98);
&::after {
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.2);
}
}
&.big {
width: 280px;
height: 280px;
}
&.small {
width: 200px;
height: 200px;
}
.item {
width: 100%;
height: 100%;
}
}
}
}
}
@keyframes infiniteAnimation1 {
0% {
transform: translateX(0%);
}
50% {
transform: translateX(-100%);
}
50.1% {
transform: translateX(100%);
}
100% {
transform: translateX(0%);
}
}
@keyframes infiniteAnimation2 {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-200%);
}
}
✨ 구현 결과물
아주 잘된다.
바이브처럼 뒷부분에 선도 그어봤다.
괜찮은 배경이미지와 색상 대신 이미지를 활용하면 더욱 좋은 결과물을 볼 수 있을 것 같다.
(아래는 위 소스를 기반으로 작성한 리액트 샘플 소스를 받아볼 수 있는 github주소입니다.)
'WEB > React' 카테고리의 다른 글
이제는 Vite로 개발을 해보자(CRA안녕...) (0) | 2023.07.17 |
---|---|
Vite - 환경 변수 설정하고 불러오기 (0) | 2023.07.10 |
Redux 개념에 대해 알아보기(vanilla redux작성) (0) | 2023.06.14 |
React - hook 파헤치기(useMemo) (0) | 2023.06.05 |
React - typescript 버전으로 변경하면서 오류 해결 (0) | 2023.06.05 |