프론트엔드에서 CSS 를 적용하는 방법
1️⃣ Global CSS
Selector 원시 방식 : 외부에 정의된 CSS 파일을 통해 import 하여 HTML Selector 로 일일히 적용 방식
Inline 방식 : <div style={**{ borderColor: ‘red’, … }**} />
: 객체라 React 리렌더 성능 이슈
= React 에서 style 내 객체가 매 렌더링마다 다르게 인식되어 매번 DOM 계산을 통한 성능 저하 발생
토이 프로젝트나 극강의 생산성을 위한 경우를 제외하고 잘 쓰지않는 방법
- 선택자 충돌을 막기위해 BEM(Block Element Modifier) 사용
- 선택자 충돌이 혹여나 발생한다면
!important
를 통해 특정 선택자의 우선순위를 강하게 주장
- 하나의 Global CSS 가 모든 페이지의 CSS 를 관할하기때문에 번들사이즈가 커도 너무 큼
2️⃣ CSS Modules
현대 방법 (적은 선호) - Global CSS 는 단 하나의 CSS 파일이라면, Modules 는 각 페이지마다의 CSS 파일
- 선택자 충돌이 발생하지 않는다 (No Collisions) - 각 페이지마다 CSS 가 로컬 Scope 를 갖기때문
- Next.js 사용 시 해당 컴포넌트 혹은 페이지가
import
하는 CSS 를 알 수 있어 Code Splitting 가능
composes
문법을 통해 타 CSS Modules 의 선택자 정의를 가져와 확장할 수 있다.
- 하지만, 여전히 No Programmatic Features (Loop, Mixin 등과 같은 확장 문법들 사용 불가능)
3️⃣ CSS Preprocessor
현대 방법 (적은 선호) - 컴파일러를 통해 SCSS, SASS, LESS 등의 CSS 확장 문법지원 언어를 CSS 로 컴파일
- Next.js 사용한다면 SASS 컴파일러를
npm
으로 설치후 .css
확장자 파일을 .scss
로 변환만 하면됨
- 모든 Programmatic Features (Loop, Mixin 등과 같은 확장 문법) 모두 훌륭하지만
- 새로운 언어를 배워야한다는 점과, JS 로직과 완전히 분리되어있기에 유저 인터랙션에 따른 조작이 힘듦
4️⃣ CSS-in-JS
Selector 없이 JS 내 CSS 사용 : styled.div**
border-color: red; **
(@Media 등 CSS 문법)
현대 방법 (큰 선호) - JS 로직을 그대로 사용하고, CSS 문법을 그대로 사용할 수 있어서 양측의 장점을 다 가짐
- Styled Components, Emotion 등이 존재하나 현재 Emotion 이 표준 (MUI 내 선택 및 사용, SSR 최적)
- 유저 인터렉션에 따라 JS 로직을 통해 동적 CSS 적용이 가능하고 (Dynamic Styles)
- CSS 의 부족한 No Programmatic Features 단점을 다양한 JS 의 Programmatic Features 로 보완
- 자연스럽게 CSS 추가 파일 생성없이 JS 파일 안에 CSS 를 정의하다보니 자연스럽게 Scoped Styles
- Next.js 사용한다면 자체 제공하는 Styled JSX 라는 CSS-in-JS 솔루션 사용 가능
5️⃣ Tailwind CSS (CSS Framework 로 분류)
Selector 원시 방식 : HTML 혹은 React Component(JSX) 내 CSS 유틸리티 클래스 바로 명시
현대 방법 (큰 선호) - 유틸리티 클래스 라이브러리. 미리 CSS 정의된 선택자에 해당하는 클래스명을 조합해 개발
- 참고로 Tailwind CSS 를 CSS Framework 로 설명하기는하나 후술할것과는 조금 좁은 의미의 프레임워크
- 어떤 프론트엔드 개발에서든 추가적인 설치 및 설정과 툴 사용을 요구한다는 단점이 있지만
- CSS 를 직접 작성하는것보다 CSS 의미론적인 유틸리티 클래스를 사용하는게 직관적이고 개발이 빠름
- IDE IntelliSence 가 자동으로 어떤 클래스를 사용하면 되는지, 자동완성 및 코드 추천을 해주기 때문
- 사용한 클래스를 제외하고 모든 미사용 유틸리티 클래스를 지우고(Purge) 번들링하여 번들 사이즈 축소
- 모든 사람이 이 방식을 좋아하는건 아니다 HTML 이 더러워진다는 단점도 분명하고
- 미리 만들어진 Component 를 제공하지 않기때문에 필요한 컴포넌트들을 직접 만들어 써야함
6️⃣ UI Framework
현대 방법 (큰 선호) - Bootstrap 자체 제작 컴포넌트와 CSS 디자인 시스템을 함께 제공
- Pre-built Component 미리 (디자인 시스템으로) 자체적으로 제작되어진 컴포넌트를 제공
- 자체 디자인 시스템을 기반으로 만들어졌기때문에, 디자인 시스템 내 변수만 바꾸면 쉽게 테마 제작 가능
- 생각보다 Pre-built Component 를 그대로 사용할일은 없고, Wrapper Component 를 만들어야함
- 사용하지 않는 Pre-built Component 들과 CSS 정의들을 모두 번들링하기에 번들 사이즈가 너무 큼
7️⃣ Component Library
현재 방법 (큰 선호) - Mantine, Ant, Material Design, Chakra UI, Chadcn 많이 들어본것들이 이에 해당
- 자체 제작 컴포넌트를 제공하긴하는데, 컴포넌트 제공에 주안점을 두고 CSS 는 최대한 무색무취로 제공
- 개발자가 자체적으로 원하는 디자인을 적용하여 커스터마이징하여 사용하기 수월
CSS Preprocessor 사용 이유 및 종류
CSS Preprocessor = Bundler + Transpiler
앞서 JS 를 통한 DOM 조작의 개발 편의성 및 성능에 문제가 있어서 라이브러리나 프레임워크가 나온것처럼
CSS 도 개발 편의성을 위해 CSS Preprocessor 가 등장
- CSS 도 JS 과 마찬가지로 파일 개수가 너무 많음 ⇒ 다양한 파일 조직가능
- CSS 개발 시 유용한 기능들이 진짜 많이 없음 ⇒ Enhanced CSS (CSS 확장 기능 사용)
CSS Preprocessor 는 다양하고 편리한 CSS 확장 문법도 제공해주고, 번들링을 통해 파일 개수도 줄여줌
- 유명한 CSS Preprocessor 중 SASS 의 예를 들면 트랜스파일링 + 번들링을 통해 최종 CSS 로 변환됨

