[Day 45] Styling(BEM, CSS Modules, React UI Framework, Sass, StoryBook)
CSS 방법론
BEM (Block Element Modifier)
정의
클래스 이름을 짓는 방법 (.header__navigation--secondary
같은 형식으로 쓴다.)
BEM에서는 클래스 이름으로 어떤 요소의 명확한 역할과 책임만 명시해준다.
공유되는 부분은 scss 문법의 @mixin
을 이용해서 표현한다.
Block
문단 전체에 적용된 엘리먼트 또는 엘리먼트를 담고 있는 컨테이너를 말한다.
/* 리액트에서는 컴포넌트의 이름을 블록 이름으로 쓴다. */
.PostList {...}
.PostDetail {...}
Element
엘리먼트는 블록 안에서 특정 기능을 수행하는 컴포넌트를 말한다.
/* 블록이름__엘리먼트이름 구조로 네이밍한다. */
.header__logo {...}
.header__menu {...}
.header__search {...}
.header__login {...}
/* 블록이름이나 엘리먼트 이름이 긴 경우 '-' 으로 연결한다. */
.block-name__element-name
Modifiers
모디파이어는 블록 또는 엘리먼트의 속성(상태)이다. —> 이 속성은 블록 또는 엘리먼트의 외관이나 상태를 변화시킨다.
/* Class 명에 '-'를 추가해서 모디파이어를 추가한다. */
.block--modifier {...}
.block__element--modifier {...}
CSS Modules
Create React App - Adding a CSS Modules Stylesheet
CSS Modules
는 Create React App ver2.0+ 에서 새로 추가된 기능이다.
클래스 이름을 유일하고 식별 가능하게 자동으로
만들어준다. —> 즉, BEM을 자동으로 해준다.
(장점) 여러 파일에서 같은 클래스 이름을 사용할 수 있게 해준다.
import React, { Component } from 'react';
import styles from './Button.module.css'; // Import css modules stylesheet as styles
import './another-stylesheet.css'; // Import regular stylesheet
class Button extends Component {
render() {
// reference as a js object
return <button className={styles.error}>Error Button</button>;
}
}
/*
CSS의 클래스 이름이 규칙에 맞춰서 변환되고, import 해오는 styles 객체에 매핑된다. ---> 객체의 속성이름에는 내가 정한 클래스명이 사용되고, 속성값에는 변환된 클래스명이 저장된다.
*/
React UI Framework
기능을 컴포넌트 단위로 미리 만들어 놓은 것.
- Semantic UI React (Semantic UI의 React 버전)
- ReactStrap (BootStrap의 React 버전)
Sass
Variables
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
Nesting
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
Import
// base.scss
@import 'reset';
body {
font: 100% Helvetica, sans-serif;
background-color: #efefef;
}
파일을 불러와서 합쳐준다. —> 합쳐진 파일만 제공하면 된다.
여러 파일에서 공유해야 하는 변수, 코드를 다른 파일에다 작성해두고 @import
해오는 방식으로 사용하면 된다.
MixIns
공유되어야 하는 코드 뭉치를 @mixin
으로 묶어서 함수처럼 재사용할 수 있다.
// mixin은 일종의 함수와 같다.
@mixin transform($property) {
-webkit-transform: $property;
-ms-transform: $property;
transform: $property;
}
// mixin을 불러올 때는 @include
.box { @include transform(rotate(30deg)); }
(중요!!) MixIn을 활용한 Media Query 작성
// commons.scss
@mixin desktop {
@media screen and (min-width: 768px) {
// @include에서 받아온 내용을 @content에 매핑해준다.
@content
}
}
// index.scss
&__list {
@include common-border;
@include desktop {
// 아래의 코드가 @content에 매핑된다.
border-color: yellow;
}
}
Operators
CSS 에서의 calc()
함수와 비슷하게 계산을 해준다.
.container {
width: 100%;
}
article[role="main"] {
float: left;
width: 600px / 960px * 100%;
}
aside[role="complementary"] {
float: right;
width: 300px / 960px * 100%;
}
UI Develop Utils
StoryBook
UI 개발할 때 각각의 페이지를 하나하나 스토리북으로 만들어서 테스트하기 편하게 해주는 도구 —>
// 설치는 아래와 같이 한다.
npx -p @storybook/cli sb init
// 시작은 아래와 같이 한다.
npm run storybook
설치하고 난 뒤 project root directory에 생긴 .storybook
폴더에 들어있는 config.js
파일을 수정해준다. —> Storybook의 Default Setting은 src/stories 에서 각각의 컴포넌트를 확인할 수 있는 구조로 되어 있는데, 이를 src/components 에서 확인할 수 있는 구조로 바꿔준다.
// .storybook/config.js
import { configure } from '@storybook/react';
const req = require.context('../src/components', true, /\.stories\.js$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
컴포넌트를 Storybook 에서 확인하려면 따로 파일을 만들어야 한다.
// 파일명은 보통 ComponentName.stories.js 형태로 만든다.
// 이 파일의 코드에 스토리북에 넣을 컴포넌트를 매핑해주면 된다.
// ex. PostForm.stories.js
import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';
import { Button, Welcome } from '@storybook/react/demo';
import PostForm from './PostForm'
// .add('title', () => <ComponentName />) 형태로 넣어준다.
// props가 들어오는 상황에 따라 각기 다른 페이지로 만들어줄 수 있다.
storiesOf('PostForm', module)
.add('default', () => <PostForm />)
.add('editing', () => <PostForm editing = {true} />)
스토리북은 통신이나 상태변화 같은 부작용을 일으키는 코드가 없는(외부세계와 연동되지 않은) 컴포넌트에서만 사용해야 한다.
—> 부작용이 있는 컴포넌트에서는 테스트하기가 어렵기 때문에 컴포넌트를 만들 때 역할과 책임을 명확하게 정해줘야 한다. (화면을 그리기만 하는 컴포넌트 vs 부작용을 일으키는 컴포넌트)
—> 컴포넌트를 부작용을 담당하는 컴포넌트(Container Component)와 화면 그리기만 담당하는 컴포넌트(Presentational Component)로 나눠서 작성하는 것이 관례(Best Practice)다.
댓글남기기