메뉴
HN
Hacker News • 133일 전

테일윈드 유틸리티에서 벗어나 순수 CSS 구조화 배우기

IMP
6/10
핵심 요약

8년간 테일윈드를 사용해온 개발자가 여러 웹사이트를 시맨틱 HTML과 바닐라 CSS로 마이그레이션하며 얻은 인사이트를 공유합니다. CSS 리셋, 컴포넌트 분리, 색상·간격 등 레이아웃을 위한 일관된 시스템 구축의 중요성을 강조하며, 프레임워크 의존도를 줄이고 자체 CSS 아키텍처를 실험하는 실무자에게 유용한 참고자료입니다.

번역된 본문

안녕하세요! 8년 전, 저는 테일윈드(Tailwind)를 발견하고 흥분된 마음으로 글을 썼습니다. 그 당시에는 CSS 코드를 어떻게 구조화해야 할지 정말 몰랐고, 완전한 혼돈의 코드와 테일윈드 중에서 선택해야 했기에 테일윈드를 기꺼이 선택했습니다. 그 덕분에 많은 작은 사이트들을 만들 수 있었습니다!

지난 일주일 정도 몇 개의 사이트를 테일윈드에서 멀어지게 마이그레이션하고, 더 시맨틱(semantic)한 HTML과 순수 CSS(바닐라 CSS) 방향으로 옮겼습니다. 그 과정이 정말 재미있고 흥미로워서, 제가 배운 몇 가지를 공유하려 합니다! 평소처럼 저는 전업 프론트엔드 개발자가 아니며, 그동안 CSS 학습은 여러 해에 걸쳐 단편적으로 이뤄졌습니다.

테일윈드가 저에게 많은 것을 가르쳐 줬더군요 CSS 구조화를 고민하기 시작할 때 처음엔 겁먹었습니다. 제가 CSS 구조화에 별로 능숙하지 않았거든요! 그러나 CSS를 어떻게 구조화할지 다루는 블로그 글(예: ‘A whole cascade of layers’나 ‘How I write CSS in 2024’)을 읽다 보니 몇 가지를 깨달았습니다.

  • 모든 CSS 코드베이스에는 여러 가지 요소(레이아웃, 글꼴, 색상, 공통 컴포넌트 등)가 섞여 있습니다.
  • 이를 관리하기 위한 체계나 가이드라인이 있으면 매우 유용합니다. 그렇지 않으면 혼돈에 빠집니다.
  • 테일윈드에는 이 중 일부를 위한 체계가 이미 있고, 저는 그 체계들을 이미 알고 있습니다!
  • 내가 마음에 드는 체계를 모방해볼 수도 있겠다는 생각이 들었습니다.

예를 들어 테일윈드에는 다음이 있습니다:

  • 리셋 스타일시트(reset stylesheet)
  • 색상 팔레트(colour palette)
  • 글꼴 스케일(font scale)

제가 이야기하려는 체계들 CSS 코드베이스의 몇 가지 측면과, 각각에 제가 부여하고 싶은 규칙에 관해 지금까지의 생각을 공유하겠습니다. 일부는 테일윈드에서 가져왔고, 일부는 그렇지 않습니다.

  • 리셋(reset)
  • 컴포넌트(components)
  • 색상(colours)
  • 글꼴 크기(font sizes)
  • 유틸리티 클래스(utility classes)
  • 베이스 간격(the base spacing)
  • 반응형 디자인(responsive design)
  • 빌드 시스템(the build system)
  1. 리셋(reset) 저는 테일윈드의 “preflight styles”를 tailwind.css 파일에서 처음 200줄 정도를 복사해 그대로 가져왔습니다. 시간이 지나면서 테일윈드의 CSS 리셋과 관계가 형성되었음을 깨달았습니다. 예를 들어 테일윈드는 모든 요소에 box-sizing: border-box를 설정합니다(요소의 너비에 패딩이 포함되도록).
  • { box-sizing: border-box; }

이런 설정 없이 CSS를 작성하는 건 큰 적응이 필요할 것 같습니다. 테일윈드 리셋에는 html { line-height: 1.5; }처럼 무의식적으로 익숙해져 있어 존재조차 인식하지 못했던 다른 규칙들도 분명 많을 것입니다.

  1. 컴포넌트(components) 이 부분이 CSS의 대부분을 차지합니다! 핵심 아이디어는 CSS를 “컴포넌트” 단위로 조직화하는 것입니다. Vue나 React 컴포넌트와 정신적으로 유사한 방식이에요(사이트에 자바스크립트가 전혀 없더라도 상관없습니다).