CSS Preprocessor / CSS Framework / UI Framework 구별
- CSS Preprocessor : SASS, SCSS
- CSS Framework : Tailwind CSS (유틸리티 클래스 기반)
- CSS 활용을 위한 방법론 및 디자인 시스템 제공
- UI Framework : Tailwind, Material UI, Chakra UI, Shadcn/ui
- 디자인 시스템 제공 및 UI 컴포넌트 제공
- 이에 따라 UI 컴포넌트를 직접 HTML 태그를 확장하여 만들지 않아도 되고
- 간단하게 디자인 시스템을 구축하여 일관된 Look & Feel 제공 가능
- 참고 : 그렇기 때문에 CSS Framework 와 UI Framework 를 합쳐 사용하지 않음
- 피치못할 상황이 아니라면 Tailwind CSS + Material UI 하지 말것
- 디자인 시스템 충돌 발생 | 물론 그렇게 사용해야할 수 밖에 없을시 공식 문서에서 방법을 제공

JS 프론트엔드 프레임워크 / CSS Framework 각 역할 정리
- JS 를 통한 DOM 조작을 풍부하게 → Javascript Framework (번들링 + 컴파일/트랜스파일 + 렌더링)
- CSS 설정을 풍부하게 → CSS Preprocessor (번들링 + 트랜스파일)

Rendering Pattern : 웹 프론트엔드 페이지 제공 방법


- SSG (서버가 페이지 제공) : (컴파일 타임에) 미리 렌더링된 페이지 페이지를 반환 = Generation
- SSR (서버가 페이지 제공) : (런타임에) 요청이 올때마다 렌더링한 페이지를 반환 = Rendering
- CSR (브라우저가 페이지 제공) : 매 요청이 올때마다 렌더링한 페이지를 반환 = Rendering
SSG
- 실제 사례 = 기술 블로그처럼 한번 글(페이지)을 작성해놓고 그걸 계속 재사용할 때
- 비실시간
- SEO 가능 = 서버가 페이지를 제공하기 때문
- 로딩속도 많이 빠름

