스타일링 방식
- CSS를 작성할 때 가장 중요한 점은 클래스명을 중복되지 않게 만드는 것!
1. 일반 CSS
1) 이름 짓는 규칙: 컴포넌트 이름 - 클래스 형태(App-headr) 혹은 BEM 네이밍(일종의 규칙을 준수하여 해당 클래스가 어디에서 어떤 용도로 사용되는지 명확하게 작성 ex) .card__title-primary)
2) CSS Selector: 특정 클래스 내부에 있는 경우에만 스타일 적용(ex) .App .logo: App안에 들어있는 .logo, .App a: App안에 들어있는 a태그 .생략)
2. Sass(Syntactically Awesome Style Sheets)
- CSS 전처리기; 복잡한 작업을 쉽게 할 수 있도록 해주고 스타일 코드의 재활용성을 높여주고 코드의 가독성을 높여 유지 보수를 쉽게 해줌.
-변수할당, 중첩구문, 모듈화, 믹스인(param받아서 속성 부여), 확장&상속, 연산자 기능 제공
.sass: 들여쓰기로 중첩 표현, 줄바꿈 만으로 속성 구분
body
font: 100% $font-stack
color: $primary-color
.scss: 중괄호로 중첩 표현, 세미콜론으로 속성 구분
body{
font: 100% $font-stack;
color: $primary-color;
}
-전세계적으로 사용자수나 활용이 SCSS > SASS
-SASS보다 SCSS가 기존 CSS와의 문법이 비슷, 호환성 좋음
3. CSS Module
-스타일을 작성할 때 CSS 클래스가 다른 CSS 클래스의 이름과 절대 충돌하지 않도록 파일마다 고유한 이름([파일이름]_[클래스 이름]_[해시값]) 형태을 자동으로 생성해줌. 클래스명 명명하느라 고민하지 않아도 됨.
-리액트 v2 버전 이상부터는 .module.css 확장자로 파일을 저장하기만 하면 적용됨
-글로벌 CSS라면 :global을 앞에 입력하여 명시
-classname 라이브러리: 여러 종류의 파라미터를 조합해 CSS 클래스 설정할 수 있어 컴포넌트에서 조건부로 클래스 설정하기 편함
//highlighted값이 true이면 클래스 적용, false이면 적용되지 않음
const MyComponent = ({highlighted, theme}) => (<div className={classNames('MyConponent', {highlighted}, theme)}>Hello</div>
);
-라이브러리 사용 없이 처리
const MyComponent = ({highlighted, theme}) => (<div className={`MyConponent ${theme} ${highlighted ? 'highlighted' : ''}`}>Hello</div>
);코드를 입력하세요
-CSS Module아닌 파일에서 CSS Module 사용하려면 :local 사용(ex) .local .wrapper{/*스타일*/})
4. Styled-component
-스타일을 JS 파일에 내장시키는 방식. (css-in-js 라이브러리의 일환; cf) emotion) 스타일을 작성함과 동시에 해당 스타일이 적용된 컴포넌트를 만들 수 있게 해줌.
-컴포넌트 상단에서 styled 를 import하고, styled.태그명을 사용하여 구현
*CSS Module과 Styled-component 비교
-CSS Module 적용
//Button.js
import React from 'react';
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;
//Button.module.css
.button {
width: 100%;
font: inherit;
padding: 0.5rem 1.5rem;
border: 1px solid #8b005d;
color: white;
background: #8b005d;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
cursor: pointer;
}
.button:focus {
outline: none;
}
.button:hover,
.button:active {
background: #ac0e77;
border-color: #ac0e77;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
}
//반응형 디자인: 768px 미만 꽉채우기
@media (min-width: 768px) {
.button {
width: auto;
}
}
-Styled-component 적용
//Button.js
import React from 'react';
import styled from 'styled-components';
//CSS-IN-JS
const Button = styled.button`
font: inherit;
padding: 0.5rem 1.5rem;
border: 1px solid #8b005d;
color: white;
background: #8b005d;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
cursor: pointer;
//반응형 디자인: 768px 이상 꽉채우기
//실제로 사용한다면 아예 다른 파일로 모듈화 한 뒤 여기저기서 사용하는 방식이 편할 것(styled-components 매뉴얼에서 제공하는 유틸 함수 참고)
@media (min-width: 768px) {
width: 100%;
}
//&문자 사용하여 Sass처럼 자기 자신 선택 가능
&:focus {
outline: none;
}
&:hover,
&:active {
background: #ac0e77;
border-color: #ac0e77;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
}
`;
export default Button;
-조건부 스타일링
//CourseInput.js
import React, { useState } from 'react';
// import styled from 'styled-components';
import Button from '../../UI/Button/Button';
import styles from './CourseInput.module.css';
// const FormControl = styled.div`
// margin: 0.5rem 0;
// & label {
// font-weight: bold;
// display: block;
// margin-bottom: 0.5rem;
// color: ${(props) => (props.invalid ? 'red' : 'black')}
// }
// & input {
// display: block;
// width: 100%;
// border: 1px solid #ccc ${(props) => (props.invalid ? 'red' : '#ccc')};
// background: ${(props) => (props.invalid ? '#ffd7d7' : '#ccc')}
// font: inherit;
// line-height: 1.5rem;
// padding: 0 0.25rem;
// }
// & input:focus {
// outline: none;
// background: #fad0ec;
// border-color: #8b005d;
// }
// // &.invalid input {
// // border-color: red;
// // background: #ffd7d7;
// // }
// // &.invalid label {
// // color: red;
// // }
// `;
const CourseInput = (props) => {
const [enteredValue, setEnteredValue] = useState('');
const [isValid, setIsValid] = useState(true);
const goalInputChangeHandler = (event) => {
if (enteredValue.trim().length > 0) {
setIsValid(true);
}
setEnteredValue(event.target.value);
};
const formSubmitHandler = (event) => {
event.preventDefault();
if (enteredValue.trim().length === 0) {
setIsValid(false);
return;
}
props.onAddGoal(enteredValue);
setEnteredValue('');
};
return (
<form onSubmit={formSubmitHandler}>
{/* 조건값을 참조하여 설정 */}
{/* <FormControl className={!isValid && 'invalid'}> */}
{/* <FormControl invalid={!isValid}> */}
{/* 템플릿 리터럴 사용 */}
<div className={`${styles['form-control']} ${!isValid && styles.invalid}`}>
<label>Course Goal</label>
<input type='text' value={enteredValue} onChange={goalInputChangeHandler} />
</div>
<Button type='submit'>Add Goal</Button>
</form>
);
};
export default CourseInput;
//CourseInput.module.css
.form-control {
margin: 0.5rem 0;
}
.form-control label {
font-weight: bold;
display: block;
margin-bottom: 0.5rem;
}
.form-control input {
display: block;
width: 100%;
border: 1px solid #ccc;
font: inherit;
line-height: 1.5rem;
padding: 0 0.25rem;
}
.form-control input:focus {
outline: none;
background: #fad0ec;
border-color: #8b005d;
}
.form-control.invalid input {
border-color: red;
background: #ffd7d7;
}
.form-control.invalid label {
color: red;
}
참고
-리액트다루는기술
-react complete guide