기본적으로:

  • 각 “컴포넌트”는 고유한 클래스를 갖습니다.
  • 한 컴포넌트의 CSS는 다른 컴포넌트의 CSS를 결코 덮어쓰지 않습니다.
  • 각 컴포넌트는 자체 CSS 파일을 갖습니다.

이렇게 하면 한 컴포넌트의 CSS를 편집해도 다른 컴포넌트가 알 수 없게 망가지는 일이 없습니다. 실제로 변경하고 싶은 CSS의 약 80%가 여러 컴포넌트 파일에 있기 때문에, 100줄짜리 컴포넌트를 편집할 때 그 100줄만 생각하면 됩니다. 훨씬 더 생각하기 쉽습니다.

예를 들어 다음 HTML은 .zine “컴포넌트”일 수 있습니다:

그리고 CSS는 중첩 선택자(nested selectors)를 사용해 이렇게 작성할 수 있습니다:

.zine { ... &.horizontal { ... } &.vertical { ... } &:hover { ... } }

컴포넌트가 서로 간섭하지 않도록 보장하기 위해 웹 컴포넌트나 @scope 같은 프로그래밍적 장치를 사용하진 않았지만, 단순히 규약을 갖고 최선을 다하는 것만으로도 큰 개선이 느껴집니다.

다음은 사이트 전체에 걸쳐 일관성을 유지하고 이 컴포넌트들이 서로 조화를 이루도록 하는 규약입니다!

  1. 색상(colours) colours.css에는 필요에 따라 사용할 수 있는 여러 변수가 있습니다. 색상은 정말 어려운 주제라 이번 리팩토링에서는 색상 사용을 다시 고치고 싶지 않아서 그냥 두었습니다. 제가 따르는 유일한 가이드라인은...
