앱이 보기좋게 컴포넌트를 스타일링한다. 조건부나 동적인 방식으로 스타일링을 하는 다양한 기술들이 존재한다.
일반적인 css 파일을 js파일에 import하여 사용하지만, 해당 컴포넌트가 아닌 전체 페이지의 모든 요소에 영향을 미친다.
<label style={{ color: isValid ? 'black' : 'red' }}>Contents</label>
이런 방식은 문제가 존재한다. 항상 inline 방식이어야 하며, css를 오버라이드하는 최우선 순위로 적용되기 때문이다.
Vue의
Binding Inline Style
과 동일한 방식이다.<div :style="{ color: isValid ? 'black' : 'red' }">Contents</div>
백틱을 사용한 템플릿 리터럴을 이용하여 상태 값에 동적으로 클래스명을 구현한다.
<div className={`form-control ${!isValid ? 'invalid' : ''}`}>
// ...
</div>
Vue의
Binding HTML Classes
와 동일한 방식이다.<div :class="[isActive ? activeClass : '', errorClass]">Contents</div>
컴포넌트 파일에 css파일을 import하면, 컴포넌트에만 적용되는 것이 아니라 앱 페이지 전체에 삽입된다. 그렇다면 앱 내 동일한 클래스명에 다같이 적용된다는 뜻을 의미한다. 대규모 프로젝트에서는 실수할 수 있는 잠재적 사이드이펙트를 가질 수 있다.
styled components는 특정 스타일이 첨부된 컴포넌트를 구축할 수 있도록 도와주는 패키지이다. 특정 컴포넌트를 제외한 다른 컴포넌트에는 영향을 주지 않는다.
npm install --save styled-components
styled-components를 설치한다.
import styled from 'styled-components';
const Button = styled.button`
font: inherit;
color: white;
&:focus {
outline: none;
}
&:hover {
background: #ac0e77;
}
`;
export default Button;
styled.button뒤에 백틱이 존재한다. 이를 taged template literal이라고 한다. styled.button 함수에 특별한 방식으로 메소드에 값을 전달한다. styled. 뒤에는 요소들을 넣을 수 있다. 그 중 Button 컴포넌트를 리턴하기 위해 button을 선택하였다. 백틱 안에 css의 내용을 추가한다. 그리고 & 연산자를 사용하여 focur, hover, active 등의 상태 스타일도 추가한다.
devtools의 elements탭에서 button 요소를 살펴보자
<button type="submit" class="sc-bcXHqe iSZPmF">Add</button>
class에 이상한 문자열 2개가 존재한다. 이 클래스명은 유저가 만든 것이 아닌 styled-components 패키지에 의해 동적으로 생성된 문자열이다. 이 패키지는 우리가 백틱 안에 설정한 스타일을 보고 생성된 임의의 클래스명으로 스타일을 감싼다. 고유한 임의의 클래스명으로 생성하여 다른 컴포넌트에 영향을 주지 않게 만든다.
Vue의
Scoped CSS
와 동일한 방식이다.<style scoped> .example { color: red; } </style> <template> <div class="example">hi</div> </template>
props를 이용하여 동적 스타일을 구현할 수 있다.
const FormDiv = styled.div`
color: white;
&.invalid {
color: red;
}
`;
return (
<FormDiv className={!isValid && 'invalid'}>
// ...
</FormDiv>
);
styled components로 만들어진 컴포넌트를 JSX안에 넣고 className를 동적으로 구성하는 방법이 존재한다.
const FormDiv = styled.div`
color: white;
&.invalid {
color: ${props => (props.invalid ? 'red' : 'white')};
}
`;
return (
<FormDiv invalid={!isValid}>
// ...
</FormDiv>
);
invalid를 태그에 바인딩시키고, styled안에 props로 활용할 수 있다. 또한 가상선택자 스타일을 제거할 수 있다.
Vue의
v-bind() in CSS
와 비슷한 것 같다.<template> <div class="text">hello</div> </template> <script> export default { data() { return { color: 'red' } } } </script> <style> .text { color: v-bind(color); } </style>
import styled from 'styled-components';
const Button = styled.button`
@media (조건) {
...
}
`;
css 파일과 js를 분리하는 것을 선호할 때 사용.
브라우저에서 코드가 실행되기 전에 코드의 변환이 필요하다. react CRA에는 이미 css 모듈을 지원하도록 설정되어있다.
스타일을 담은 Buttom.module.css 파일을 생성한다.
import styles from './Button.module.css';
const Button = props => {
return (
<button
type={props.type}
className={styles.button}
onClick={props.onClick}
>
{props.children}
</button>
);
};
export default Button;
DevTools > elements에
<button type="submit" class="Button_button__nN4lI">Add</button>
와 같이 이상한 클래스명이 존재한다. 실제 styled 컴포넌트가 추가한 이름이 아니다.
컴포넌트명_클래스명__고유해시값
으로 클래스명이 만들어진다.
css 클래스나 파일을 가지고 클래스명을 고유하게 변경한다. 새로운 클래스명으로 래핑한다.
css 모듈의 개념은 css 파일에서 설정한 스타일의 범위가 import하는 컴포넌트에만 한정된다.
.form-control {
background-color: red;
}
.form-control.invalid {
background-color: red;
}
import styles from './CourseInput.module.css';
const Form = () => {
return (
<form>
<div className={`${styles['form-control']} ${!invalid && styles.invalid}`}>
</form>
);
}
객체로서 className에 동적으로 접근 가능