기획자로부터 하나의 페이지 기획이 도착했고, 디자이너와 개발자가 협력하여 디자인과 개발이 진행되었습니다.
페이지가 모두 완성되었는데, 다른 페이지에 적용되는 버튼에 대한 추가적인 기획안이 도착했습니다.
어? 그런데 기획자가 요청한 사항에서 버튼에 대한 기획이 이전에 요청받았던 버튼을 똑같이 사용하도록 요청했습니다.
그렇다면 디자이너와 개발자는 이 부분을 모두 새로 만들어야 하는 걸까요?
여러 프로젝트 혹은 여러 팀 간에 같은 UI 컴포넌트를 공유한다면 이런 고민을 하지 않아도 되겠죠!
디자인과 개발 단계에서부터 재사용할 수 있는 UI 컴포넌트를 미리 디자인하고 개발하면 이런 고민을 해결할 수 있습니다.
이 고민을 해결하기 위해 등장한 개발 방법이 바로 Component Driven Development (CDD) 입니다.
레고처럼 조립해 나갈 수 있는 부품 단위로 UI 컴포넌트를 만들어 나가는 개발을 진행할 수 있습니다.
실제로 CDD 방법을 활용하여 UI 를 구축하는 사이트들도 많습니다.
이제 여러분들은 위 사이트처럼 CDD 방법을 이용한 UI 컴포넌트 제작 방식을 배우게 됩니다.
인터넷이 만들어진 이후 기술의 발달과 함께 사용자들은 다양한 환경(디바이스)에서 인터넷을 사용하기 시작했습니다. 이에 따라 개발자들의 CSS 작성 방식도 꾸준히 진화해 오고 있습니다.
이미지 출처 : https://orezytivarg.github.io/css-evolution-from-css-sass-bem-css-modules-to-styled-components/
프로젝트의 규모나 복잡도가 점점 커지고 함께 작업해야 할 팀원 수도 많아짐에 따라 CSS를 작성하는 일관된 패턴이 없다는 것은 개발자들에게 가장 큰 걸림돌이 되었습니다.
또한 모바일이나 태블릿을 비롯한 다양한 디바이스들의 등장으로 웹사이트들이 다양한 디스플레이를 커버해야 하기 때문에 CSS는 더 복잡해지게 되었습니다.
이러한 문제점들을 해결하기 위해 CSS 전처리기(CSS Preprocessor)라는 개념이 등장했습니다.
CSS 전처리기(CSS Preprocessor)란 CSS가 구조적으로 작성될 수 있게 도움을 주는 도구입니다.
우리가 흔히 CSS 문서를 작성할 때는 많은 반복적인 작업을 요구하고 Color 값을 찾는 일, tag를 닫는 일 등 번거로운 작업 역시 포함이 되어 있습니다. 그뿐만 아니라 클래스의 상속과 같은 사항으로 점점 CSS 문서는 양이 많아지고 이로 인해 이후 유지관리에 많은 영향을 끼칩니다. 이런 CSS의 문제점들을 프로그래밍 개념(변수, 함수, 상속 등)을 활용하여 해결해 나갈 수 있습니다.
하지만 이 CSS 전처리기(CSS Preprocessor) 자체만으로는 웹 서버가 인지하지 못하기 때문에 각 CSS 전처리기에 맞는 Compiler를 사용해야 하고 컴파일을 하게 되면 실제로 우리가 사용하는 CSS 문서로 변환이 됩니다.
이를 통해 CSS 파일들을 잘 구조화할 수 있게 되었고, 최소한 CSS 파일을 몇 개의 작은 파일로 분리할 수 있는 방법이 생겼습니다.
CSS 전처리기 중에서 가장 유명한 SASS는 Syntactically Awesome Style Sheets의 약자로 CSS를 확장해 주는 스크립팅 언어입니다.
즉, CSS를 만들어주는 언어로서 자바스크립트처럼 특정 속성(ex. color, margin, width 등)의 값(ex. #ffffff, 25rem, 100px 등)을 변수로 선언하여 필요한 곳에 선언된 변수를 적용할 수도 있고, 반복되는 코드를 한 번의 선언으로 여러 곳에서 재사용할 수 있도록 해 주는 등의 기능을 가졌습니다. 그래서 SASS는 SCSS 코드를 읽어서 전처리한 다음 컴파일해서 전역 CSS 번들 파일을 만들어 주는 전처리기(preprocessor)의 역할을 합니다.
하지만 얼마 지나지 않아서 SASS가 ‘CSS의 구조화’를 해결해 주는 것의 장점보다 다른 문제들을 더 많이 만들어낸다는 것이 밝혀집니다.
결국 우리는 전처리기(preprocessor)가 내부에서 어떤 작업을 하는지는 알지 못한 채, 스타일이 겹치는 문제를 해결하기 위해 단순히 계층 구조를 만들어 내는 것에 의지하게 되었고, 그 결과 컴파일된 CSS의 용량은 어마어마하게 커지게 되었습니다.
이러한 CSS 전처리기의 문제를 보완하기 위해 BEM, OOCSS, SMACSS 같은 CSS 방법론이 대두되었습니다. 각각의 장단점이 있으나 결국 세 방법론 모두 같은 지향점을 가지고 있습니다.
방법론의 공통 지향점은 다음과 같습니다.
코드의 재사용
코드의 간결화(유지 보수 용이)
코드의 확장성
코드의 예측성(클래스 명으로 의미 예측)
이런 CSS 방법론들은 같이 일하는 팀 동료들의 팀워크와도 연결되기 때문에 여러 팀원이 함께 작업하는 상황에서 CSS 작성에 있어서 방법들을 규칙으로 정해두는 것은 매우 중요한 요소라고 할 수 있습니다.
대표적인 CSS 방법론으로는 BEM이 있습니다.
BEM이란 Block, Element, Modifier로 구분하여 클래스명을 작성하는 방법이며, Block, Element, Modifier 각각은 —와 __로 구분합니다.
클래스명은 BEM 방식의 이름을 여러 번 반복하여 재사용할 수 있도록 하며 HTML/CSS/SASS 파일에서도 더 일관된 코딩 구조를 만들어 줍니다.
애플리케이션으로 개발 방향이 진화하면서 컴포넌트 단위의 개발은 캡슐화의 중요성을 불러왔습니다. 하지만 CSS는 컴포넌트 기반의 방식을 위해 만들어진 적이 한 번도 없었습니다. 결국 CSS도 컴포넌트 영역으로 불러들이기 위해서 CSS-in-JS가 탄생해서 이 문제를 정확하게 해결합니다.
Styled-Component는 기능적(Functional) 혹은 상태를 가진 컴포넌트들로부터 UI를 완전히 분리해 사용할 수 있는 아주 단순한 패턴을 제공합니다. Styled-Component에 대해서는 다음 강의에서 더 자세하게 알아봅시다.
CSS-in-JS에는 대표적으로 Styled-Component가 있습니다.
CSS 코드를 다룰 때 다음과 같은 불편함을 느껴보신 적 있으신가요?
Styled Components는 앞서 배운 CSS in JS 라는 개념이 대두되면서 나온 라이브러리입니다. 기존에 HTML, CSS, JS 파일로 쪼개서 개발하던 방법에서, React 등의 라이브러리의 등장으로 컴포넌트 단위 개발이 주류가 되었지만, CSS는 그렇지 못했다는 점에서 출발한 개념이죠.
CSS in JS 라이브러리를 사용하면 CSS도 쉽게 Javascript 안에 넣어줄 수 있으므로, HTML + JS + CSS까지 묶어서 하나의 JS파일 안에서 컴포넌트 단위로 개발할 수 있게 됩니다. 이런 CSS in JS 라이브러리 중에서 현재 가장 인기 있는 라이브러리가 바로 Styled Components 입니다. 이번 챕터에서는 이 Styled Components 사용법에 대해 알아보도록 합시다.
Styled Components 의 설치는 간단합니다. 터미널에 아래의 명령어 한 줄을 입력해 Styled Components 라이브러리를 설치할 수 있습니다.
# with npm
$ npm install --save styled-components
# with yarn
$ yarn add styled-components
Styled Components는 package.json에 다음 코드를 추가하도록 권장하고 있습니다. 아래의 코드를 추가하면 여러 버전의 Styled Components가 설치되어 발생하는 문제를 줄여줍니다.
{
"resolutions": {
"styled-components": "^5"
}
}
그 다음 Styled Components를 사용할 파일로 불러와주면 사용 준비는 완료입니다!
import styled from "styled-components"
Styled Components로 컴포넌트를 만드는 방법은 다음과 같습니다.
Styled Components는 ES6의 Templete Literals 문법을 사용합니다. 즉, 따옴표가 아닌 백틱(`)을 사용합니다.
컴포넌트를 선언한 후 styled.태그종류를 할당하고, 백틱 안에 기존에 CSS를 작성하던 문법과 똑같이 스타일 속성을 작성해주면 됩니다. 이렇게 만든 컴포넌트를 React 컴포넌트를 사용하듯 리턴문 안에 작성해주면 스타일이 적용된 컴포넌트가 렌더되는 것을 확인할 수 있습니다.
import styled from "styled-components";
//Styled Components로 컴포넌트를 만들고
const BlueButton = styled.button`
background-color: blue;
color: white;
`;
export default function App() {
// React 컴포넌트를 사용하듯이 사용하면 됩니다.
return <BlueButton>Blue Button</BlueButton>;
}
이미 만들어진 컴포넌트를 재활용해서 새로운 컴포넌트를 만들 수도 있습니다. 컴포넌트를 선언하고 styled() 에 재활용할 컴포넌트를 전달해준 다음, 추가하고 싶은 스타일 속성을 작성해주면 됩니다.
import styled from "styled-components";
const BlueButton = styled.button`
background-color: blue;
color: white;
`;
//만들어진 컴포넌트를 재활용해 컴포넌트를 만들 수 있습니다.
const BigBlueButton = styled(BlueButton)`
padding: 10px;
margin-top: 10px;
`;
//재활용한 컴포넌트를 재활용할 수도 있습니다.
const BigRedButton = styled(BigBlueButton)`
background-color: red;
`;
export default function App() {
return (
<>
<BlueButton>Blue Button</BlueButton>
<br />
<BigBlueButton>Big Blue Button</BigBlueButton>
<br />
<BigRedButton>Big Red Button</BigRedButton>
</>
);
}
Styled Component로 만든 컴포넌트도 React 컴포넌트처럼 props를 내려줄 수 있습니다. 내려준 props 값에 따라서 컴포넌트를 렌더링하는 것도 가능합니다.
Styled Components는 템플릿 리터럴 문법( ${ } )을 사용하여 JavaScript 코드를 사용할 수 있습니다. props를 받아오려면 props를 인자로 받는 함수를 만들어 사용하면 됩니다.
위 코드의 경우는 삼항연산자를 활용해 컴포넌트에 skyblue 라는 props가 있는지 확인하고, 있으면 배경색으로 skyblue를, 없을 경우 white를 지정해주는 코드입니다. 이 코드에 따라 렌더링된 컴포넌트는 아래 그림과 같을 것입니다.
Button1 의 경우는 skyblue 라는 props가 있어 배경색이 skyblue 로 지정됐고, Button2의 경우는 props가 아예 없어 배경색이 white 로 지정된 것을 확인할 수 있습니다.
import styled from "styled-components";
import GlobalStyle from "./GlobalStyle";
//받아온 prop에 따라 조건부 렌더링이 가능합니다.
const Button1 = styled.button`
background: ${(props) => (props.skyblue ? "skyblue" : "white")};
`;
export default function App() {
return (
<>
<GlobalStyle />
<Button1>Button1</Button1>
<Button1 skyblue>Button1</Button1>
</>
);
}
3번과 비슷하게, props의 값을 통째로 활용해서 컴포넌트 렌더링에 활용할 수 있습니다.
import styled from "styled-components";
import GlobalStyle from "./GlobalStyle";
//받아온 prop 값을 그대로 이용해 렌더링할 수도 있습니다
const Button1 = styled.button`
background: ${(props) => (props.color ? props.color : "white")};
`;
//다음과 같은 형식으로도 활용할 수 있습니다.
const Button2 = styled.button`
background: ${(props) => props.color || "white"};
`;
export default function App() {
return (
<>
<GlobalStyle />
<Button1>Button1</Button1>
<Button1 color="orange">Button1</Button1>
<Button1 color="tomato">Button1</Button1>
<br />
<Button2>Button2</Button2>
<Button2 color="pink">Button2</Button2>
<Button2 color="turquoise">Button2</Button2>
</>
);
}
우선 전역 스타일을 설정하기 위해 Styled Components에서 createGlobalStyle 함수를 불러옵니다.
import { createGlobalStyle } from "styled-components";
그 다음 이 함수를 사용해 CSS 파일에서 작성하듯 설정해주고 싶은 스타일을 작성합니다.
const GlobalStyle = createGlobalStyle`
button {
padding : 5px;
margin : 2px;
border-radius : 5px;
}