원문 보기
원문 보기 (영어)
Hello! 8 years ago, I wrote excitedly about discovering Tailwind . At that time I really had no idea how to structure my CSS code and given the choice between a pile of complete chaos and Tailwind, I was really happy to choose Tailwind. It helped me make a lot of tiny sites! I spent the last week or so migrating a couple of sites away from Tailwind and towards more semantic HTML + vanilla CSS, and it was SO fun and SO interesting, so here are some things I learned! As usual I&rsquo;m not a full-time frontend developer and so all of my CSS learning has happened in fits and starts over many years. it turns out Tailwind taught me a lot When I started thinking about structuring CSS, I was intimidated at first: I&rsquo;m not very good at structuring my CSS! But then I started reading blog posts talking about how to structure CSS (like A whole cascade of layers or How I write CSS in 2024 ) and I realized a couple of things: Every CSS code base has a bunch of different things going on (layouts! fonts! colours! common components!) It&rsquo;s extremely useful to have systems or guidelines to manage each of those things, otherwise things descend into chaos Tailwind has systems for some of these, and I already know those systems! Maybe I can imitate the systems I like! For example, Tailwind has: a reset stylesheet a colour palette a font scale the systems I&rsquo;m going to talk about I&rsquo;m going to talk about a few aspects of my CSS codebase and my thoughts so far what kind of rules I want to impose on the codebase for each one. Some of them are copied from Tailwind and some aren&rsquo;t. reset components colours font sizes utility classes the base spacing responsive design the build system 1. reset I just copied Tailwind&rsquo;s &ldquo; preflight styles &rdquo; by going into tailwind.css and copying the first 200 lines or so. I noticed that I&rsquo;ve developed a relationship with Tailwind&rsquo;s CSS reset over time, for example Tailwind sets box-sizing: border-box on every element (which means that an element&rsquo;s width includes its padding): * { box-sizing: border-box; } I think it would be a real adjustment for me to switch to writing CSS without these, and I&rsquo;m sure there are lots of other things in the Tailwind reset (like html {line-height: 1.5;} ) that I&rsquo;m subconsciously used to and don&rsquo;t even realize are there. 2. components This next part is the bulk of the CSS! The idea here is to organize CSS by &ldquo;components&rdquo;, in a way that&rsquo;s spiritually related to Vue or React components. (though there might not actually be any Javascript at all in the site) Basically the idea is that: Each &ldquo;component&rdquo; has a unique class The CSS for one component never overrides the CSS for any other component Each component has its own CSS file So editing the CSS for one component won&rsquo;t mysteriously break something in another component. And probably like 80% of the CSS that I would actually want to change is in various component files, so if I&rsquo;m editing a 100-line component, I just have to think about those 100 lines. It&rsquo;s way easier for me to think about. For example, this HTML might be the .zine &ldquo;component&rdquo;. <figure class="zine horizontal"> <img src="whatever.jpg"> </figure> And the CSS looks something like this, using nested selectors: .zine { ... &.horizontal { ... } &.vertical { ... } &:hover { ... } } I haven&rsquo;t done anything programmatic (like web components or @scope ) that ensures that components won&rsquo;t interfere with each other, but just having a convention and trying my best already feels like a big improvement. Next: conventions to maintain some consistency across the site and keep these components in line with each other! 3. colours colours.css has a bunch of variables like this which I can use as necessary. Colour is really hard and I didn&rsquo;t want to revisit my use of colour in this refactor, so I left this alone. The only guideline I&rsquo;m trying to enforce here is that all colours used in the site are listed in this file. :root { --pink: #fea0c2; --pink-light: #F9B9B9; --red: #f91a55; --orange: rgb(222, 117, 31); ... } 4. font sizes One thing I appreciated about Tailwind was that if I wanted to set a font size, I could just think &ldquo;hm, I want the text to be big&rdquo;, write text-lg , and be done with it! And maybe if it&rsquo;s not big enough I&rsquo;d use xl or 2xl instead. No trying to remember whether I&rsquo;m using em or px or rem . So I defined a bunch of variables, taken from Tailwind, like this: --size-xs: 0.75rem; --line-height-xs: 1rem; --size-sm: 0.875rem; --line-height-sm: 1.25rem; Then if I want to set a font size, I can do it like this. It&rsquo;s a little more verbose than Tailwind but I&rsquo;m happy with it for now. h3 { font-size: var(--size-lg); line-height: var(--line-height-lg); } 5. utilities There are some things like buttons that appear in many different components. I&rsquo;m calling these &ldquo;utilities&rdquo;. I copied some utility classes from Tailwind (like .sr-only for things that should only appear for screenreader users). This section is pretty small and I try to be careful about making changes here. 6. the base &ldquo;base&rdquo; styles are styles that apply across the whole site that I chose myself. I have to keep this section really small because I&rsquo;m not confident enough to enforce a lot of styles across the whole site. These are the only two I feel okay about right now, and I might change the <section> one: /* 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); } I think for the base styles it&rsquo;s going to be easiest for me to work kind of bottom up &ndash; first start with almost nothing in the base styles, and then move some styles from the components into base styles as I identify common things I want. 7. spacing I haven&rsquo;t completely worked out an approach to managing padding and margins yet. I&rsquo;m definitely trying to be more principled than how I was doing it in Tailwind though, where I would just haphazardly put padding and margins everywhere until it looked the way I wanted. Right now I&rsquo;m working towards making the outer layout components in charge of spacing as much as possible. For example if I have a <section> with a bunch of children that I want to have space between them, I might use this to space the children evenly: section > *+* { margin-top: 1rem; } Some inspiration blog posts: the owl selector &ldquo;no outer margin&rdquo; 8. responsive design: use more grid! The way I was doing responsive design in Tailwind was to use a lot of media queries. Tailwind has this md:text-xl syntax that means &ldquo;apply the text-xl style at sizes md or larger&rdquo;. I&rsquo;m trying something pretty different now, which is to make more flexible CSS grid layouts that don&rsquo;t need as many breakpoints. This is hard but it&rsquo;s really interesting to learn about what&rsquo;s possible with grid, and it&rsquo;s a good example of something that I don&rsquo;t think is possible with Tailwind. For example, I&rsquo;ve been learning about how to use auto-fit to automatically use 2 columns on a big screen and 1 column on a small screen like this: display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content)); justify-content: center; I also used grid-template-areas a lot which is an amazing feature that I don&rsquo;t think you can use with Tailwind. Some inspiration: A responsive grid layout with no media queries from CSS Tricks 9. the build system: esbuild In development, I don&rsquo;t need a build system: CSS now has both built in import statements, like this: @import "reset.css"; @import "typography.css"; @import "colors.css"; and built in nested selectors, like this: .page { h2 { ...} } If I want, I can use esbuild to bundle the CSS file for production.