SSR
- 실제 사례 = 쿠팡 커머스 서비스 내 상품 상세 페이지에는 실시간으로 가격변동이 잘 적용되어있어야함
- 실시간성
- SEO 가능 = 서버가 페이지를 제공하기 때문
- 로딩속도 적당히 빠름
- 바로바로 요청할때마다의 실시간 데이터가 반영된 최신 페이지를 볼 수 있음

CSR
- 앱과 같이 부드러운 페이지 전환 (앞선 SSR, SSG 는 새로운 페이지를 가져오면 빈 하얀색 화면/끊김)
- 실시간성
- SEO 불가
- 초기 로딩속도 느림(앱 다운로드 개념) + 이후 로딩속도 겁나 빠름

Static Websites
정적 페이지를 반환하는 웹 서버(WS) 활용 : Nginx, Apache, S3
가장 초기의 웹 페이지 형태 : 초창기 홈페이지는 같이 한번 만들면 거의 변경될 일이 없었음

- 미리 만들어진 웹 페이지인 정적 웹 페이지 를 요청에 따라 반환
- 1000 명의 유저 정보 페이지 = 1000 개의 유저 정보 페이지
✨ 특징
- 서버 불필요 (S3 같은 별개 저장소 사용 시) = 기술 블로그 같은 호스팅 유용
- 서버가 반환하고자하는 모든 정적 웹 페이지를 갖고있어야함
- 웹 페이지 버전 변경을 하려면, 매번 파일을 변경해줘야하여 번거로움
- 서버가 가지고 있는 정적 웹 페이지를 반환만 하면 되기때문에 매우 빠른 웹 페이지 반환 속도
- 구글과 같은 검색엔진 최적화(SEO, Search Engine Optimization)에 유리
MPA(Multi-Page) = SSR(Server-Side Rendering)
동적 페이지를 반환하는 웹 어플리케이션 서버(WAS) 활용 : Tomcat (Spring Boot + Thymeleaf)
쇼핑몰과 같이 실시간성이 중요한 웹 페이지 형태 : 검색 필터에 따라 다른 결과 및 가격 변동에 예민
- MPA 등장 배경 : 서버가 제공하려는 모든 정적 페이지를 저장하려니, 너무 많은 용량이 필요


- 서버는 요청에 따라 그때그때 동적 웹 페이지 를 만들어 반환 : 반복되는 템플릿과 실시간 정보를 분리
- 1000 명의 유저 정보 페이지 = 1 개의 유저 정보 페이지 템플릿 + 1000명 유저 정보 데이터베이스
✨ 특징
- 서버 필요
- 서버가 동적 웹 페이지를 생성하여 반환하기 때문에, 반환하려는 모든 웹 페이지를 갖고있을 필요 X
- 웹 페이지 만들고, 유저가 보기까지 시간이 걸릴 수 있다.
- 서버가 생성해서 반환하기에 웹 페이지 반환 속도는 DB 조회 속도, 웹 페이지 생성 속도에 의존
- 웹 서버의 CPU, 메모리 자원이 사용되기 때문에 AWS 같은 클라우드 사용 시 비용 부담
- 심화 : 비용 감소를 위한 Serverless 적용
- 구글과 같은 검색엔진 최적화(SEO, Search Engine Optimization)가 가능
SPA(Single-Page) = CSR(Client-Side Rendering)
웹 브라우저 내 자바스크립트 활용해 동적 페이지 생성 + 자바스크립트 반환을 위한 웹 서버 or 저장소(S3)
모바일 앱과 같이 실시간 유저 인터페이스가 중요한 웹 페이지 : 페이지 이동이나 버튼에 따른 동작 부드러움
- SPA 등장 배경 : Fast Route Transition (모바일 앱과 유사한 화면 전환 및 사용성) ⇒ SPA Route


