반응형 웹은 조건부 렌더링과 깊은 연관이 있다. 따라서, 조건부 렌더링을 이용한 탭 레이아웃 구성을 먼저 진행해보기로 한다.
① Tab.jsx 파일을 생성하고 아래의 내용을 입력한다.
import { useState } from 'react';
import styled from 'styled-components';
const TabMenu = styled.ul`
width: calc(100% - 350px);
background-color: #ffffff;
color: #333;
font-weight: bold;
display: flex;
flex-direction: row;
align-items: center;
list-style: none;
padding: 0;
border-radius: 10px;
`;
const MenuItem = styled.li`
flex: 1;
padding: 10px;
text-align: center;
cursor: pointer;
transition: background-color 0.3s, color 0.3s;
color: #000000;
font-size: 22px;
border-radius: 10px;
&:hover {
background-color: #f0f0f0;
color: #0067A3;
}
&.focused {
background-color: #0067A3;
color: #ffffff;
}
`;
const Tab = ({ menuItems, setCurrentTab }) => {
const [selectedTab, setSelectedTab] = useState(0);
const selectMenuHandler = (index) => {
setCurrentTab(index);
setSelectedTab(index);
};
return (
<div>
<TabMenu>
{menuItems.map((item, index) => (
<MenuItem
key={index}
className={index === selectedTab ? "focused" : ""}
onClick={() => selectMenuHandler(index)}
>
{item}
</MenuItem>
))}
</TabMenu>
</div>
);
};
export default Tab;
② 탭 레이아웃을 적용할 jsx 파일에 아래의 내용을 추가한다.
function RegisterPage(props) {
const [currentTab, setCurrentTab] = useState(0);
...
return (
<Wrapper>
<Tab
menuItems={['스케줄링 등록', '스케줄링 목록']}
setCurrentTab={setCurrentTab}
/>
{currentTab === 0 && (
// 첫번째 탭을 클릭했을 때 나타날 화면
...
)}
{currentTab === 1 && (
// 두번째 탭을 클릭했을 때 나타날 화면
...
)}
</Wrapper>
);
}
웹 페이지는 모바일, 태블릿, PC 등 다양한 디바이스에서 접근 가능하므로, 해상도와 무관하게 항상 우수한 UI/UX를 제공할 수 있어야 한다. 이러한 원칙에 따라 설계된 웹 어플리케이션을 반응형 웹이라 하는데, 반응형 웹을 만드는 방법은 media query를 사용하는 방법과 react-responsive를 사용하는 방법으로 구분된다.
Media Query는 아래와 같은 형태를 취한다.
@media only screen and (min-width: 400px) {
...
}
이제 위 쿼리의 의미를 해석하기 위해 Media Query의 구성요소에 대해 알아보자.
① 스타일 적용 대상
② 미디어 타입
③ 속성
즉, 위 쿼리는 화면 View Port의 너비가 400픽셀 이상인 경우에 적용할 스타일을 정의하겠다는 의미인 것이다. 이를 통해 다양한 해상도의 디바이스에 접근하더라도 해상도에 알맞은 UI를 제공할 수 있게 된다.
사실 Media Query를 사용하는 방법보다는 react-responsive 모듈을 import 하는 방식이 더 편리하다. react-responsive의 사용법은 아래와 같다.
① 아래의 명령을 이용해 react-responsive 모듈을 설치한다.
npm install react-responsive
② 이제 해상도에 따라 UI를 다르게 보여주기 위해, 현재 접속한 디바이스가 PC인지 모바일인지를 해상도를 통해 구분하는 컴포넌트를 만든다.
import React from 'react';
import {useMediaQuery} from 'react-responsive';
export const Mobile = ({children}) => {
const isMobile = useMediaQuery({
query : "(max-width:768px)"
});
return <>{isMobile && children}</>
}
export const PC = ({children}) => {
const isPc = useMediaQuery({
query : "(min-width:769px)"
});
return <>{isPc && children}</>
}
③ 이제 반응형 UI를 제공할 페이지에 가서 아래와 같이 코드를 수정한다.
import React, { useState } from 'react';
import { Mobile, PC } from './ResponsiveComponents';
...
function MainPage(props) {
return (
<CenterWrapper>
<Mobile>
<p>모바일 화면으로 인식</p>
</Mobile>
<PC>
...
</PC>
</CenterWrapper>
);
}
④ 실행결과를 확인한다.
여기서는 두가지 방법을 모두 사용하여 아래와 같이 MainPage를 반응형 웹으로 구성하였다. 웹 페이지가 축소되는 상황에도 반응할 수 있도록 Responsive 컴포넌트를 아래와 같이 수정하였다.
import React from 'react';
import {useMediaQuery} from 'react-responsive';
export const Mobile = ({children}) => {
const isMobile = useMediaQuery({
query : "(max-width:480px)"
});
return <>{isMobile && children}</>
}
export const HalfScreen = ({children}) => { // PC에서 화면 축소
const isHalfScreen = useMediaQuery({
query: "(min-width: 481px) and (max-width: 1080px)"
});
return <>{isHalfScreen && children}</>
}
export const PC = ({children}) => {
const isPc = useMediaQuery({
query : "(min-width:1081px)"
});
return <>{isPc && children}</>
}
화면 크기에 따라 텍스트나 이미지 뷰의 크기가 동적으로 달라지기 때문에, 반드시 너비와 폰트 크기에 상한이 존재해야 한다. 여기서는 너비 제한(또는 높이 제한)은 min-width(min-height)
와 max-width(max-height)
로 설정하였으며, font-size 제한은 아래와 같이 미디어 쿼리를 이용해 설정하였다.
const TitleText = styled.p`
font-size: 18px;
font-weight: 700;
height: auto;
@media (max-width: 1080px) { // 큰 경우를 먼저 작성해야 함
font-size: 16px;
}
@media (max-width: 480px) {
font-size: 14px;
}
`;
아래는 완성된 화면이다.