Tailwind에서 벗어나기, 그리고 나의 CSS 구조화 학습하기
요약
작성자는 Tailwind CSS에서 벗어나 의미론적 HTML과 바닐라 CSS로 마이그레이션하며 얻은 CSS 구조화 학습 경험을 공유합니다. Tailwind가 제공하던 리셋 스타일, 컬러 팔레트, 폰트 스케일 등의 시스템을 바닐라 CSS 환경에서 어떻게 재구축하고 관리할 수 있는지에 대한 통찰을 담고 있습니다.
핵심 포인트
- Tailwind CSS는 리셋, 컬러, 폰트 등 체계적인 디자인 시스템을 제공하며, 이를 바닐라 CSS로 모방할 수 있음
- 효율적인 CSS 관리를 위해서는 레이아웃, 폰트, 색상, 공통 컴포넌트 등 각 요소에 대한 가이드라인이 필수적임
- Tailwind의 'preflight styles'와 같은 리셋 스타일을 활용하여 일관된 기본 스타일을 유지하는 것이 중요함
- CSS를 Vue나 React 컴포넌트와 유사한 방식으로 조직화하여 관리하는 접근 방식이 유용함
안녕하세요! 8년 전, 저는 Tailwind를 발견하고 설레는 마음으로 글을 썼습니다.
당시 저는 제 CSS 코드를 어떻게 구조화해야 할지 전혀 몰랐고, 완전히 혼란스러운 상태와 Tailwind 중 하나를 선택해야 한다면 Tailwind를 선택할 수 있어 정말 행복했습니다. Tailwind는 제가 수많은 작은 사이트들을 만드는 데 큰 도움을 주었습니다!
지난 일주일 정도 저는 몇몇 사이트들을 Tailwind에서 벗어나 더 의미론적인 HTML (semantic HTML) + 바닐라 CSS (vanilla CSS)로 마이그레이션(migrating)하는 데 시간을 보냈는데, 정말 즐겁고 흥미로웠습니다. 그래서 제가 배운 몇 가지 내용들을 공유하고자 합니다!
평소와 마찬가지로 저는 전업 프론트엔드 개발자(frontend developer)가 아니기에, 저의 모든 CSS 학습은 수년에 걸쳐 간헐적으로 이루어졌습니다.
CSS 구조화를 고민하기 시작했을 때, 처음에는 겁이 났습니다. 저는 CSS 구조를 잡는 데 그리 능숙하지 않거든요! 하지만 CSS를 어떻게 구조화하는지에 대한 블로그 포스트들(예: A whole cascade of layers 또는 How I write CSS in 2024)을 읽기 시작하면서 몇 가지 사실을 깨달았습니다:
- 모든 CSS 코드베이스(code base)에는 다양한 요소들이 작동하고 있습니다 (레이아웃(layouts)! 폰트(fonts)! 색상(colours)! 공통 컴포넌트(common components)!).
- 이러한 각각의 요소들을 관리하기 위한 시스템이나 가이드라인을 갖추는 것은 매우 유용하며, 그렇지 않으면 상황은 혼돈에 빠지게 됩니다.
- Tailwind는 이러한 요소 중 일부에 대한 시스템을 갖추고 있으며, 저는 이미 그 시스템들을 알고 있습니다! 어쩌면 제가 좋아하는 그 시스템들을 모방할 수 있을지도 모릅니다!
예를 들어, Tailwind에는 다음과 같은 것들이 있습니다:
- 리셋 스타일시트 (reset stylesheet)
- 컬러 팔레트 (colour palette)
- 폰트 스케일 (font scale)
저는 제 CSS 코드베이스의 몇 가지 측면과, 각 측면에 대해 코드베이스에 어떤 종류의 규칙을 적용하고 싶은지에 대한 지금까지의 생각들을 이야기해 보려 합니다. 그중 일부는 Tailwind에서 복사한 것이고 일부는 그렇지 않습니다.
- 리셋 (reset)
- 컴포넌트 (components)
- 색상 (colours)
- 폰트 크기 (font sizes)
- 유틸리티 클래스 (utility classes)
- 베이스 (the base)
- 간격 (spacing)
- 반응형 디자인 (responsive design)
- 빌드 시스템 (the build system)
저는 단순히 Tailwind의 "preflight styles"를 복사했습니다.
tailwind.css 파일로 들어가서
처음 200줄 정도를 복사하는 방식으로 말이죠.
저는 시간이 흐르면서 Tailwind의 CSS 리셋과 일종의 관계가 형성되었다는 것을 깨달았습니다.
예를 들어, Tailwind는 모든 요소에
box-sizing: border-box를 설정합니다
(이는 요소의 너비(width)에 패딩(padding)이 포함된다는 것을 의미합니다):
* { box-sizing: border-box; }
이러한 설정들 없이 CSS를 작성하는 방식으로 전환하는 것은 저에게 정말 큰 적응 과정이 될 것 같습니다. 그리고 Tailwind 리셋(reset)에는 html {line-height: 1.5;}와 같이 제가 무의식적으로 익숙해져서 존재조차 인지하지 못하고 있는 다른 많은 것들이 분명히 있을 것입니다.
다음 부분은 CSS의 핵심입니다!
여기에서의 아이디어는 Vue나 React 컴포넌트(component)와 정신적으로 유사한 방식으로 CSS를 "컴포넌트"별로 조직화하는 것입니다. (비록 사이트에 자바스크립트(Javascript)가 전혀 없을 수도 있지만 말입니다)
기본적인 아이디어는 다음과 같습니다:
- 각 "컴포넌트"는 고유한 클래스(class)를 가집니다.
- 한 컴포넌트의 CSS는 다른 어떤 컴포넌트의 CSS도 절대 덮어쓰지(override) 않습니다.
- 각 컴포넌트는 자신만의 CSS 파일을 가집니다.
따라서 한 컴포넌트의 CSS를 수정한다고 해서 다른 컴포넌트의 무언가가 알 수 없는 이유로 망가지는 일은 없을 것입니다. 그리고 실제로 제가 변경하고 싶어 할 CSS의 약 80%는 다양한 컴포넌트 파일에 들어있을 것이므로, 만약 제가 100줄짜리 컴포넌트를 편집하고 있다면 저는 그 100줄에 대해서만 생각하면 됩니다. 이는 제가 사고하기에 훨씬 쉽습니다.
예를 들어, 이 HTML은 .zine "컴포넌트"일 수 있습니다.
<figure class="zine horizontal">
<img src="whatever.jpg">
</figure>
그리고 CSS는 중첩 선택자(nested selectors)를 사용하여 다음과 같은 모습일 것입니다:
.zine {
...
&.horizontal {
...
컴포넌트들이 서로 간섭하지 않도록 보장하는 프로그래밍적인 방식(웹 컴포넌트(web components)나 @scope 등)을 사용하지는 않았지만, 단지 규칙(convention)을 정하고 최선을 다하는 것만으로도 이미 큰 개선처럼 느껴집니다.
다음: 사이트 전반에 걸쳐 어느 정도의 일관성을 유지하고 이러한 컴포넌트들이 서로 조화를 이루게 하기 위한 규칙들!
colours.css에는 필요에 따라 사용할 수 있는 다음과 같은 변수(variables)들이 많이 들어있습니다.
색상은 정말 어려운 작업이라 이번 리팩터링(refactor)에서 색상 사용 방식을 다시 검토하고 싶지 않았기에, 이 부분은 그대로 두었습니다.
여기서 제가 강제하려고 노력하는 유일한 가이드라인은 사이트에서 사용되는 모든 색상이 이 파일에 나열되어 있어야 한다는 점입니다.
:root {
--pink: #fea0c2;
--pink-light: #F9B9B9;
...
Tailwind에서 좋았던 점 중 하나는 폰트 크기 (font size)를 설정하고 싶을 때, 그저 "음, 텍txt를 크게 만들고 싶어"라고 생각한 뒤 text-lg라고 적기만 하면 끝난다는 것이었습니다! 만약 충분히 크지 않다면 대신 xl이나 2xl을 사용하면 되었죠. em, px, 또는 rem 중 무엇을 사용하고 있는지 기억하려고 애쓸 필요도 없었습니다.
그래서 저는 Tailwind에서 가져온 다음과 같은 변수들을 대량으로 정의했습니다:
--size-xs: 0.75rem;
--line-height-xs: 1rem;
--size-sm: 0.875rem;
...
그다음 폰트 크기를 설정하고 싶다면 다음과 같이 할 수 있습니다. Tailwind보다는 조금 더 장황하지만(verbose), 현재로서는 만족스럽습니다.
h3 {
font-size: var(--size-lg);
line-height: var(--line-height-lg);
...
여러 다양한 컴포넌트에서 나타나는 버튼과 같은 것들이 있습니다. 저는 이것들을 "유틸리티 (utilities)"라고 부릅니다.
저는 Tailwind에서 몇 가지 유틸리티 클래스(예: 스크린 리더 (screenreader) 사용자에게만 보여야 하는 항목을 위한 .sr-only)를 복사해 왔습니다.
이 섹션은 꽤 작으며, 저는 여기서 변경 사항을 만드는 데 신중하려고 노력합니다.
"base" 스타일은 제가 직접 선택한, 사이트 전체에 적용되는 스타일입니다. 사이트 전체에 너무 많은 스타일을 강제할 만큼의 확신이 없기 때문에 이 섹션을 매우 작게 유지해야 합니다. 현재로서는 이 두 가지만 괜찮다고 느끼며, <section> 관련 설정은 변경할 수도 있습니다:
/* 각 <section>의 중앙에 950px 컬럼을 배치합니다 */
section {
--inner-width: 950px;
...
base 스타일의 경우, 일종의 상향식 (bottom up) 방식으로 작업하는 것이 저에게 가장 쉬울 것 같습니다. 즉, base 스타일에는 거의 아무것도 없는 상태에서 시작하여, 공통적으로 원하는 요소들을 식별함에 따라 컴포넌트(components)에 있는 일부 스타일을 base 스타일로 옮기는 방식입니다.
패딩 (padding)과 마진 (margin)을 관리하는 접근 방식은 아직 완전히 정립하지 못했습니다. 하지만 제가 원하는 모습이 나올 때까지 아무 데나 패딩과 마진을 무작위로 집어넣었던 Tailwind 방식보다는 확실히 더 원칙적인 (principled) 방식을 취하려고 노력하고 있습니다.
현재 저는 가능한 한 외부 레이아웃 컴포넌트 (outer layout components)가 간격 (spacing)을 담당하도록 만드는 방향으로 작업하고 있습니다. 예를 들어, 자식 요소들 사이에 간격을 두고 싶은 여러 개의 자식을 가진 <section>이 있다면, 다음과 같이 자식 요소들 사이에 균등한 간격을 주기 위해 사용할 수 있습니다:
section > *+* {
margin-top: 1rem;
}
영감을 준 블로그 포스트들:
Tailwind에서 반응형 디자인 (responsive design)을 구현하던 방식은 많은 미디어 쿼리 (media queries)를 사용하는 것이었습니다. Tailwind에는 md:text-xl과 같은 문법이 있는데, 이는 "md 사이즈 이상에서 text-xl 스타일을 적용하라"는 의미입니다.
저는 지금 이와는 상당히 다른 시도를 하고 있는데, 바로 많은 중단점 (breakpoints)이 필요하지 않은 더 유연한 CSS 그리드 레이아웃 (CSS grid layouts)을 만드는 것입니다. 이는 어렵지만 그리드 (grid)로 무엇이 가능한지 배우는 과정은 정말 흥미로우며, Tailwind로는 불가능하다고 생각되는 부분의 좋은 예시이기도 합니다.
예를 들어, 저는 다음과 같이 큰 화면에서는 자동으로 2개의 열 (columns)을 사용하고 작은 화면에서는 1개의 열을 사용하도록 auto-fit을 사용하는 방법을 배우고 있습니다:
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content));
justify-content: center;
또한 저는 grid-template-areas를 많이 사용했는데, 이는 Tailwind에서는 사용할 수 없을 것 같은 놀라운 기능입니다.
영감:
- CSS Tricks의 미디어 쿼리 없는 반응형 그리드 레이아웃 (A responsive grid layout with no media queries)
개발 과정에서 저는 빌드 시스템 (build system)이 필요하지 않습니다. 이제 CSS에는 다음과 같은 내장 임포트 문 (built in import statements)이 있습니다:
@import "reset.css";
@import "typography.css";
@import "colors.css";
그리고 다음과 같은 내장 중첩 선택자 (built in nested selectors)도 있습니다:
.page {
h2 { ...}
}
원한다면, 프로덕션 (production)을 위해 CSS 파일을 번들링 (bundle)하도록 esbuild를 사용할 수 있습니다. 그 모습은 대략 다음과 같습니다.
esbuild style.css --bundle --loader:.svg=dataurl --loader:.woff2=file --outfile=/tmp/out.css
저는 보통 CSS와 JS 빌드 시스템을 사용하는 것을 피하지만, esbuild (2021년에 이곳에 대해 글을 쓴 적이 있습니다)를 사용하는 것은 괜찮습니다. 왜냐하면 이것은 웹 표준 (web standards)을 기반으로 하며 정적 Go 바이너리 (static Go binary)이기 때문입니다.
몇몇 사람들이 제가 왜 Tailwind에서 벗어나려 하는지 물었습니다. 기여한 몇 가지 요인은 다음과 같습니다:
- Tailwind는 2018년 이후로 빌드 시스템 (build system)에 훨씬 더 의존하게 되었습니다. 제 생각에는 빌드 시스템을 사용하지 않고 최신 버전의 Tailwind를 사용하는 것은 불가능(?)한 것 같습니다. 그래서 저는 수년 동안 Tailwind v2를 사용해 왔습니다. (litewind라는 것도 있는 것 같더군요)
- Tailwind를 빌드 시스템과 함께 사용해야 한다는 것은 항상 사실이었지만, 저는 실제로 그렇게 해본 적이 없습니다. 그래서 많은 프로젝트에 2.8MB 크기의
tailwind.min.css파일(gzip 압축 시 270K)을 포함하고 있으며, 이는 조금 우스꽝스럽게 느껴집니다. - 저는 Tailwind를 처음 사용하기 시작했을 때보다 CSS를 훨씬 더 잘 다루게 되었습니다.
- 궁극적으로 Tailwind는 제한적입니다. CSS에서 '이상한 일 (Weird Stuff)'을 하고 싶을 때, Tailwind로는 항상 가능한 것은 아닙니다. 그러한 제한 사항들은 매우 유용할 수 있지만 (이 포스트의 상당 부분은 제가 Tailwind의 제한 사항 중 일부를 재구현하는 것에 관한 것입니다!), 현 시점에서 저는 선택적으로 골라 사용할 수 있기를 원합니다.
- 결국 한 프로젝트 내에 바닐라 CSS (vanilla CSS)와 Tailwind를 혼합하여 사용하는 사이트들을 만들게 되었고, 이는 유지보수하기가 즐겁지 않았습니다.
- 더 의미론적인 HTML (semantic HTML)을 작성하는 것이 어떤 느낌일지 궁금해졌습니다.
이 과정을 진행하면서, 저는 사용하지는 않았지만 언젠가 배워보고 싶은 많은 CSS 기능들에 대해 알게 되었습니다:
@layer(A Whole Cascade of Layers에서 발췌)@scope- 컨테이너 쿼리 (container queries)
- 서브그리드 (subgrid)
저는 이 포스트에서 Tailwind를 사용하며 배운 점들에 대해 많이 이야기해 왔고, 그것은 모두 사실입니다.
하지만 저는 3년 전에 'Tailwind와 CSS의 여성성 (Tailwind and the Femininity of CSS)'이라는 포스트를 읽었고, 그것이 제 머릿속에 깊이 남았습니다. 솔직히 저는 아마도 그 포스트가 묘사하는 것과 약간 유사한 태도로 CSS를 시작했을 것입니다:
그들은 CSS가 단순하다고 들었기에, 그것이 쉽다고 가정합니다. 하지만 막상 사용하려고 하면 제대로 작동하지 않습니다. 그들은 자신이 똑똑하다는 것을 알고 있고, 이것은 쉬워야만 하기 때문에, 반드시 언어의 잘못일 것이라고 생각합니다.
하지만 지난 10년 동안 저는 기술로서의 CSS를 진심으로 사랑하고 존중하는 법을 배웠습니다.
그래서 저는 몇 년 전, "CSS는 어렵다"라는 말에 대해 CSS의 가치를 깎아내리는 대신, CSS를 하나의 기술로서 진지하게 받아들이고 더 잘 다루는 방식으로 대응하기로 결심했습니다. 그렇게 하자 모든 것이 바뀌었습니다. 제가 느꼈던 수많은 좌절감("중앙 정렬은 불가능해")이 이미 오래전에 CSS에서 해결되었다는 것을 배웠고, 또한 "중앙 정렬"이 의미하는 바가 항상 단순하지 않으며 이를 수행하는 다양한 방법이 존재하는 것이 당연하다는 사실을 깨달았습니다. CSS가 어려운 이유는 그것이 어려운 문제를 해결하고 있기 때문입니다!
저는 지난 10~15년 동안 구축된 새로운 CSS 기능들(이 포스트에서 언급한 것 중 일부도 있습니다!)과 그것들이 어떻게 CSS 사용을 더 쉽게 만드는지에 깊은 인상을 받았으며, CSS 기술을 향상시키기 위해 시간을 투자하는 것은 정말 멋진 경험이었습니다.
그리고 그 포스트는 Tailwind가 CSS 전문 지식의 가치를 떨어뜨리는 데 기여하고 있다는 느낌을 주었고, Tailwind가 개인적으로 저에게 유용한 도구였을지라도 저는 그런 흐름에 동참하고 싶지 않다는 생각을 들게 했습니다. 특히 인간의 전문성을 가치 있게 여기는 것이 그 어느 때보다 중요하게 느껴지는 LLM (대규모 언어 모델) 시대에는 더욱 그렇습니다.
저에게 영향을 준 Tailwind를 비판하는 또 다른 블로그 포스트도 있습니다:
wizardzines.com의 CSS를 처음으로 설계하고 작성해 준 Melody Starling 덕분에, 이 사이트의 멋지고 재미있는 모든 요소는 Melody 덕분입니다.
또한 이 작업을 하는 동안 CSS에 관한 수많은 놀라운 블로그 포스트들(CSS Tricks, Smashing Magazine 등)을 읽었습니다. 이 포스트 곳곳에 그중 일부를 링크하려고 노력했으며, CSS 커뮤니티의 사람들이 자신들의 실무 경험을 공유해 주는 것에 대해 진심으로 감사하게 생각합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN AI Posts의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기