들어가기에 앞서 이 글은 Styled components의 themePorvider에 대한 기본적인 지식이 있어야하며, react-responsive 라이브러리에 대한 내용은 다루지 않습니다.
태블릿, PC, 모바일 등 다양한 기기에서도 불편함 없는 서비스를 동일하게 제공하기 위해 각 해상도에 따라 레이아웃과 스타일의 변화를 주어 제공하는 웹입니다.
미디어 쿼리는 CSS에서 나온 기술로 특정 조건이 성립됐을 때 CSS 속성을 적용할 수 있게 해주는 문법입니다.
위에서 말한 특정 조건이란 화면의 넓이나 높이와 같이 브라우저가 어떤 기기에서 실행되고 있는지를 파악해서 기기별로 서로 다른 스타일을 제공하는 방법을 선택하는데, 이것을 반응형 프로그래밍이라고 합니다.
미디어 쿼리 사용 방법
@media screen and (max-width: 768px) {
color: white;
background-color: black;
}
위 코드는 screen 영역이 768px 전 까지의 width에서 속성이 적용됩니다.
라이브러리를 설치해서 사용하면 편리함이 있긴하지만 개인적인 견해로는 라이브러리를 많이 설치하는 것을 그렇게 선호하지 않으며, 반응형 웹 작업에 ThemeProvider 사용을 하는 것이 스타일들을 관리하기에 효율적이라고 생각했습니다.
먼저 2개의 객체를 생성하겠습니다.
1) size 객체: 기기의 사이즈의 값이 들어있는 객체
2) device 객체: media query의 속성값이 들어있는 객체
const deviceSizes = {
mobile: 375,
tablet: 768,
laptop: 1024,
};
const device = {
mobile: `screen and (max-width: ${deviceSizes.mobile}px)`,
tablet: `screen and (max-width: ${deviceSizes.tablet}px)`,
laptop: `screen and (max-width: ${deviceSizes.laptop}px)`,
};
const theme = {
device
};
export default theme;
App.js에서 ThemeProvider의 theme을 props로 전달해서 사용하면 됩니다.
import React from "react";
import styled, { ThemeProvider } from "styled-components";
import theme from "./theme";
const Wrapper = styled.div`
@media ${({ theme }) => theme.device.tablet} {
flex-direction: column;
}
width: 100vw;
height: 100vh;
background: wheat;
display: flex;
align-items: center;
justify-content: center;
`;
const Item = styled.div`
width: 100px;
height: 100px;
background: white;
margin: 5px;
`;
function App() {
return (
<ThemeProvider theme={theme}>
<Wrapper>
<Item>리액트</Item>
<Item>미디어 쿼리 예제</Item>
</Wrapper>
</ThemeProvider>
);
};
export default App;
위의 미디어쿼리 속성을 모듈화하는 방법에서 조금 발전한 방법입니다.
개인적인 의견으로는 미디어쿼리 속성을 모듈화 하여 사용하는 것보다 미디어쿼리 자체를 모듈화해서 사용하는 것이 조금 더 어렵지만 어려운 만큼 실제로 적용할 때는 편한 것 같습니다.
1) media.js는 미디어쿼리 자체를 내보낼 파일
2) theme.js 통일화를 위해 정의된 다른 theme 속성
media.js
import { css } from "styled-components";
const sizes = {
mobile: 320,
tablet: 768,
laptop: 1024,
};
export default Object.keys(sizes).reduce((acc, label) => {
acc[label] = (...args) => css`
@media screen and (max-width: ${sizes[label]}px) {
${css(...args)};
}
`;
return acc;
}, {});
Object.keys()
Object.keys()메소드는 객체(typeof 연산자로 확인했을 때 object가 반환되는)의 프로퍼티들 중에서 key값, 다른 말로는 프로퍼티 이름들만 묶어서 배열로 반환하는 메소드 입니다.
- 사용법: Object 객체에 keys 메서드를 호출하고 파라미터로 Key값을 알아내고자 하는 객체를 전달해주면 된다.
const object1 = { a: 'somestring', b: 42, c: false }; const object1 = Object.keys(object1); console.log(object1); // ["a", "b", "c"]
Object.keys()함수로 매개변수로 넘어간 sizes 객체에 있는 enumerable 속성명을 가지고,
reduce()의 리듀서 함수로 size에 정의된 값으로 acc 연산으로 각각의 media query의 속성들을 styled-components의 css 속성을 이용해서 만들어냅니다.
그리고 그 속성 값들을 위에서 정의한 sizes 객체에 있는 값들로 media query의 속성을 만드는데 ...args 문법으로 생성된 모든 args를 media query 내에 적용시켜줍니다.
기존에 정의된 theme이 있다면 spread operator를 이용해 적용시켜주면 됩니다.
theme={theme} -> theme={{...theme, ...media}}
import React from "react";
import styled, { ThemeProvider } from "styled-components";
import theme from "./theme";
import media from "./media";
const Wrapper = styled.div`
font-size: ${({ theme }) => theme.fontSizes.subtitle};
${({ theme }) => theme.tablet`
flex-direction: column;
font-size: ${({ theme }) => theme.fontSizes.paragraph};
`};
width: 100vw;
height: 100vh;
background: wheat;
display: flex;
align-items: center;
justify-content: center;
`;
const Item = styled.div`
width: 100px;
height: 100px;
background: white;
margin: 5px;
`;
const ThemeProviderPrac = () => {
return (
<ThemeProvider theme={{ ...theme, ...media }}>
<Wrapper>
<Item>리액트</Item>
<Item>미디어쿼리 적용 예제</Item>
</Wrapper>
</ThemeProvider>
);
};
export default ThemeProviderPrac;