[react] 스플래시 화면 꾸미기 #1 - swiper 와 emotion 활용 with next.js

2023. 2. 13. 01:22
728x90
반응형

프롤로그

progresive웹 앱으로 기록 앱을 만들기로 한 [그리디브] 팀원들. 약 3주차에 걸쳐 나는 회원가입 폼을 완성해 내었다. 그리고 부여 받은 할일은 style 을 입히는 작업이다. 에이전시에서 퍼블리싱 작업을 하고 있는 나는 html, css, js, jquery 로 주로 작업을 해왔는데 React 를 배우며 다양한 style 을 입히는 라이브러리와 방법들을 접해왔다. css 가 기초적 기반이라 어려움은 없었지만 사용방법이 달라 생소한 부분들이 많았다. 회원가입 폼을 styling 하기에 앞서 모바일의 첫 화면이 될 스플래쉬 화면을 먼저 꾸며 보기로 했다.

스플래쉬 모바일 화면

스플래시 화면?

모바일 앱을 시작할 때 첫인상과 같은 역할을 하는 표지 화면을 본 적이 있다. 우리는 그것을 스플래시 화면이라고 부른다. 로딩바가 진행 되면서 아이콘을 보여주는 어플도 있고 여러 페이지로 모바일 앱의 설명을 담아서 시작 가이드의 느낌을 주는 앱도 있다. 잘 꾸며진 스플래시 화면은 모바일 어플의 정체성을 만들고 좋은 첫인상을 심어줘서 앱을 더 궁금하게 만들기도 한다.

스플래시 화면에 대해 간략하게 설명하자면 이렇다고 한다.
출처는 팁스터

스플래시 스크린의 시작은 애플로, 더 나은 사용자 경험을 위해 앱이 빠르게 반응하는 것처럼 보이도록 Placeholder Image를 요구했어요. 기능적으로 이는 앱 아이콘을 탭 하고, 앱이 실제로 실행되는 사이의 짧은 간격을 메우는데 중요한 역할을 하게 되었습니다. 이제 스플래시는 기능적 측면보다 브랜딩 측면에서 더 자주 사용되고 있는데요. 반드시 거쳐가는 시간이자 화면이기 때문입니다.

기능적인 부분도 있지만 브랜딩 측면에서 더욱 자주사용되고 중요한 부분. 나도 애니메이션을 사용한 스플래시 화면을 본 적이 있었는데 한눈에 어떤 앱인지 알 수 있었다.

기능적인 부분 설명

화려한 애니메이션이 있으면 좋겠지만 우선 사용자가 직접 넘기면서 간략한 설명을 인지 할 수 있도록 4페이지의 화면을 구성했다. (중간에 겹치는 부분은 생략하기로 했다.) 그리고 마지막 화면에는 로그인 페이지를 넣고 누르면 이동 할 수 있도록 해주자.

swiper 라이브러리르 사용해 슬라이드와 페이지네이션 기능을 넣고, emotion 으로 styling 을 해주기로 하자.

swiper

swiper 는 js 사용법과 비슷했다. 오히려 사실 react 가 더 간략해서 허무했을 정도
swiper 리액트
cdn link 로 불러오지 않고 yarn 으로 설치해 줬다.

yarn add swiper