- 웹 브라우저는 요청에 따라 그때그때 동적 웹 페이지 를 만들어 반환 : 모든 화면 전환 모두 웹 브라우저에서
- 모바일 앱과 같은 최적의 사용성을 유저에게 제공 : “웹 브라우저 위에서의 작은 모바일 앱”
- 출장 뷔페 = CSR :
그러니 Bundled JS 용량이 크지 …
✨ 특징
- 서버 불필요 (S3 같은 별개 저장소 사용 시) = 간단한 졸업 작품이나 포트폴리오 같은 호스팅 유용
- 서버 불필요하다는건 빈 HTML + CSS + JS 에 해당, 데이터 반환을 위한 API 서버는 필요
- 웹 브라우저가 동적 웹 페이지를 생성하여 반환하기 때문에, 웹 페이지 전환 시 깜빡임이 존재하지 X
- 유저에게 최적의 사용성(UX)을 제공하려다보니 Bundled JS 크기가 너무 크다 : Initial Loading
- 구글과 같은 검색엔진 최적화(SEO, Search Engine Optimization)가 불가능
- 웹 크롤러가 웹 페이지를 수집할 수 없음
- 어떤 페이지가 있는지 클라이언트가 렌더링하지않는 한 알 수 없음 : 웹 크롤러는 렌더링 못함
SSR(Server-Side Rendering) with Hydration = MPA + SPA
동적 페이지를 반환하는 웹 어플리케이션 서버 활용 + 웹 브라우저 내 자바스크립트 활용해 동적 페이지 생성
Next.js, Nuxt.js, SveltKit 과 같은 모든 종류의 메타 프레임워크 Meta Framework 가 제공하는 기능
- SSR 등장 배경 : CSR 의 Initial Loading 문제와 SEO 불가능한 단점 모두를 보완하기 위해
- SSR (Server-Side Rendering) ⇒ MPA
- with Hydration ⇒ SPA

MPA(Multi-Page Application) = SSR(Server-Side Rendering) 특징과 동일
- 서버는 요청에 따라 그때그때 동적 웹 페이지 를 만들어 반환 : 반복되는 템플릿과 실시간 정보를 분리
- 1000 명의 유저 정보 페이지 = 1 개의 유저 정보 페이지 템플릿 + 1000명 유저 정보 데이터베이스
+ 여기에 CSR 의 장점을 누릴 수 있도록 Hydration 이 추가된 것
SSG(Static Site Generation) with Hydration
React 같은 프레임워크로 개발 및 빌드한 정적 페이지를 반환하는 웹 서버 활용 : Nginx, Apache, S3
웹 프론트엔드 프레임워크(React, Vue 등)를 통해 CSR 개발하듯이 개발한 뒤 빌드하면 정적 페이지 생성
- SSG 등장 배경 : SEO 개선을 위해서 페이지 로딩 속도를 극단적으로 줄일 필요
튜닝의 끝은 순정
- HTML, JS, CSS 를 직접 생성하는 Static Websites 과 달리, SSG 는 빌드(Prerender)로 생성

