1. CSS Framework의 역사
- HTML의 탄생, 1990년
- HTML은 콘텐츠에 의미를 부여하는 태그를 붙여주어 서식을 꾸미는 방식
- inline-style : 태그에 직접 style을 지정하는 방식
- 코드가 너무 비대해지거나 가독성이 떨어지고 유지 보수가 어려움
- CSS : inline-style의 중복을 제거
- Sass(2006) : Syntactically Awesome Style Shets, selector를 세분화
- CSS의 단점을 보완하기 위해 만든 CSS 전처리기
- CSS의 단순 반복되는 부분을 해결
- Ajax의 등장과 HTML 편집권의 변화
- 백엔드에서 HTML을 제외한 데이터만 전달할 수 있게되면서 HTML의 편집권은 백엔드에서 프론트엔드로 내려오게 됨
- CSS를 복잡하게 하는 것보다 HTML을 복잡하게 하는 것이 더 낫다는 것을 알게 됨
(CSS에서 복잡한 Selector를 쓰기 보다는 HTML에서 미리 잘 지어둔 class명이 더 좋음)
- BEM(2013) 방식 : Block_Element_Modiflier로 구성하여 이름을 짓는 방법
- CSS Modules(2015) : CSS의 문제인 Global Scope를 막기 위해 Component 단위에서 사용되는 CSS에 hash를 추가하여 CSS가 더 이상 global하지 않도록 하는 방식
- class명에 hash값을 붙여 다시 생성하여 모듈로 내보내 사용
- CSS-in-JS의 등장 : styled component, emotion
- Atomic CSS : class명에 해당하는 태그의 스타일을 작성하면 됨
2. CSS Framework
0. 순위
- 부동의 1위, bootstrap
- 놀라운 tailwindcss의 성장세
1. CSS Pre-processor : CSS 전처리기
1) Sass(Syntactically Awesome Style Sheet)
-
CSS를 로직이 있는 언어로 접근하여 재사용성을 높임
-
간편한 문법으로 구현한 코드가 렌더링 시 순수 CSS로 변환됨
- 성능이 느려지는 것을 해결하기 위해 Zero-Time CSS, Nere Zero CSS 컨셉 발전 중
-
사용법 : 컴파일러 설치 후 .scss or .sass 파일에 (문법이 있는) CSS 작성
style.sass $base-color: #c6538c; $border-dark: rgba($base-color, 0.88); .alert { border: 1px solid $border-dark; }
2. CSS-in-CSS
1) CSS Module
-
CSS파일에 선언한 class명이 자동 변경되어 중복을 신경쓰지 않아도 되며, 전체 페이지의 CSS를 렌더링 시 한 번에 로드함
-
CSS 코드가 JS 번들에 포함되어 있지만, 온전한 CSS형태를 유지하고 있어 CSS-in-JS에 비해 짧은 시간에 화면을 그릴 수 있음
-
모든 CSS를 가져오므로 컴포넌트 기반 개발에서는 비효율적임
-
매번 JS파일에 CSS import해야 하는 과정이 번거로움
-
컴포넌트가 자주 바뀌는 interactive한 웹 개발 시 Javascript가 변경되더라도 CSS에 영향이 없이 바로 적용되므로 효율적임
-
zero-runtime
-
사용법: .module.css 파일에 일반 CSS 작성
// style.module.css .className { color: green; background: red; }
3. CSS-in-JS
1) Styled-component
runtime: runtime과정에서 필요한 css를 동적으로 만들어 적용- runtime에서 동적으로 스타일을 생성하기에 스타일이 수시로 변경된다면, runtime 오버헤드가 발생할 수 있다.
- 개발 모드에서는
- 배포 모드에서는 styleSheet를 CSSSTyleSheet.insertRule을 통해 CSSOM에 주입 → 성능상의 이점
- 장점
- CSS를 JS를 통해서만 만들어 CSS범위를 컴포넌트 내부로 국한하며, 컴포넌트로 전달하는 값(JS 함수,값 공유)에 따라 동적으로 스타일 적용 가능
- CSS의 global scope 문제를 해결하고 selector가 사라져 specificity 문제도 사라짐
- Global Scope 문제 : 전역에 스타일이 적용되는 문제
- 활성화된 컴포넌트 관련 스타일만 가져오므로 컴포넌트 기반 개발에서는 효율적임
- 중복되지 않는 class 이름을 고려할 필요가 없음
- 컴포넌트와 스타일 코드를 쉽게 오갈 수 있다.
- 단점
- JS 런타임에서 동적인 클래스명이 생성(클래스명 지정X)되며, CSS 구문 분석 과정이 필요하여 렌더링 속도가 낮아짐
- 이미 마크업 개발자가 만들어놓은 문서를 사용하는 경우, HTML과 CSS를 받아 컴포넌트 단위로 재배치해야 하며 유지 보수가 지저분할 수 있음
- 컴포넌트(JS)가 자주 리렌더링되는 인터렉티브한 개발 시에는 JS 내 CSS 코드를 매번 같이 파싱해야 하므로 성능 저하
- 사용법: 패키지 설치 후 .js 파일 내부에서 특정 문법 내에 일반 css 작성
Component.js
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
render(
<Wrapper>
<Title>
Hello World!
</Title>
</Wrapper>
);
2) Emotion
- Style in JS와 제공하는 기능이 똑같음
- SSR, Media Queries, Theming Support 등
- 둘다 sass문법을 사용
4. Atomic CSS
: 미리 정의된 className을 조합하여 스타일링하는 방식
- 동의어 : Functional CSS, Utility-first
1) TailwindCSS
- Zero-runtime
- runtime에 css를 생성하지 않으면서 페이지를 더 빠르게 로드할 수 있음
- Javascript bundle에서 styles코드를 모두 실행되어야 페이지가 로드됨
- build타임에 css를 생성해야하기 때문에 webpack 설정을 해야 함
- 사용하지 않는 스타일을 결과물에서 제외하여 최적화하는 방법
- 방대한 class name을 가진 CSS 파일
- postcss(플러그인 제공), autoprefixer(CSS 파싱 & 접두사 추가) 필요
- 장점
- 모두 같은 specificity class로 구성되어 CSS의 관리와 네이밍을 위한 고민이 필요하지 않음
- 반복되는 속성을 가지는 시멘틱(코드 의미 중요시)한 네이밍이 아닌 utility-first 컨셉 : 클래스가 1 가지 작업만을 수행
- JSX와 CSS함께 작성하기에 CSS를 작성할 때 시간을 많이 절약할 수 있음
- 컴포넌트 생성과 관리가 쉬우며, 유지보수하기 편함
- 프로그래밍 언어와 같은 추상화 수준을 제공해 스타일을 빠르게 적용할 수 있어 코드의 길이가 줄고, 개발 시간이 절약됨
- 커스터마이징이 쉬워 원하는대로 디자인을 변경할 수 있음
- rem을 기본 단위로 제공 → 반응형 디자인 구현도 쉬워짐
- 단점
- inline-style을 사용하여 가독성과 유지보수 좋지 않음
- 클래스가 빌드 타임에 모두 생성되므로 동적 변수(JS 코드) 사용에 제약이 있음
- animation과 transition사용에도 제약이 있음
- 새로운 스타일을 사용하면 CSS 클래스를 생성하게 되어 CSS 파일 크기가 커지고 페이지 로드 시간도 늘어날 수 있음
- 의존성을 가져 더 많은 코드가 필요하게 됨
- tailwind를 사용할 수 없는 스타일인 경우에 별도의 css 파일을 생성해야 하기 때문에 일관성 있는 스타일링이 어려울 수 있음
팁
1. [Twin.Macro](https://github.com/ben-rogerson/twin.macro)를 활용하기 - Twin.Macro : Tailwindcss에 유연함을 추가해주는 라이브러리- 직접 값을 넣고 싶을 때 Tailwind CSS만으로는 힘들다. 이러한 부분을 해결
- 중간 매게체 역할로, styled-component 혹은 emotion과 함께 사용
예시 코드
import tw from "twin.macro";
function ExampleDiv({ width, height }) {
return (
<div
css={[
tw`bg-black`,
{
width: width,
height: height,
},
]}
>
안녕하세요
</div>
);
}
- 커스텀 플러그인 추가
코드
// scrollbar-hide.js
const plugin = require("tailwindcss/plugin");
const scrollbarHide = plugin(function ({ addUtilities }) {
addUtilities({
// . + 유틸리티 이름
".scrollbar-hide": {
"scrollbar-width": "none",
"-ms-overflow-style": "none",
"&::-webkit-scrollbar": {
display: "none",
},
},
});
});
module.exports = scrollbarHide;
// tailwind.config.js
...
plugins: [
require('./plugins/scrollbar-hide'),
]
- 위 코드를 추가하면
<div class="scrollbar-hide">처럼 한 줄로 복잡한 코드를 암축
-
다해상도 대응
// tailwind.config에서 커스텀 세팅 mobile: '360px' // @media (min-width: 360px) foldable: '523px' // @media (min-width: 523px) tablet: '768px' // @media (min-width: 768px) 'under-foldable': { max: '522px' } // @media (max-width: 522px) 'under-tablet': { max: '767px' } // @media (max-width: 767px) 'under-mobile': { max: '359px' } // @media (max-width: 359px) // 768px 이상에서만 overflow-hidden 적용, bg-black은 모든 경우에 적용 <div css={tw`tablet:overflow-hidden bg-black`} /> -
새로운 단위 정의하기
pxr이라는 새로운 단위를 추가pxr단위 : px을 작성하면 rem단위로 변환해주는 단위
// tailwind.config.js
const pxToRem = (px, base = 16) => `${px / base}rem`;
module.export = {
...
theme: {
...
spacing: {
...range(1, 100).reduce((acc, px) => {
acc[`${px}pxr`] = pxToRem(px);
return acc;
}, {}),
}
}
}
<div css={tw`w-16pxr h-16pxr`} />
// 16px에 대응하는 1rem으로 자동 변환
-
컬러 모드 지원
// tailwind.config.js module.exports = { darkMode: "class", // ... };-
HTML 트리 최상단(html,body 등)에 아래와 같은 클래스가 존재한다면, 다크모드로 인식하여
dark종단점이 동작하게 되고, 해당 클래스가 없다면 라이트모드로 인식되어dark종단점이 동작하지 않음<html class="dark">
-
- 사용 예시
<div css={tw`w-200pxr h-200pxr bg-black dark:bg-white`}>
2) Vanilla Extract : Zero-runtime StyleSheets in Typescript
-
TailwindCSS, Styled System의 Type-safe 버전
-
빌드 타임 때 TS파일 → CSS파일로 만듬
-
Sprinkles : 커스텀 utility class 설정 가능
그 외
1) Bootstrap
-
트위터에 의해 개발
-
수많은 CSS 프레임워크의 근간
-
가장 높은 사용률
-
미리 만들어진 컴포넌트를 제공
-
예시
<button class="btn btn-secondary dropdown-toggle" > // .. -
prefix를 이용하여 커스텀 가능
.btn-bd-primary { --bs-btn-font-weight: 600; --bs-btn-color: var(--bs-white); }
2) Material
- 구글에 의해 개발된 디자인 아키텍처
- 이를 기반으로 웹 디자인과 안드로이드 디자인, 현재는 Flutter를 위한 디자인에 사용
3) semantic-ui
-
자체 테마 변경 사항을 유지할 수 있는 Semantic UI 패키지 Gulp 빌드 도구
-
예시
<button class="ui labeled icon button"> <i class="pause icon"></i> Pause </button>
4) bulma
-
쉽게 반응형 웹 인터페이스를 만들 수 있게 도와주는 Framework
<article class="message"> <div class="message-header"> <p>Hello World</p> <button class="delete" aria-label="delete"></button> </div> <div class="message-body"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. <strong>Pellentesque risus mi</strong>, tempus quis placerat ut, porta nec nulla. Vestibulum rhoncus ac ex sit amet fringilla. Nullam gravida purus diam, et dictum <a>felis venenatis</a> efficitur. Aenean ac <em>eleifend lacus</em>, in mollis lectus. Donec sodales, arcu et sollicitudin porttitor, tortor urna tempor ligula, id porttitor mi magna a neque. Donec dui urna, vehicula et sem eget, facilisis sodales sem. </div> </article>
3. runtime vs zero-runtime
- runtime이 반드시 성능 저하를 초래하는 것은 아니며, 프로젝트 규모와 상황에 따라 달라질 수 있음
1. runtime
: runtime 때 동적으로 style 적용한다.
- props에 의해 style 변경 가능
- e.g.
styled-component,emotion - 리렌더링이 발생하면 css 다시 parsing
- critical CSS : 초기 렌더링 최적화를 위해 현재 화면에서 필요한 CSS만 효율적으로 먼저 로딩하는 방법을 고려해야 함
- styled-components
- 페이지에서 사용하는 css만 head에 style tag로 삽입
- styled-components
- colectStyles api를 통해 현재 페이지에서 사용되고 있는 스타일만 별도의 스타일 시트로 생성
- emotion
- extractCritical 제공 : styled-components와 비슷한 방식으로, 초기 페이지 렌더링에 필요한 critical css를 추출하고 이후 동적인 스타일은 runtime에 생성되는 방식
2. zero-runtime
- runtime에서의 동작이 없음. 즉 동적으로 스타일을 생성하지 않음
- babel plugin과 webpack loader를 통해 사용된 css코드를 추출해 정적인 스타일시트 생성
- e.g. tailwindcss, linaria, compiled
3. near-zero runtime
- e.g. stitches.js
4. CSS 개발 도구
1. postcss
- CSS후처리기, Javascript 플러그인을 통해 스타일을 변형하는 도구
기능
- 코드 가독성을 높여줌
- 최신 CSS 문법으로 변환해줌
- class명을 바꿔줘 Global style 문제 해결
2. autoPrefixer
- 자동으로 css속성 앞에
-mz-,-webkit-등의 접두사를 붙여주는 라이브러리
3. CSS 전처리기
1. SaSS(SCSS)
: CSS구문과 완전히 호환되도록 새로운 구문을 도입해 만든 SaSS의 모든 기능을 지원하는 CSS의 상위집합
- Next.js에서 지원 (설치 후 next.config.js 간단한 설정 후 사용 가능)