그리고 바로 import 하고 컴포넌트 구조를 만들어 준다.
길어보이지만 swiper 안에 필요한 swiperSlide 컴포넌트를 만들어 주면 된다. swiper 에는 필요한 옵션들을 props 로 보내주자. 나는 페이지네이션을 쓸거라서 modules  pagination 을 따로 설치해주고 불러왔다. (css 도 함께 import 해주어야 한다.)

 <Swiper
          modules={[Pagination]}
          pagination={{
            type: "fraction",
            clickable: true,
          }}
          spaceBetween={0}
          slidesPerView={1}
          className="mySwiper"
          onSlideChange={() => console.log("slide change")}
          onSwiper={(swiper) => console.log(swiper)}
        >
          <SwiperSlide>
            <main css={[main]}>
              <Image
                src={mainImage01}
                layout="fill"
                objectFit="cover"
                quality={100}
              />
              <h1 css={[title]}>
                DEAR MY
                <br /> YOGA JOURNEY
              </h1>
              <Image src={mainIcon} css={yogapose01} width={694} height={455} />
            </main>
          </SwiperSlide>
          <SwiperSlide>
            <main css={[main]}>
              <Image
                src={mainImage01}
                layout="fill"
                objectFit="cover"
                quality={100}
              />
              <h1 css={[title]}>
                We practice <br /> Yoga and <br /> Keep a Journal
              </h1>
              <Image src={mainIcon} css={yogapose02} width={694} height={455} />
            </main>
          </SwiperSlide>
          <SwiperSlide>
            <main css={[main]}>
              <Image
                src={mainImage01}
                layout="fill"
                objectFit="cover"
                quality={100}
              />
              <h1 css={[title]}>
                WE <br /> CONNECTED WITH LIFE <br /> THROUGH THIS
              </h1>
              <Image
                src={mainIcon02}
                css={yogapose03}
                width={694}
                height={455}
              />
            </main>
          </SwiperSlide>
          <SwiperSlide>
            <main css={[main]}>
              <Image
                src={mainImage01}
                layout="fill"
                objectFit="cover"
                quality={100}
              />
              <h1 css={[title]}>
                DEAR MY <br /> YOGA JOURNEY
              </h1>
              <div css={[utils]}>
                <div css={utils_tit}>Start your Yoga Life</div>
                <Button css={button} onClick={() => linkTo("/signup")}>
                  Join Now
                </Button>
                <Button css={button} onClick={() => linkTo("/login")}>
                  Login
                </Button>
              </div>
            </main>
          </SwiperSlide>
        </Swiper>

emotion

emotion 으로 styling 을 해주기 위해 emotion 설치 진행해준다.
Emotion 리액트

yarn add @emotion/react

css 를 그냥 쓰는게 익숙해져있는 나는 className 을 주고 css 를 써도 됐지만 emotion 을 사용해서 (더 리액트 다운 방식으로 🤔) 스타일링을 해주기로 했다. 하지만 bakcground 를 불러오거나 이미지를 불러오는 부분에 있어서 조금 애를 먹었다.

emotion 으로 global style 지정

우선 가장 기초적인 reset css 를 글로벌로 불러오자. 이 emotion 에 들어있는 reset 부분도 따로 설치를 해줬다. 그리고 global 도 꺼내 와준다.

import emotionReset from "emotion-reset";
import { Global, css } from "@emotion/react";

리턴 함수에 <></> 감싸주고 하위에 글로벌 컴포넌트로 감싸주었다.
emotion 은 css`` 이런식으로 정의하고 css 속성을 주었다.

 <Global
        styles={css`
          ${emotionReset}

          body {
            font-family: "Roboto";
            width: 390px;
            margin: 0 auto;
          }
        `}
      />

emotion 으로 background 주기

그리고 이제 배경화면을 줘야하는데 아무리 찾아도 emotion 에서 백그라운드를 어떻게 props 로 보내주는지 모르겠는것이다😨 그러다가 next.js 에서 emotion 을 활용해서 bakcgournd 전체를 주는 방법을 찾았는데 next.js 에서 제공하는 <Image/> 컴포넌트를 활용하는 것이었다.

nextjs 이미지 사용법
백그라운드 이미지

공식문서에서 제공하는 예제를 따라봤다.
방법은 이러하다. <Image/> 컴포넌트를 활용 해서 프로퍼티로 그 이미지를 꽉 채워주는것이다. layout="fill" 속성을 주자! 이 속성은 주로 함께 objectFit 속성과 함께 온다고 한다. quality 는 화질설정!

