리액트에서 글라스모피즘을 적용한 반응형, 적응형 레이아웃 만들기

허민(허브)·2022년 2월 27일
11

DEMO 및 코드 보러가기 링크

원티드 기업과제를 하면서 반응형 디자인에 신경쓰지 못한 것이 아쉬워서 따로 시간을 내서 반응형 디자인에 대해 공부해보았다.

그리고 기업과제 제출시에 가독성이 떨어진다는 점으로 글라스모피즘이 적용된 디자인을 하지 못해서 아쉬움이 남아 이번 예제를 만들면서 적용해보았다

반응형 디자인이란? Responsive layouts

쉽게 말해 유저의 스크린 사이즈에 fit하게 맞는 것이다. 엘레멘트의 포지션이 바뀌지 않고 그저 화면 크기에 맞게만 변한다.

예를 들자면 사진크기가 큰 화면에선 크게 보이고 작은 화면에선 작게 보이는 것을 생각할 수 있다.

적응형 디자인이란? Adaptive layouts

유저의 화면에 잘 맞게 보이는 것까진 동일하지만, 스크린 사이즈에 따라 미디어 쿼리를 통해 엘레멘트 위치가 변한다.

예를 들어 데스크탑용 사이트와 모바일용 사이트를 예로 들 수 있을 것이다.

그럼 시작해 볼까요?

먼저 나는 react, styled-components를 활용해서 개발을 하였다. 필요하다면 css, SCSS를 활용해서 개발을 해도 좋다.

npx create-react-app myapp

CRA를 이용하여 준비를 해준다. 그리고 styled-components 를 프로젝트 dependency에 추가하도록 하자

cd myapp
npm install --save styled-components

src 폴더 내 App.js와 index.js 파일만 남겨주고 모두 삭제해준다.

우리는 flex를 활용하여 화면크기에 맞춰 카드들이 보여지도록 만들어 볼 것이다.

먼저 모바일은 24px, 테블릿 18px, 웹 16px로 세팅을 해줄 것이다.
그리고 reference는 모바일 320px width, 테블릿 720px width, 데스크탑은 1024px width에서 시작하도록 해보자.

CSS 초기화와 글로벌 설정

src 폴더 내 styles 폴더를 만들고 그 안에 global.js폴더를 만들자.

그리고 내부에 아래와 같이 작성해준다.

import { createGlobalStyle } from "styled-components";
import px2vw from "../utils/px2vw"; //converts pixels to viewport width

export const Global = createGlobalStyle`
@import url("https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Pangolin&display=swap");
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: "Roboto", sans-serif;

  }
  :root {
    font-size: ${px2vw(24)};
    background-color: #74EBD5;
    background-image: linear-gradient(90deg, #74EBD5 0%, #9FACE6 100%);
    height: 100vh;
      @media (min-width: 768px) {
        font-size: ${px2vw(18)};
      }

      @media (min-width: 1024px) {
        font-size: ${px2vw(16)};
      }
    }
`;

export default Global;

간단한 resetcss를 적용해주었고, googlefonts를 사용해서 기본 글씨가 아닌 좀 더 이쁜 글씨를 적용해보았다.
https://fonts.google.com/
여기서 본인의 맘에 드는 다른 폰트로 변경하여 적용을 해보는 것을 추천한다.

HTML root에는 앞으로 사용할 font-size와 배경을 넣었다.

https://gradienthunt.com/

해당 사이트에서 이쁜 그라디언트를 얻을 수 있으니 본인이 맘에 드는 색상을 가져와 바꿔보도록 하자.

여기서 px2vw 함수는 pixel을 viewport width로 변환해주는 함수이다. 반응형 디자인을 만들 예정이기 때문에 스크린사이즈에 맞춰서 반응하도록 하기 위함이다.

그러면 엘레멘트도 사이즈에 맞춰서 fit하게 변할 것이고 폰트도 동일하게 변할 것이다.

pixel to viewport width

const px2vw = (size, width = 1440) => `${(size / width) * 100}vw`;

export default px2vw;

src 폴더 내 utils 폴더를 만들고 utils 폴더 내 px2vw.js 를 하나 만들어주자.

기본 width 는 1440px로 설정을 해놓았다. 여기에 viewport width도 설정을 해서 개발을 할 수 도 있지만
viewport height는 smartTV 개발을 할때 문제가 있다는 이야기가 있어서 사용하지는 않았다.

layout을 만들어 볼까요?

먼저 src 폴더 내 pages 폴더를 만들고 안에 Home 폴더를 만들어주자. 그리고 Home 폴더 내 Home.js와 HomeStyles.js를 만든다.

HomeStyles.js 폴더에 아래와 같이 작성을 해준다.

import styled from "styled-components";
import px2vw from "../../utils/px2vw";

export const Title = styled.h1`
  display: flex;
  justify-content: center;
  padding-top: ${px2vw(40)};
  font-size: 2rem;
  text-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
`;

export const Container = styled.div`
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin: ${px2vw(32)};
  max-width: 100%;

  @media (min-width: 1024px) {
    flex-wrap: nowrap;
  }
`;

