Tailwind에서 벗어나며 CSS 구조화 배우기
요약
본 글은 Tailwind CSS의 유틸리티 클래스 기반 방식에서 벗어나, 순수 CSS와 컴포넌트 중심의 구조화된 방식으로 웹사이트 스타일링을 재정비하는 과정을 다루고 있습니다. 주요 변경 사항으로는 전역 리셋(reset) 규칙의 수동 적용, 컴포넌트별 파일에 고유 클래스를 사용하여 스타일을 캡슐화하고 중첩 선택자를 활용하는 방법 등이 포함됩니다. 또한 색상 변수와 폰트 크기 역시 CSS 변수를 적극적으로 사용하며 관리합니다.
핵심 포인트
- Tailwind의 유틸리티 방식에서 벗어나, 순수 CSS를 이용한 구조적 스타일링으로 전환함.
- CSS는 컴포넌트별 파일에 고유 클래스를 사용하여 스타일을 캡슐화하고 중첩 선택자로 관리하는 것이 핵심임.
- 색상(colours)과 폰트 크기(font sizes)는 전역 CSS 변수(`:root`)를 정의하여 일관성을 유지함.
- 전체 레이아웃 간격 관리는 바깥쪽 컨테이너 컴포넌트가 책임지도록 원칙을 세우고, 반응형 디자인은 `auto-fit` 같은 그리드 기능을 활용해 유연하게 구현하려 함.
reset
- Tailwind의 preflight styles를
tailwind.css
에서 처음 약 200줄 복사해 사용함
- Tailwind reset에 오래 익숙해져 있었고, 모든 요소에
box-sizing: border-box
를 적용하는 규칙은 요소의 너비가 padding을 포함하게 만듦
* { box-sizing: border-box; }
html {line-height: 1.5;}
같은 다른 reset 규칙에도 무의식적으로 의존하고 있을 가능성이 있으며, 이런 규칙 없이 CSS를 쓰려면 큰 적응이 필요해 보임
components
- CSS 대부분은 Vue나 React 컴포넌트와 비슷한 방식으로
컴포넌트별 파일에 정리함 - 각 컴포넌트는 고유 클래스를 갖고, 한 컴포넌트의 CSS가 다른 컴포넌트의 CSS를 덮어쓰지 않도록 구성함
- 실제로 바꾸고 싶은 CSS의 약 80%가 컴포넌트 파일 안에 있어, 100줄짜리 컴포넌트를 편집할 때는 그 100줄만 생각하면 됨
- 예를 들어
.zine
컴포넌트는 다음과 같은 HTML을 가질 수 있음
<figure class="zine horizontal">
<img src="whatever.jpg">
</figure>
- CSS는 중첩 선택자로
.horizontal
, .vertical
, :hover
같은 상태를 컴포넌트 내부에 모음
.zine {
...
&.horizontal {
...
}
&.vertical {
...
}
&:hover {
...
}
}
- Web Components나
@scope
처럼 컴포넌트 간 간섭을 프로그램적으로 막지는 않았지만, 관례를 정해 지키는 것만으로도 크게 나아진 느낌을 줌
colours
colours.css
에는 필요할 때 사용할 수 있는 CSS 변수를 모아 둠
- 색상은 어렵고 이번 리팩터링에서 색상 사용을 다시 검토하고 싶지 않았기 때문에 기존 방식을 유지함
- 유일한 규칙은 사이트에서 쓰는 모든 색상을 이 파일에 나열하는 것임
:root {
--pink: #fea0c2;
--pink-light: #F9B9B9;
--red: #f91a55;
--orange: rgb(222, 117, 31);
...
}
font sizes
- Tailwind에서는
text-lg
, xl
, 2xl
처럼 크기 단계를 고르면 됐기 때문에 em
, px
, rem
중 무엇을 쓰는지 기억할 필요가 없었음
- 이를 바닐라 CSS에서도 유지하기 위해 Tailwind에서 가져온 크기 변수를 정의함
--size-xs: 0.75rem;
--line-height-xs: 1rem;
--size-sm: 0.875rem;
--line-height-sm: 1.25rem;
- 폰트 크기는 변수로 지정하며, Tailwind보다 조금 장황하지만 현재로서는 만족스러운 방식임
h3 {
font-size: var(--size-lg);
line-weight: var(--line-weight-lg);
}
utilities
- 여러 컴포넌트에서 반복되는 버튼 같은 요소는
utilities로 분류함 - 스크린리더 사용자에게만 보여야 하는 요소를 위한
.sr-only
같은 일부 유틸리티 클래스는 Tailwind에서 복사함
-
이 영역은 작게 유지하고, 변경할 때 조심하려 함
base
- “base” 스타일은 사이트 전체에 직접 적용하는 스타일임
- 사이트 전체에 많은 스타일을 강제할 만큼 확신이 없기 때문에 이 영역은 매우 작게 유지함
- 현재 괜찮다고 느끼는 규칙은
<section>
과 a
두 가지이며, <section>
규칙은 나중에 바뀔 수 있음
/* put a 950px column in the middle of each <section> */
section {
--inner-width: 950px;
padding: 3rem max(1rem, (100% - var(--inner-width))/2);
}
a {
color: var(--orange);
}
-
base 스타일은 처음에는 거의 비워두고, 공통으로 원하는 것을 찾을 때 컴포넌트에서 base로 옮기는
상향식 방식이 가장 쉬워 보임
spacing
- padding과 margin을 관리하는 방식은 아직 완전히 정해지지 않았음
- Tailwind를 쓸 때는 원하는 모양이 나올 때까지 padding과 margin을 여기저기 즉흥적으로 넣었고, 지금은 그보다 더 원칙적인 방식을 찾고 있음
- 현재는 가능한 한 바깥 레이아웃 컴포넌트가 간격을 책임지도록 하려 함
- 여러 자식을 가진
<section>
에서 자식 사이를 균일하게 띄우고 싶을 때는 다음 규칙을 사용할 수 있음
section > *+* {
margin-top: 1rem;
}
responsive design
- Tailwind에서는
md:text-xl
처럼 특정 크기 이상에서 text-xl
스타일을 적용하는 미디어 쿼리 기반 문법을 많이 사용했음
- 지금은 breakpoint를 많이 쓰지 않아도 되는 더 유연한 CSS grid 레이아웃을 만들려고 함
auto-fit
을 사용하면 큰 화면에서는 2열, 작은 화면에서는 1열을 자동으로 사용할 수 있음
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content));
justify-content: center;
build system
- 개발 중에는 별도의 빌드 시스템이 필요하지 않음
- CSS에는 내장
@import
문이 있어 파일을 나눠 가져올 수 있음
@import "reset.css";
@import "typography.css";
@import "colors.css";
.page {
h2 { ...}
}
- 프로덕션용으로 CSS 파일을 묶고 싶다면
esbuild
를 사용할 수 있음
esbuild style.css --bundle --loader:.svg=dataurl --loader:.woff2=file --outfile=/tmp/out.css
- 보통 CSS와 JS 빌드 시스템 사용을 피하지만,
esbuild
는 웹 표준 기반이고 정적 Go 바이너리이기 때문에 괜찮다고 봄
esbuild
에 대해서는 2021년에 esbuild와 Vue 관련 글을 쓴 적이 있음
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기