그리고 그 이미지 컴포넌트는 position: relative 로 떠 있다. 근데 진짜 emotion 에서 백그라운드로 이미지를 주는 방법은 없는 것인가?

<Image
  src={mainImage01}
  layout="fill"
  objectFit="cover"
  quality={100}
/>

그리고 nextjs 에서 image 를 불러오는 방식도 따로 존재했다.
import 로 불러오거나 require 로 직접 써주거나!
import 로 불러오면 각 이미지의 사용할 이름을 써주고 불러온다.
image 폴더는 public 폴더 안에 넣어 주었다.

import Humaaans from "../public/img/Humaaans.png";
import mainImage01 from "../public/img/mainbackground.png";
import mainIcon from "../public/img/mainIcon.png";
import mainIcon02 from "../public/img/mainIcon02.png";

<Image src={mainIcon} css={yogapose01} width={694} height={455} />

emotion 으로 css styling

그리고 emotion 의 방식이 불편하면서도 적응이 되면 편하려나
이렇게 각 클래스를 부여하는 것 처럼 css={classname 명} 지어주고, 각 변수로 할당해 주었다. styling 은 사실 css 방식과 동일

const main = css`
  height: 100vh;
  width: 100%;
`;

const title = css`
  font-size: 3vw;
  font-weight: 800;
  height: 350px;
  color: #222;
  opacity: 0.9;
  padding: 15vw 1.5vw 5vw;
  box-sizing: border-box;
  letter-spacing: -0.01em;
  font-family: "Roboto Mono";
`;
const imagebox = css`
  width: 100%;
  background-color: #2a4337;
`;
const yogapose01 = css`
  transform: translateX(10%);
  width: 150% !important;
  height: 455px !important;
  max-width: initial !important;
`;
const yogapose02 = css`
  transform: translateX(-40%);
  width: 150% !important;
  height: 455px !important;
  max-width: initial !important;
`;
const yogapose03 = css`
  width: 40% !important;
  height: 100% !important;
  max-width: initial !important;
  min-width: initial !important;
  transform: translateX(50%);
`;
const utils = css`
  display: flex;
  flex-direction: column;
  position: relative;
  z-index: 9;
  padding: 1.5vw;
`;
const utils_tit = css`
  font-size: 2vw;
  line-height: 1.4;
  color: #fff;
`;
const button = css`
  color: #3a3a3a;
  background-color: #fff;
  opacity: 0.8;
  border-radius: 5px;
  outline: none;
  appearance: none;
  border: none;
  padding: 13px;
  margin: 5px 0;
  font-size: 2vw;
  color: #2a4337;
  font-weight: 600;
`;

각각의 클래스네임을 지정해주고 css 부여

emotion 을 더 잘 사용하기 위하여

emotion 을 쓰다보니 불편한 점이 하나 있었는데 빽틱을 사용하다 보니까 자동완성이 안되는 것이었다. vs code 를 사용하는 이유중의 하나인것을..
근데 바로 vs code 플러그인이 있다는 사실을 듣고 설치를 진행했다. 그리고 아주 편안하고 오타없이 css 작성을 할 수 있었다.

결과

에필로그

css 를 작성하는데는 무리가 없었지만 새로운 방식으로 진행을 하다보니 꽤 시간이 걸렸다. 하지만 공식문서를 토대로 찾아보고 어느정도 아는 개념들이 있어 막막하지는 않았다. 하지만 css 한 파일에 코드를 몰아 넣지 않고, 컴포넌트 별로 분리하고 그 안에서 모든 것을 작성하는 방식이 효율적인지는 아직은 모르겠다. 기껏 많아 봤자 두페이지 정도 밖에 되지 않기 때문이다. 뭔가 더 작은 컴포넌트 단위로 나누어야 할 것 같다. 폴더 구조도 아직 정확한 개념은 아니어서 아무래도 이번 스터디 때 팀원들에게 도움을 요청 해봐야 겠다.

728x90
반응형