Static Websites 특징과 동일
- 미리 만들어진 웹 페이지인 정적 웹 페이지 를 요청에 따라 반환
- 1000 명의 유저 정보 페이지 = 1000 개의 유저 정보 페이지
+ 여기에 CSR 의 장점을 누릴 수 있도록 Hydration 이 추가된것
✨ 특징 ← Static Websites 특징과 동일
-
서버 불필요 (S3 같은 별개 저장소 사용 시) = 기술 블로그 같은 호스팅 유용
-
서버가 반환하고자하는 모든 정적 웹 페이지를 갖고있어야함
-
웹 페이지 버전 변경 시, 개발 → 빌드 과정을 거치면되어 비교적 6.1. Static Websites 보다 간편
-
서버가 가지고 있는 정적 웹 페이지를 반환만 하면 되기때문에 매우 빠른 웹 페이지 반환 속도
-
구글과 같은 검색엔진 최적화(SEO, Search Engine Optimization)에 유리
➕ 하이드레이션 Hydration 을 활용하여, 여전히 모바일 앱과 유사한 사용성 제공 가능 !
웹 브라우저가 동적 웹 페이지를 생성하여 반환하기 때문에, 웹 페이지 전환 시 깜빡임 존재 X
Hydration = SSG, SSR 장점 위에 CSR 장점 얹기
1️⃣ 하나의 온전한 페이지를 유저에게 보여주는 방법은 세가지
- SSG : 이미 만들어져있는 웹 페이지를 웹 서버가 갖고, 바로 웹 브라우저에게 반환하여 유저에게 보여주거나
- SSR : 웹 서버가 열심히 온전한 페이지를 만들어서 웹 브라우저가 그걸 받아와 유저에게 보여주거나
- CSR : 웹 브라우저가 열심히 빈 페이지를 온전한 페이지로 만들어서 유저에게 보여주는 것
2️⃣ 이 각각의 세가지 방법들은 각자 아래와 같은 장단점을 갖고 있는데
- SSG : 이미 만들어져있는 웹 페이지를 반환해주니 속도는 제일 빠른데, 웹 페이지의 실시간성이 위배
- SSR : 실시간성을 취하나, 웹 서버가 웹 페이지를 다 만드는데까지 너무 많은 시간이 걸림
- CSR : 페이지 전환이나 버튼에 따른 동작들이 너무 부드럽지만, 그걸 위한 Bundled JS 가 너무 무거움
3️⃣ 쉽게 말하자면 하이드레이션 Hydration 은 SSG, SSR 장점 위에 CSR 장점을 얹기 위한 방법
- SSG : 웹 페이지 내 비실시간성 요소들은 미리 준비하여 속도가 제일 빠르게 반환
- SSR : 실시간성이 필요한 웹 페이지 내 부분은 웹 서버로부터 요청이 들어오자마자 만들어 반환
- CSR : 모바일 앱과 같은 사용성을 제공하면 좋은 일부 요소들은 CSR 로 렌더링하여 Bundled JS 경량화
Hydration 적용 시 JS 가 늦게 로드되기 때문에 짧은 시간동안 유저 사용성에 관련된 버튼 등이 동작되지 않음
ISR(Incremental Static Regeneration)
React 같은 프레임워크로 개발 및 빌드한 정적 페이지를 주기적 갱신 / 반환하는 웹 어플리케이션 서버 활용
데이터베이스나 API 를 사용한 SSG 인 경우, 근원 정보가 바뀌었을때 빌드밖에 갱신할 방법이 없음
- ISR 등장 배경 : SEO 개선을 위해 SSG 사용했으나 실시간 페이지 업데이트를 위해 너무 잦은 빌드 필요
- SSG 를 위해선 웹 서버로 충분하지만,
- 주기적으로 근원 정보 호출을 통해 정적 페이지 리빌드를 위해선 웹 어플리케이션 서버 필요
SSG(Static Site Generation) 특징과 동일
- 미리 만들어진 웹 페이지인 정적 웹 페이지 를 요청에 따라 반환
- 1000 명의 유저 정보 페이지 = 1000 개의 유저 정보 페이지
+ 여기에 CSR 의 장점을 누릴 수 있도록 Hydration 이 추가된것
++ 여기에 Revalidate 옵션으로 SSG 로 빌드했던 웹 페이지가 일정 시간이 지나면 리빌드되어 준실시간성 보장
✨ 특징 ← SSG(Static Site Generation) 와 서버 필요 여부 제외하고 동일
- 서버 필요 (SSG 임에도 불구하고) = 기술 블로그 같은 호스팅이 매우 어려움
- 서버가 반환하고자하는 모든 정적 웹 페이지를 갖고있어야함
- 웹 페이지 버전 변경 시, 개발 → 빌드 과정을 거치면되어 비교적 6.1. Static Websites 보다 간편
- 서버가 가지고 있는 정적 웹 페이지를 반환만 하면 되기때문에 매우 빠른 웹 페이지 반환 속도
- 구글과 같은 검색엔진 최적화(SEO, Search Engine Optimization)에 유리
- 정적 웹 페이지이지만 일정 주기에 따라 WAS 가 웹 페이지를 리빌드하여 준실시간성이 보장
➕ 하이드레이션 Hydration** 을 활용하여, 여전히 모바일 앱과 유사한 사용성 제공 가능 !
웹 브라우저가 동적 웹 페이지를 생성하여 반환하기 때문에, 웹 페이지 전환 시 깜빡임 존재 X