안녕하세요, 코린이의 코딩 학습기 채니 입니다.
[리액트를 다루는 기술]의 책을 참고하여 포스팅한 개인 공부 내용입니다.
컴포넌트 스타일링
styled-components
- 자바스크립트 파일 안에 스타일을 선언하는 방식 (CSS-in-JS)
사용을 위해 설치해보겠습니다.
$ yarn add styled-components
StyledComponent.js
import styled, { css } from 'styled-components'
const Box = styled.div`
/* props로 넣어준 값을 직접 전달 가능 */
background: ${props => props.color || 'blue'};
padding: 1rem;
display: flex;
`;
const Button = styled.button`
background: white;
color: black;
border-radius: 4px;
padding: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: 1rem;
font-weight: 600;
/* & 문자를 사용하여 Sass처럼 자기 자신 선택 가능 */
&:hover {
background: rgba(255, 255, 255, 0.9);
}
/* inverted 값이 true일 때 특정 스타일 부여 */
${props =>
props.inverted &&
css`
background: none;
border: 2px solid white;
color: white;
&:hover {
background: white;
color: black;
}
`};
& + button {
margin-left: 1rem;
}
`;
const StyledComponent = () => (
<Box color='black'>
<Button>안녕하세요</Button>
<Button inverted={true}>테두리만</Button>
</Box>
);
export default StyledComponent;
App.js
import StyledComponent from './StyledComponent';
class App extends Component {
render() {
return (
<div>
<StyledComponent />
</div>
);
}
}
export default App;
※ 컴포넌트 내부에 작성한 CSS 코드의 신택스 하이라이팅 적용을 원한다면 vscode-style-components 설치
위 작동원리를 이해하기 위해 원리와 사용법을 알아보도록 하겠습니다.
Tagged 템플릿 리터럴
스타일 작성 시 `(백틱)을 사용하여 문자열에 스타일 정보를 넣어준 것을 확인할 수 있습니다.
해당 문법을 'Tagged 템플릿 리터럴' 이라고 합니다.
일반 템플릿 리터럴과 다른 점은 템플릿 내의 js 객체나 함수를 전달할 때 온전히 추출할 수 있습니다.
일반 템플릿 리터럴 예
객체 혹은 함수를 넣으면 객체는 [object Object] 형태, 함수는 문자열 그대로 나타나는 것을 확인할 수 있습니다.
Tagged 템플릿 리터럴 예
이처럼 Tagged 템플릿 리터러를 사용하면 js 객체나 함수를 그대로 추출할 수 있습니다.
따라서 이러한 속성을 이용해 styled-components로 만든 컴포넌트의 props를 스타일쪽에서 쉽게 조회할 수 있는 것!
스타일링된 엘리먼트 만들기
styled-components를 사용하여 스타일링된 엘리먼트를 만들 땐 컴포넌트 파일 상단에서 styled를 불러오고,
styled.태그명을 사용하여 구현합니다.
import styled from 'styled-components';
const MyComponent = styled.div`
font-size: 2rem;
`;
이처럼 styled.div 뒤에 Tagged 템플릿 리터럴 문법으로 스타일을 지정해주면, 해당 스타일이 적용된 div로 이루어진 리액트 컴포넌트가 생성됩니다.
따라서 나중에 <MyComponent>Hello</MyComponent> 형태로 사용할 수 있는 것이죠.
(button 혹은 input에 스타일링을 하고 싶다면, styled.button / style.button 형태로 사용)
하지만 사용해야 할 태그가 유동적이거나 특정 컴포넌트 자체에 스타일링을 해주고 싶다면 아래와 같이 해주면 됩니다.
// 태그 타입을 styled 함수의 인자로 전달
const MyInput = styled('input')`
background: gray;
`
// 아예 컴포넌트 형식의 값을 넣어줌
const StyledLink = styled(Link)`
color: blue;
`
스타일에서 props 조회하기
위에서 생성하였던 코드를 살펴보면, 스타일 쪽에서 컴포넌트에게 전달된 props 값을 참조할 수 있었습니다.
StyledComponent.js - Box 컴포넌트
const Box = styled.div`
/* props로 넣어준 값을 직접 전달 가능 */
background: ${props => props.color || 'blue'};
padding: 1rem;
display: flex;
`;
...
...
<Box color='black'> ... </Box>
background 값에 props를 조회해 props.color 값이 주어지지 않는다면 'blue'로 기본 색상을 설정해주었습니다.
JSX에서 color값을 props로 넣어준 것도 확인할 수 있습니다.
props에 따른 조건부 스타일링
StyledComponent.js - Button
import styled, { css } from 'styled-components'
/*
단순 변수의 형태가 아니라 여러 줄의 스타일 구문을 조건부로 설정해야 하는 경우엔
css를 불러와야 함
*/
const Button = styled.button`
background: white;
color: black;
border-radius: 4px;
padding: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: 1rem;
font-weight: 600;
/* & 문자를 사용하여 Sass처럼 자기 자신 선택 가능 */
&:hover {
background: rgba(255, 255, 255, 0.9);
}
/* inverted 값이 true일 때 특정 스타일 부여 */
${props =>
props.inverted &&
css`
background: none;
border: 2px solid white;
color: white;
&:hover {
background: white;
color: black;
}
`};
& + button {
margin-left: 1rem;
}
`;
<Button>안녕하세요</Button>
<Button inverted={true}>테두리만</Button>
위처럼 생성한 컴포넌트는 props를 사용하여 다른 스타일을 적용할 수 있습니다.
또한, 스타일 코드 여러 줄을 props에 따라 넣어 주어야 할 때는 CSS를 불러와야 합니다.
CSS를 불러오지 않고도 문자열을 넣어도 작동하긴 하지만 문자열 그대로 취급 되므로, 함수를 받아 사용하진 못하여 props 값을 사용할 수 없습니다.
// css 사용하지 않은 버전
${props =>
props.inverted &&
`
background: none;
border: 2px solid white;
color: white;
&:hover {
background: white;
color: black;
}
`};
Tagged 템플릿 리터럴이 아니기 때문에 props를 참조하지 않는다면 css 불러와서 사용하지 않고 위처럼 사용해도 되지만,
만일 props를 참조한다면 반드시 CSS로 감싸준 후 Tagged 템플릿 리터럴을 사용해줘야 합니다.
반응형 디자인
브라우저 가로 크기에 따라 다른 스타일 적용하기 위해 media 쿼리를 사용해주겠습니다.
StyledComponent.js - Box
const Box = styled.div`
/* props로 넣어준 값을 직접 전달 가능 */
background: ${props => props.color || 'blue'};
padding: 1rem;
display: flex;
/*
기본적으로 가로 크기 1024px에 가운데 정렬을 하고,
가로 크기가 작아짐에 따라 크기를 줄이고
768px 미만이 되면 꽉 채움
*/
width: 1024px;
margin: 0 auto;
@media (max-width: 1024px) {
width: 768px;
}
@media (max-width: 768px) {
width: 100%;
}
`;
위처럼 일반 CSS와 별다른 차이가 없습니다.
해당 작업을 함수화하여 간편하게 사용해보겠습니다. (styled-components 매뉴얼에서 제공하는 유틸 함수 참고)
const sizes = {
desktop: 1024,
tablet: 768
}
// 위에 있는 size 객체에 따라 자동으로 media 쿼리 함수 생성
const media = Object.keys(sizes).reduce((acc, label) => {
acc[label] = (...args) => {
css`
@media (max-width: ${sizes[label] / 16}em) {
${css(...args)};
}
`
}
return acc;
}, {});
const Box = styled.div`
/* props로 넣어준 값을 직접 전달 가능 */
background: ${props => props.color || 'blue'};
padding: 1rem;
display: flex;
width: 1024px;
margin: 0 auto;
${media.desktop`width: 768px`}
${media.tablet`width: 100%`}
`;
이처럼 다른 파일로 모듈화하여 필요에 따라 불러와 간편하게 사용할 수 있습니다.
'JavaScript > React' 카테고리의 다른 글
React) 일정 관리 웹 애플리케이션 만들기 - 2 (todoList 렌더링, 항목 추가 기능 구현하기) (0) | 2022.11.19 |
---|---|
React) 일정 관리 웹 애플리케이션 만들기 - 1 (프로젝트 준비 및 UI 구성) (0) | 2022.11.19 |
React) 컴포넌트 스타일링③ - CSS Module (classnames) (0) | 2022.11.19 |
React) 컴포넌트 스타일링② - Sass 사용하기 (0) | 2022.11.18 |
React) 컴포넌트 스타일링① - 일반 CSS 방식 (0) | 2022.11.18 |