export const Box = styled.div`
  display: flex;
  width: ${px2vw(320, 320)};
  min-height: ${(200, 320)};
  flex-direction: column;
  padding: ${px2vw(20)};
  margin: ${px2vw(20)};
  height: 100%;

  background: rgba(255, 255, 255, 0.25);
  box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.18);

  @media (min-width: 768px) {
    width: ${px2vw(320, 768)};
    min-height: ${px2vw(200, 768)};
    height: 100%;
  }

  @media (min-width: 1024px) {
    width: ${px2vw(500)};
    min-height: ${px2vw(300)};
    height: 100%;
  }
`;

export const BoxTitle = styled.h3`
  color: white;
  font-size: 2.5rem;
  text-align: center;
  text-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);

  @media (min-width: 1024px) {
    font-size: 2rem;
  }
`;

export const BoxText = styled.p`
  margin-top: ${px2vw(20)};
  color: #444;
  font-size: 1.5rem;
  padding: ${px2vw(20)};

  @media (min-width: 1024px) {
    font-size: 1rem;
  }
`;

flex를 통해 레이아웃 요소들의 위치를 잡는다. flex layout을 통해서 나는 적응형 레이아웃을 구현해보았다.

그리고 미디어 쿼리를 통해 각 엘레멘트의 요소들의 사이즈를 수정하도록 했다. 이때 px2vw 함수를 활용해서 픽셀값으로 들어와도 viewport width로 변경해주어 반응형으로 구현되도록 할 수 있다.

그리고 Box 컴포넌트 내 글라스모피즘을 적용하기 위해 아래와 같은 코드를 추가하였다. 해당 코드는 아래의 사이트에서 만들 수 있다.
https://hype4.academy/tools/glassmorphism-generator

 background: rgba(255, 255, 255, 0.25);
  box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.18);

이렇게 스타일을 짜고 로직 레이어를 만들어 주자. HomeStyles.js와 동일한 위치에 Home.js를 생성해주고 아래와 같이 적어보자.

import React from "react";

import * as S from "./HomeStyles";

export default function Home({ boxData }) {
  return (
    <>
      <S.Title>glassmorphism responsive and adaptive layouts</S.Title>
      <S.Container>
        {boxData.map((box) => (
          <S.Box key={box.id}>
            <S.BoxTitle>{box.title}</S.BoxTitle>
            <S.BoxText>{box.text}</S.BoxText>
          </S.Box>
        ))}
      </S.Container>
    </>
  );
}

여기서 styled-components를 import 위와 같은 방식으로 하면 import할 컴포넌트가 너무 많아져서 코드가 복잡해지는 것을 방지할 수 있다.
또한 코드 내에서 어떤 것이 스타일 컴포넌트이고 어떤 것이 로직이 구현된 컴포넌트인지 구분이 쉬워 코드를 작성하기도 훨씬 간편하다.

그럼 이제 이 코드를 App.js에 import 시켜보자.

App.js 내에 아래와 같이 작성하자.

import React from "react";
import Global from "./styles/global";
import Home from "./pages/Home/Home";

const lorem =
  "Lorem, ipsum dolor sit amet consectetur adipisicing elit. Laboriosam, sed iure blanditiis voluptatum nulla quidem minus quam tempora obcaecati necessitatibus inventore! Vitae totam quam pariatur facilis fugit maxime adipisci eaque.";

const data = [
  {
    id: Math.random(),
    title: "Box Title 🚀",
    text: lorem,
  },
  {
    id: Math.random(),
    title: "Box title ❤️",
    text: lorem,
  },
  {
    id: Math.random(),
    title: "Box title 🐬",
    text: lorem,
  },
  {
    id: Math.random(),
    title: "Box title 🏀 ",
    text: lorem,
  },
];

function App() {
  return (
    <>
      <Global />
      <Home boxData={data} />
    </>
  );
}

export default App;

자 그러면 끝났다! 이제 한번 잘 작동하는지 한번 살펴보자.

정상적으로 잘 작동하는 것을 볼 수 있다 ㅎㅎㅎ
원티드 기업과제를 제출할때마다 항상 시간이 부족하여 모바일 환경을 구현하지 못한 아쉬움을 이렇게 한번 풀어보았다.
요즘 시대에는 모바일 시장이 점점 커지고 있고 나 또한 모바일로 많은 컨텐츠를 소비하기 때문에 따로 시간을 내어 공부를 해보았다.

코드와 Demo는 아래의 링크에서 바로 확인할 수 있다.

DEMO 및 코드 보러가기 링크

profile
Adventure, Challenge, Consistency

1개의 댓글

comment-user-thumbnail
2023년 6월 12일

미디어쿼리를 쓴 시점부터 적응형이라고 부를수 없습니다.
적응형은 스크린 사이즈에 따라 미디어 쿼리를 통해 엘레멘트 위치가 변한다. 가 아니고
기기마다 다른 스타일을 불러오는 겁니다

답글 달기