반응형
CSS
CSS 클래스를 활용한 스타일링
- 기존부터 사용해 왔던 전통적인 방식의 CSS 스타일링을 계속 사용하는데 문제가 없고, 새로운 스타일링 방식을 적용하는 것이 불필요하다고 판단된다면 기존의 CSS 스타일링 방식을 그대로 사용해도 무방하다.
- React 컴포넌트에 스타일을 적용하는 가장 간단한 방법은 인라인(inline) 스타일을 적용하는 것이다. HTML 태그에 인라인 스타일을 적용하는 것과 마찬가지로 style 속성을 사용하여 React 엘리먼트에 인라인 스타일을 곧바로 적용할 수 있다.
- 하지만 React에서는 웹 페이지와는 달리 인라인 스타일을 적용할 때 style 속성값으로 일반 문자열이 아닌 자바스크립트 객체를 할당해야만 하고, CSS 속성명을 카멜 표기법(CamelCase)으로 바꿔 작성해야만 한다.
// App.js
const appStyle = {
textAlign: "left"
};
const headerStyle = {
backgroundColor: "black",
color: "yellow",
textAlign: "center"
};
const titleStyle = {
textDecoration: "underline",
textShadow: "4px 1px #9c9c9c"
};
const App = () => {
return (
<div style={appStyle}>
<header style={headerStyle}>
<h1 style={titleStyle}>Hello, React!</h1>
</header>
<p>React 스타일링 수업에 잘 오셨습니다!</p>
</div>
);
};
export default App;
- 하지만 React 애플리케이션의 주요 스타일링 방식으로 style 속성을 활용한 인라인 스타일링만을 사용하는 것은 유지보수 측면이나 성능 상의 이유로 권장하지 않으며, style 속성은 렌더링될 때 동적으로 스타일을 추가하기 위해서만 사용하는 것이 좋다.
- 따라서 인라인 스타일링보다는 일반적으로 별도의 파일에 스타일을 정의해 놓고, className 속성을 사용하여 외부 CSS stylesheet에 정의된 클래스(class)를 참조하는 방식이 주로 사용된다.
/* styles.css */
.App {
text-align: left;
}
.App-header {
background-color: black;
color: yellow;
text-align: center;
}
.App-title {
text-decoration: underline;
text-shadow: 4px 1px #9c9c9c;
}
// App.js
import "./styles.css";
const App = () => {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">Hello, React!</h1>
</header>
<p>React 스타일링 수업에 잘 오셨습니다!</p>
</div>
);
};
export default App;
- CSS 클래스를 참조하는 속성명으로 class가 아닌 className을 사용해야 한다는 점에 주의하자
- 위와 같이 외부 CSS stylesheet를 참조하는 방식은 사용 방법이 매우 간단하다. 하지만 애플리케이션의 규모가 커질수록 컴포넌트의 개수도 증가하게 되고, 이렇게 관리해야 할 CSS 파일이 많아질수록 여러 컴포넌트에서 사용된 ClassName 속성값이 중복될 가능성도 함께 높아지는 단점이 있다.
CSS 선택자를 활용한 스타일링
- React 컴포넌트에 스타일을 적용하는 또 다른 방법으로는 CSS 선택자(Selector)를 활용한 방법이 있다. CSS에서는 스타일을 적용할 대상을 손쉽게 선택할 수 있도록 다양한 선택자를 제공하고 있으며, 이를 활용하여 컴포넌트에 손쉽게 스타일을 적용할 수 있다.
/* styles.css */
.App {
text-align: left;
}
/* .App에 포함되어 있는 <header>요소 */
.App header {
background-color: black;
color: yellow;
text-align: center;
}
/* .App에 포함되어 있는 <header>요소에 포함되어 있는 <h1>요소 */
.App header h1 {
text-decoration: underline;
text-shadow: 4px 1px #9c9c9c;
}
// App.js
import "./styles.css";
const App = () => {
return (
<div className="App">
<header>
<h1>Hello, React!</h1>
</header>
<p>React 스타일링 수업에 잘 오셨습니다!</p>
</div>
);
};
export default App;
Sass
- Sass(https://sass-lang.com/documentation)는 Syntactically Awesome Stylesheet(문법적으로 엄청나게 멋진 스타일시트)의 줄임말로 기존 CSS의 단점을 보완하기 위해 만들어진 스크립팅 언어인 동시에 CSS 전처리기(pre-processor)이다.
- 기존의 CSS 문법은 단순 반복되는 코드가 많았기에 프로젝트의 크기가 커질수록 작성되는 CSS 코드의 양도 많아지고 복잡해짐에 따라 유지 보수가 힘들었다. 또한, 다른 프로그래밍 언어에서는 기본적으로 제공되는 기본적인 연산 기능이나 함수 등을 미지원함으로 인해 언어적 한계성도 가지고 있다.
- 이에 Sass는 기존의 CSS 문법을 확장하여 반복되는 중첩 구문을 간결하게 만듦으로써 코드의 가독성을 높였다. 그리고 변수나 함수, 반복문, 조건문 등을 사용할 수 있도록 지원하고 있으며, Mixin 기능을 제공함으로써 코드의 재사용성을 높일 수 있도록 개발되었다. Mixin은 함수와 비슷한 동작을 하는 기능으로 CSS 스타일 시트에서 반복적으로 재사용할 수 있는 CSS 스타일 그룹을 선언하는 문법이다.
- Sass에서는 *.sass와 *.scss라는 두 가지 확장자를 지원하며, 기본적으로 CSS 문법을 확장하여 만든 언어이기 때문에 기존에 작성한 CSS 파일을 확장자만 *.sass 또는 *.scss로 변경해도 정상적으로 동작한다. 하지만 웹 브라우저는 스크립팅 언어인 Sass 파일을 인식할 수 없기 때문에 Sass로 작성된 코드는 별도의 컴파일러를 통해 웹 브라우저가 인식할 수 있는 일반적인 CSS 코드로 변환되어야만 한다.
Sass와 SCSS
- Sass는 크게 Sass와 SCSS로 구분할 수 있다.
- SCSS는 Sassy CSS(Sass한 듯한 CSS)의 줄임말로 Sass보다 늦게 개발되었지만, 좀 더 넓은 범용성과 CSS와의 완벽한 호환성이라는 장점을 가지고 있어서 현재 널리 사용되고 있다.
- 두 문법 사이의 가장 큰 차이점으로는 Sass는 들여쓰기를 사용하여 중첩을 표현하고, 속성들을 줄바꿈으로 구분한다. 하지만 SCSS는 중괄호({})를 사용하여 중첩을 표현하고, 속성들을 세미콜론(;)으로 구분한다.
- SCSS는 Sass의 문법에 기존 CSS에서 사용한 중괄호({})를 추가함으로써 코드의 가독성을 높이고 잘못된 들여쓰기나 줄바꿈으로 인한 실수를 미연에 방지할 수 있게 해준다.
/* CSS */
nav ul {
margin: 0;
list-style: none;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
}
/* Sass */
nav
ul
margin: 0
list-style: none
li
display: inline-block
a
display: block
padding: 6px 12px
/* SCSS */
nav {
ul {
margin: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
}
}
React에서 Sass 사용하기
- React에서 sass를 사용하기 위해서는 우선 node-sass 라이브러리를 설치해야 한다.
# npm인 경우
npm install node-sass
# yarn인 경우
yarn add node-sass
- 그리고 기존에 사용하던 CSS 파일의 확장자를 *.scss로 변경한다. SCSS는 기존 CSS 문법과 완전히 호환되므로 기존에 작성한 코드를 변경할 필요가 없다. 그리고 SCSS 파일 내 CSS 코드를 SCSS 문법으로 바꿔주기만 하면 된다.
// Menu.js
const Menu = () => {
return (
<nav>
<ul>
<li>Home</li>
<li>About</li>
<li>Service</li>
<li>Contact</li>
</ul>
</nav>
);
};
export default Menu;
/* styles.scss */
$primary-color: #93BFCF;
$secondary-color: #6096B4;
@mixin hover-text {
text-transform: uppercase;
font-weight: 600;
}
nav {
margin: 20px;
background-color: $primary-color;
ul {
list-style: none;
margin: 0;
padding: 0;
li {
padding: 20px;
display: inline-block;
text-align: center;
/* '&' 문자는 SCSS에서 부모 선택자를 참조할 때 사용 */
/* '&' 문자는 nav > ul > li 과 같은 의미 */
&:hover{
background-color: $secondary-color;
@include hover-text;
}
}
}
}
- CSS 문법을 확장하여 기존 CSS 스타일링에서의 여러 단점들을 개선한 Sass도 전처리를 위한 별도의 컴파일러가 필요하고, 컴파일하는데 추가적인 시간이 소요된다는 단점을 가지고 있다. 따라서 Sass를 사용하는 것이 CSS를 사용하는 것보다 무조건 더 좋다는 의미가 아니며, 프로젝트의 상황 및 특성을 고려하여 CSS와 Sass 중 적합한 스타일링 방식을 선택하여 사용하는 것이 중요하다.
CSS Module
- 외부 CSS 파일을 참조하는 방식은 React 애플리케이션의 규모가 커질수록 여러 컴포넌트에서 사용된 CSS 클래스명이 서로 중복될 가능성이 높아진다. 만약 서로 다른 두 개의 CSS 파일에 동일한 이름의 CSS 클래스가 정의되어 있다면, 해당 클래스가 적용된 React 엘리먼트는 이 두 스타일이 모두 한꺼번에 적용된다.
- 이와 같은 문제점을 해결하기 위해 CSS Module을 사용할 수 있습니다. CSS Module은 CSS 클래스를 불러와 사용할 때 클래스명을 고유한 이름으로 자동 변환해줌으로써 CSS 클래스명이 서로 중첩되는 현상을 미연에 방지해 주는 기술이다.
- React에서 CSS Module을 적용하는 방법은 아주 간단하다. 별도의 설정 없이 CSS Module을 적용하고 싶은 CSS 파일의 이름을 아래와 같은 방식으로 작성하기만 하면 자동으로 적용된다.
[모듈명].module.css
- CSS Module을 적용한 파일에 작성된 클래스는 아래 코드처럼 styles 객체를 활용하여 자바스크립트 객체의 프로퍼티(property) 형식으로 참조할 수 있다.
import styles from "파일 경로";
//...
<div className="{styles.[클래스명]}">...</div>
- React 컴포넌트에서 해당 CSS 파일을 불러올 때 선언된 CSS 클래스명은 모두 고유한 이름으로 자동 변환된다. 고유한 클래스명은 파일 경로, 파일 이름, 원래 작성한 클래스명, 해쉬값 등을 사용하여 자동 생성된다. 따라서 CSS Module을 사용하면 CSS 파일마다 고유한 네임스페이스를 자동으로 부여해 주기 때문에 각각의 React 컴포넌트는 완전히 분리된 스타일을 보장받는다.
/* FirstModule.css */
.wrapper {
color: yellow;
background-color: black;
text-align: center;
}
/* SecodeModule.css */
.wrapper {
color: white;
background-color: blue;
text-align: left;
}
// FirstModule.js
// import "./FirstModule.css"; // CSS 클래스명이 고유하지 않을 때
import styles from "./FirstModule.module.css"; // CSS Module 적용
const FirstModule = () => {
return (
//<div className="wrapper"> // CSS 클래스명이 고유하지 않을 때
<div className={styles.wrapper}> // CSS Module 사용
<h1>Hello, React!</h1>
</div>
);
};
export default FirstModule;
// SecondModule.js
// import "./SecondModule.css"; // CSS 클래스명이 고유하지 않을 때
import styles from "./SecondModule.module.css"; // CSS Module 적용
const SecondModule = () => {
return (
//<div className="wrapper"> // CSS 클래스명이 고유하지 않을 때
<div className={styles.wrapper}> // CSS Module 사용
<h1>Hello, React!</h1>
</div>
);
};
export default SecondModule;
- 컴포넌트에서 CSS Module을 불어와 저장할 때 사용한 styles라는 이름 대신에 어떠한 이름을 사용해도 괜찮다. 예제에서는 일반적으로 많이 사용하는 styles를 사용했을 뿐이며, 다른 이름을 사용해도 무방하다.
- 위의 예제와 같이 CSS Module을 사용하면 이미 다른 CSS 파일에 wrapper 클래스가 정의되어 있더라도 해당 CSS 파일에 정의된 wrapper 클래스는 전혀 영향을 받지 않는다.
- 최종적으로 렌더링된 웹 페이지를 개발자 도구로 확인해 보면 각 컴포넌트에 적용된 클래스명이 우리가 작성한 wrapper라는 이름이 아닌 해시(hash) 값이 뒤에 붙은 고유한 클래스명으로 변경되어 있는 것을 확인할 수 있다.
- 자동으로 생성된 고유한 클래스명: [파일명]_[클래스명]__[해시값]

여러 개의 클래스 적용하기
- 만약 CSS Module이 적용된 파일로부터 여러 개의 CSS 클래스를 불러와 적용하고 싶다면 ES6 문법부터 제공되는 템플릿 리터럴(template literal)을 사용하여 여러 개의 클래스명을 하나의 문자열로 합하여 적용할 수 있다.
- 이 때 템플릿 리터럴의 시작과 끝을 알려주는 '` ' 문자를 백틱(backtick)이라고 부르며, '$' 문자와 중괄호({})가 합쳐진 문자열 인터폴레이션(string interpolation)은 '+' 연산자를 사용하지 않고도 손쉽게 자바스크립트 표현식을 문자열로 변환할 수 있게 해준다.
/* FirstModule.module.css */
.wrapper {
color: yellow;
background-color: black;
text-align: center;
}
.h1 {
text-decoration: underline;
text-shadow: 5px 2px gray;
}
// FirstModule.js
import styles from "./FirstModule.module.css";
const FirstModule = () => {
return (
<div className={`${styles.wrapper} ${styles.h1}`}>
<h1>Hello, React!</h1>
</div>
);
};
export default FirstModule;
- 만약 템플릿 리터럴을 사용하고 싶지 않다면 적용하고 싶은 CSS 클래스들의 이름을 하나의 배열로 만든 후에 자바스크립트의 join() 메소드를 사용하여 배열의 모든 요소를 하나의 문자열로 반환하여 적용할 수 있다.
<div className={[styles.wrapper, styles.h1].join(" ")}>
CSS Module의 장점과 단점
- CSS Module을 이용한 스타일링 방식은 다음과 같은 장점을 가지고 있다.
- 동일한 클래스명의 재정의로 인한 스타일의 전역 오염을 미연에 방지할 수 있다.
- 자동으로 고유한 클래스명으로 변환해주기 때문에 클래스명을 짓기 위한 개발자의 고민을 줄여줄 수 있다.
- 컴포넌트 단위로 스타일을 관리할 수 있어서 스타일의 유지보수가 편해진다.
- 다만 CSS Module은 모듈마다 별도의 CSS 파일을 작성해야 하기 때문에 별도로 많은 CSS 파일을 만들어 관리해야 한다는 단점을 가진다. 또한, 클래스를 동적으로 추가할 경우 최종 렌더링된 결과물에서 자동 변환된 클래스명이 코드의 가독성을 어지럽히는 경우가 종종 발생한다.
// isHovered 변수의 불리언값에 따라 styles.h1 스타일의 적용 유무를 제어하는 조건부 스타일 예제
// FirstModule.js
import styles from "./FirstModule.module.css";
const FirstModule = () => {
let isHovered = false;
return (
<div className={`${styles.wrapper} ${styles.h1 && isHovered}`}>
<h1>Hello, React!</h1>
</div>
);
};
export default FirstModule;
- 이 예제를 렌더링한 웹 페이지를 확인해 보면 해당 컴포넌트에 적용되지 않은 CSS 클래스명이 불리언 값인 false와 함께 추가되어 있는 것을 확인할 수 있다. 이렇게 적용되지 않은 클래스명이 최종 렌더링된 웹 페이지에 추가됨으로써 코드의 가독성이 매우 좋지 않게 되었다.
classnames
- 적용되지 않은 클래스명이 최종 렌더링된 웹 페이지에 추가됨으로써 코드의 가독성이 매우 좋지 않게 만드는 문제점을 해결하기 위해 많은 개발자들이 CSS Module을 사용하는 경우에 classnames 라이브러리를 함께 사용하고 있다.
- classnames 라이브러리는 CSS 클래스를 동적으로 설정하는 조건부 스타일링 작업에 매우 유용한 라이브러리이며, CSS Module에서 여러 개의 클래스를 동시에 적용할 때 매우 편리하게 사용할 수 있다.
- React에서 classnames를 사용하기 위해서는 우선 classnames 라이브러리를 설치해야 한다.
# npm인 경우
npm install classnames
# yarn인 경우
yarn add classnames
- classnames의 기본적인 사용 방법은 다음과 같다.
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
// 불리언 값인 false로 평가되는 값들은 모두 무시된다
classNames(null, false, 'foo', undefined, 0, 1, { bar: null }, ''); // => 'foo 1'
- 위와 같이 여러 타입의 값들을 다양하게 조합하여 클래스명을 작성할 수 있기 때문에 CSS 클래스를 동적으로 설정할 때 매우 편리하다.
- 또한, classnames 라이브러리에서 제공하는 bind() 메소드를 사용하면 매번 styles.[클래스명] 형태로 클래스를 호출하지 않고도 바인드한 이름을 사용하여 여러 클래스를 한 번에 불러올 수 있다. bind() 메소드를 사용하기 위해서는 우선 classnames/bind 패키지에서 classNames를 불어와야 한다.
- 이를 활용하여 CSS Module에서 동적으로 추가되는 클래스명의 좋지 않은 가독성 문제를 해결할 수 있다.
// FirstModule.js
import styles from "./FirstModule.module.css";
import classNames from "classnames/bind";
const FirstModule = () => {
const cx = classNames.bind(styles);
let isHovered = false;
return (
<div className={cx("wrapper", { h1: isHovered })}>
<h1>Hello, React!</h1>
</div>
);
};
export default FirstModule;
- 위 예제를 렌더링한 웹 페이지를 확인해 보면 조건에 의해 적용되지 않은 클래스명은 최종 결과물에 추가되지 않은 것을 확인할 수 있다.
styled-components
CSS-in-JS
- CSS가 등장한 이후 웹 앱은 점점 더 복잡해지고 동적인 기능들의 요구 또한 꾸준히 증가해 왔다. 이에 따라 HTML과 CSS만으로는 사용자 View에 대한 모든 스타일링 요구를 처리할 수 없는 상황에 이르게 되었다.
- 이를 해결하기 위해 성능과 효율을 위한 다양한 라이브러리와 프레임워크가 등장하게 되었으며, 우리가 앞서 살펴 본 Sass와 같은 CSS 전처리기를 사용하는 방식과 CSS Module처럼 CSS를 모듈화하여 사용하는 방식 등이 개발되었다.
- 하지만 위와 같은 CSS-in-CSS 방식과는 다른 관점에서 이러한 문제점을 해결하려는 시도가 등장한다. 2014년 페이스북의 개발자였던 Christopher Chedeau(vjeux)에 의해 자바스크립트(JS) 코드 안에 CSS 코드를 함께 작성하는 방식인 CSS-in-JS에 대한 개념이 제시되었다.
CSS-in-JS의 특징
- Christopher Chedeau(vjeux)는 기존의 CSS 스타일링 방식이 다음과 같은 문제들로 인해 사용이 점차 어려워지고 있다고 설명한다.
- Global namaspace : CSS는 전역 스코프에 모든 스타일을 작성하기 때문에 CSS 클래스명에 대한 별도의 명명 규칙이 필요하다.
- Dependencies : 하나의 CSS 스타일이 여러 HTML 요소에 적용될 수 있으며, 반대로 하나의 HTML 요소에 여러 CSS 스타일이 적용될 수도 있다. 이 모든 관계는 명시적이지 않기 때문에 개발자가 이 모든 의존 관계를 기억해야만 한다.
- Dead Code Elimination : CSS 코드의 의존 관계는 명시적이지 않기 때문에 현재 사용되고 있지 않은 코드의 파악이 쉽지 않으며, 이에 따라 기능 변경에 따른 유지보수가 힘들다.
- Sharing Constants : JS와 CSS 파일이 서로 분리되어 있기 때문에 JS의 상태 값을 CSS에 공유하기 어렵다.
- Non-deterministic Resolution : 로드 순서에 따라 CSS의 우선 순위가 변경되므로, CSS의 로드 순서까지 관리해야만 한다.
- 이에 Christopher Chedeau(vjeux)는 CSS-in-JS라는 개념을 제시하면서, 이를 사용하면 위에서 언급한 문제들이 다음과 같이 해결될 것이라고 설명했다.
- Global namaspace : CSS 스타일이 지역 스코프로 한정되므로, 별도의 명명 규칙이 필요하지 않다.
- Dependencies : CSS가 컴포넌트 레벨에서 모듈화되므로, CSS 간의 의존 관계를 고려할 필요가 없다.
- Dead Code Elimination : CSS가 컴포넌트와 같은 파일에 존재하므로, 사용되지 않는 코드를 간단히 파악할 수 있다.
- Sharing Constants : JS 코드와 CSS 코드가 한 파일에 존재하므로, 상태나 함수를 서로 쉽게 공유할 수 있다.
- Non-deterministic Resolution : HTML과 CSS를 강하게 결합시킴으로써, 현재 렌더링된 HTML에 적용된 CSS가 무엇인지 언제나 알 수 있다.
CSS-in-JS의 단점
- 이렇게 다양한 장점을 가지고 있는 CSS-in-JS 방식도 다음과 같은 문제점을 가지고 있다.
- CSS-in-JS는 컴포넌트가 렌더링될 때 자바스크립트 코드의 해석 과정이 필요하므로, 추가적인 CPU의 런타임 오버헤드(runtime overhead)가 발생한다.
- CSS-in-JS 방식으로 구현된 React 웹 앱을 방문하는 사용자들은 해당 라이브러리를 다운로드해야만 하므로, 번들의 크기가 늘어나고 렌더링 속도가 저하된다.
- CSS-in-JS의 각 속성들이 React DevTool에 포함되므로, 디버깅할 때 DevTool을 통한 코드의 가독성이 저하된다.
- 이와 같은 새로운 패러다임의 등장으로 CSS-in-JS 개념을 구현한 수많은 라이브러리가 등장했으며, 대표적인 라이브러리로는 styled-components, Emotion, styled-jsx, vanilla-extract 등이 있다.
styled-components
- styled-components(https://styled-components.com)는 React에서 사용되고 있는 CSS-in-JS 방식의 라이브러리 중에서 가장 많이 사용되고 있는 라이브러리다.
# npm인 경우
npm install styled-components
# yarn인 경우
yarn add styled-components
- styled-components를 사용하기 위해서는 우선 styled-components 패키지를 불러와야 한다.
- styled-components는 HTML 요소나 React 컴포넌트에 원하는 스타일을 적용할 때 사용되며, 스타일링 대상에 따라 사용 방법이 약간 다르다.
- 첫 번째로 HTML 요소의 경우에는 기본적인 HTML 요소에 대한 속성은 미리 정의되어 있기 때문에 해당 태그명을 그대로 사용하여 CSS 스타일을 정의할 수 있다.
styled.[HTML태그명]`CSS 스타일`;
// App.js
import styled from "styled-components";
// CSS 스타일이 적용된 새로운 HTML <button>요소를 생성하여 ButtonOne이라는 이름의 컴포넌트로 저장
const ButtonOne = styled.button`
padding: 6px 12px;
margin: 10px;
border: 2px solid orange;
color: orange;
font-size: 1rem;
`;
<div>
<ButtonOne>오렌지색 버튼</ButtonOne>
</div>
- 두 번째로 React 컴포넌트의 경우에는 특정 컴포넌트를 인수로 전달함으로써 해당 컴포넌트의 CSS 스타일을 손쉽게 확장하여 사용할 수 있다. 즉, 인수로 전달된 컴포넌트의 스타일은 모두 그대로 상속 받은 채 특정 스타일을 추가하거나 변경한 컴포넌트를 손쉽게 생성할 수 있다.
styled([REACT컴포넌트명])`CSS 스타일`;
// App.js
const ButtonOne = styled.button`...`
// 인수로 전달받은 ButtonOne 컴포넌트의 모든 스타일을 상속 받고
// 그 중에서 border 속성과 color 속성만을 다른 스타일로 변경한 ButtonTwo 컴포넌트를 생성
const ButtonTwo = styled(ButtonOne)`
border: 4px solid green;
color: green;
`;
<div>
<ButtonOne>오렌지색 버튼</ButtonOne>
<ButtonTwo>초록색 버튼</ButtonTwo>
</div>
Tagged 템플릿 리터럴
- 위의 예제에서 우리는 CSS 스타일을 백틱(`) 문자를 사용하여 문자열 형태로 작성하였다. 이 방식은 CSS Module에서 살펴 본 템플릿 리터럴과 아주 비슷하지만, 커스텀 tag 함수를 사용하여 템플릿에 추가한 자바스크립트 객체나 함수를 컴포넌트에서 온전히 추출할 수 있다는 점이 다른데, 이를 Tagged 템플릿 리터럴이라고 한다.
- 템플릿 리터럴에서 문자열 인터폴레이션(string interpolation)을 사용하여 객체나 함수를 추가하면 해당 객체나 함수는 단순 문자열로 치환되어 저장된다. 하지만 Tagged 템플릿 리터럴에서는 템플릿 안에 넣은 객체나 함수를 원래대로 다시 추출할 수 있다.
- 이와 같은 특성을 활용하여 컴포넌트에서 전달한 props 값을 스타일에서 손쉽게 참조하여 사용할 수 있으며, 이를 통해 컴포넌트에서 넘어온 props 값에 따라 서로 다른 스타일을 적용할 수 있다.
// App.js
// props를 통해 서로 다른 color 속성값을 전달하여 서로 다른 스타일의 컴포넌트를 생성
const ButtonOne = styled.button`
padding: 6px 12px;
margin: 10px;
border: 2px solid ${(props) => props.color};
color: ${(props) => props.color};
font-size: 1rem;
`;
<div>
<ButtonOne color="red">빨간색 버튼</ButtonOne>
<ButtonOne color="orange">주황색 버튼</ButtonOne>
</div>
//...
css prop를 활용한 조건부 스타일링
- Tagged 템플릿 리터럴을 사용하면 props 값에 따라 서로 다른 스타일의 React 컴포넌트를 생성할 수 있다. 하지만 props에 따라 바꾸고 싶은 CSS 속성이 하나가 아니라 여러 개일 경우에는 styled-components에서 제공하는 css prop을 사용하여 여러 개의 CSS 속성을 하나로 묶어서 정의할 수 있습니다. css prop을 사용하기 위해서는 먼저 styled-components 패키지에서 css를 불러와야 한다.
// App.js
import styled, { css } from "styled-components";
const ButtonOne = styled.button`
padding: 6px 12px;
margin: 10px;
border: 2px solid ${(props) => props.color};
color: ${(props) => props.color};
font-size: 1rem;
${(props) =>
props.bold &&
css`
color: ${(props) => props.color};
font-weight: 600;
border: 4px solid ${(props) => props.color};
`}
`;
<div>
<ButtonOne color="red">빨간색 버튼</ButtonOne>
<ButtonOne color="orange" bold>주황색 버튼</ButtonOne>
// <ButtonOne color="orange" bold=”true”>는 같은 의미
// props의 값을 생략하면, 해당 값을 true라고 간주
</div>
Reference
반응형
'Development > ReactJs' 카테고리의 다른 글
[React] 리액트 렌더링 - 조건부 렌더링, 배열 렌더링 (1) | 2025.03.08 |
---|---|
[React] 리액트 이벤트 핸들링 - 이벤트 핸들링 및 전파 (0) | 2025.03.07 |
[React] 리액트 데이터 관리 - Props, State (1) | 2024.11.19 |
[React] 리액트 컴포넌트 - 엘리먼트, export, import, default (0) | 2024.11.18 |
[React] 리액트 JSX - 정의, 모듈, 문법, DOM 속성 (2) | 2024.11.18 |