2023.02.07 styled-components
styled-components는 CSS 문법을 그대로 사용하면서 결과물을 스타일링된 컴포넌트 형태로 만들어주는 오픈소스 라이브러리입니다.
미니 프로젝트를 진행할 때 사용할 예정이기 때문에 간단하게 배워봅시다.
#npm을 사용하는 경우
npm install --save styled-components
#yarn을 사용하는 경우
yarn add styled-components
vscode에서 자동완성을 위해 라이브러리 추가
MainPage.jsx를 만들어 test해보자.
import React from "react";
import styled from "styled-components";
const Wrapper = styled.div`
padding: 1em;
background: grey;
`;
const Title = styled.h1`
font-size: 1.5em;
color: white
text-align: center;
`;
function MainPage(props) {
return (
<Wrapper>
<Title>
안녕, 리액트
</Title>
</Wrapper>
)
}
export default MainPage;
수정 후 브라우저를 띄우면 아래와 같이 잘 작동하는것을 볼 수 있습니다.
styled-components는
태그드 템플릿 리터럴(tagged template literal)을 사용하여 구성 요소의 스타일을 지정합니다.
여기에서 템플릿 리터럴이라는 것이 등장하는데 이것은 자바스크립트에서 제공하는 문법 중 하나입니다.
프로그래밍에서 리터럴은 소스코드의 고정된 값을 의미합니다.
흔히 상수와 헷갈려 하는 경우가 있는데 둘은 다른 개념입니다.
위의 그림을 보면 대입 연산자(=)의 왼쪽에는 number라는 이름의 변수가 등장하고
오른쪽에는 정수 20이 등잡합니다.
여기에서 오른쪽에 있는 정수 20이 바로 리터럴입니다.
소스코드 상에 있는 고정된 값을 의미하는 것이죠.
// 정수 리터럴(Integer literal)
cosnt myNumber = 10;
// 문자열 리터럴(String literal)
const myStr = 'Hello';
// 배열 리터럴(Array literal)
const myArray = [];
// 객체 리터럴(Object literal)
const myObject = {};
변수를 선언할 때 var나 let을 사용하지 않고 상수를 의미하는 const를 사용했는데,
이렇게 선언하게 되면 해당 변수들이 모두 상수가 됩니다.
그리고 대입 연산자(=)의 오른쪽에 있는 값이 모두 리터럴이 됩니다.
템플릿 리터럴은 말 그대로 리터럴을 템플릿 형태로 사용하는 자바스크립트의 문법인데,
backticks(`)를 사용하여 문자열을 작성하고 그 안에 대체 가능한 expression을 넣는 방법입니다.
여기에서 이 expression을 대체라는 뜻을 가진 substiution이라고 부릅니다.
템플릿 리터럴은 또 크게 언태그드 템플릿 리터럴과 태그드 템플릿 리터럴로 나뉩니다.
// Untagged template literal
// 단순한 문자열
`string text`
// 여러 줄(Multi-line)에 걸친 문자열
`string text line1
string text lin2`
// 대체 가능한 expression이 들어있는 문자열
`string text ${exprssion} string text`
// Tagged template literal
// myFunction의 파라미터로 expression으로 구분된 문자열 배열과 expression이 순서대로 들어간 형태로 호출됨
myFunction`string text ${expressoin} string text`;
위 코드에 나온 것처럼
언태그드 템플릿 리터럴은 보통 문자열을 여러 줄에 걸쳐서 작성하거나 포매팅을 하기 위해서 사용합니다.
태그드 템플릿 리터럴은 앞에 나와있는 태그 함수를 호출하여 결과를 리턴합니다.
여기에서 태그 함수의 파라미터는 expression으로 구분된 문자열 배열과 expression이 순서대로 들어가게 됩니다.
좀 더 쉬운 이해를 위해 아래 예제 코드를 봅시다.
const name = '인제';
const region = '서울';
function myTagFunction(strings, nameExp, regionExp) {
let str0 = strings[0]; // "제 이름은 "
let str1 = strings[1]; // "이고, 사는 곳은"
let str2 = strings[2]; // "입니다."
// 여기에서도 template literal을 사용하여 리턴할 수 있음
return `${str0}${nameExp}${str1}${regionExp}${str2}`;
}
const output = myTagFunction`제 이름은 ${name}이고, 사는 곳은${region}입니다.`;
// 출력 결과
// 제 이름은 인제이고, 사는 곳은 서울입니다.
console.log(output);
위 코드는 태그드 템플릿 리터럴을 사용한 예제입니다.
태그 함수에 파라미터가 어떻게 들어가는지 쉽게 파악되죠?
이처럼 태그드 템플릿 리터럴을 사용하면 문자열과 expression을 태그 함수의 파라미터를 넣어
호출한 결과를 받게 됩니다.
styled-components는
태그드 템플릿 리터럴을 사용하여 CSS속성이 적용된 리액트 컴포넌트를 만들어 줍니다.
styled-components를 사용하는 기본적인 방법은
아래와 같이 backticks(`)로 둘러싸인 문자열 부분에 CSS속성을 넣고
태그 함수 위치에는 styled.<HTML 태그> 형태로 사용합니다.
이렇게 하면 해당 HTML 태그에 CSS 속성들이 적용된 형태의 리액트 컴포넌트가 만들어집니다.
import React from "react";
import styled from "styled-components";
const Wrapper = styled.div`
padding: 1em;
background: grey;
`;
styled-components에서 조건이나 동적으로 변하는 값을 사용해서 스타일링할 수 있는 방법은
바로 props입니다.
리액트 컴포넌트의 props와 같은 개념으로 이해하면 됩니다.
import React from "react";
import styled from "styled-components";
const Button = styled.button`
color: ${props => props.dark ? "white" : "dark"},
background: ${props => props.dark ? "black" : "white"};
border: 1px solid black;
`;
function Sample(props) {
return (
<div>
<Button>Normal</Button>
<Button dark>Dark</Button>
</div>
)
}
export default Sample;
위의 Button이라는 컴포넌트는 styled-components를 사용해서 만들어진 것입니다.
그리고 styled-components를 사용하는 부분의 CSS속성을 보면 내부에 props가 사용된 것을 볼 수 있습니다.
여기에서는 props는 해당 컴포넌트에 사용된 props를 의미합니다.
따라서 실제 Button 컴포넌트를 사용하는 부분의 코드를 보면
<Button>Dark<Button>처럼 props로 dark를 넣어 주는 것을 볼 수 있습니다.
그리고 이렇게 들어간 props는 그대로 styled-components로 전달됩니다.
이 기능을 사용하면 styled-components를 사용하여 다양한 스타일을 자유자재로 구현할 수 있습니다.
앞에서 styled-components를 사용하면 리액트 컴포넌트가 생성된다고 설명했습니다.
그렇다면 이렇게 생성된 컴포넌트를 기반으로 추가적인 스타일을 적용하고 싶을 경우에는 어떻게 해야할까요?
styled-components에서는 이를 위한 스타일 확장 기능을 제공합니다.
import React from "react";
import styled from "styled-components";
// Button 컴포넌트
const Button = styled.button`
color: grey;
border: 1px solid black;
`;
// Button에 style이 추가된 RoundedButton 컴포넌트
const RoundedButton = styled(Button)`
border-radius: 16px;
`;
function Sample(props) {
return (
<div>
<Button>Normal</Button>
<RoundedButton>Rounded</RoundedButton>
</div>
)
}
export default Sample;
먼저 Button 컴포넌트는 HTML의 button 태그를 기반으로 만들어진 단순한 버튼입니다.
그리고 RoundedButton 컴포넌트를 만드는 부분을 보면 HTML 태그가 빠져있고
Button 컴포넌트가 괄호로 둘러싸인 채로 들어가 있는 것을 볼 수 있습니다.
이것이 바로 다른 컴포넌트의 스타일을 확장해서 사용하는 부분입니다.
import styled from "styled-components";
const Wrapper = styled.div`
padding: 1rem;
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
background-color: lightgrey;
`;
const Block = styled.div`
padding: ${(props) => props.padding};
border: 1px solid black;
border-radius: 1rem;
background-color: ${(props) => props.backgroundColor};
color: white;
font-size: 2rem;
font-wright: bold;
text-align: center;
`;
const blockItems = [
{
label: "1",
padding: "1rem",
backgroundColor: "red"
},
{
label: "2",
padding: "3rem",
backgroundColor: "green"
},
{
label: "3",
padding: "2rem",
backgroundColor: "blue"
}
];
function Blocks(props) {
return (
<Wrapper>
{blockItems.map((blockItem) => {
return (
<Block
padding={blockItem.padding}
backgroundColor={blockItem.backgroundColor}
>
{blockItem.label}
</Block>
);
})}
</Wrapper>
);
}
export default Blocks;
수정 후 브라우저를 확인하면 아래 그림처럼 세 개의 박스가 가로로 나열되어 나타난다.
이것은 현재 flex-direction이 row로 되어 있기 때문입니다.
align-items 속성을 baseline으로 변경.
align-items 속성을 flex-end 변경.
alifn-items 속성을 stretch로 바꾸면 아래와 같이 박스가 세로로 늘어나는 것을 확인할 수 있습니다.
이번에는 박스들을 세로로 정렬해 봅시다.
flex-direction 속성을 column으로 변경하면 됩니다.
flex-direction 속성을 column-reverse로 변경
CSS란?
선택자(selector)
CSS 문법과 선택자
레이아웃과 관련된 속성
플렉스박스
폰트와 관련된 속성
많이 사용하는 기타 속성
CSS 문법을 그대로 사용하면서 결과물을 스타일링된 컴포넌트 형태로 만들어주는 오픈소스 라이브러리
컴포넌트 개념을 사용하기 때문에 리액트와 궁합이 잘 맞음
태그드 템플릿 리터럴을 사용하여 구성 요소의 스타일을 지정