Tailwind에서 벗어나며 CSS 구조화 배우기

2 hours ago 1
  • 몇몇 사이트를 Tailwind에서 시맨틱 HTML과 바닐라 CSS로 옮기며, Tailwind가 제공하던 규칙 중 필요한 것만 직접 재구현함
  • Tailwind의 preflight reset, 색상 팔레트, font scale처럼 익숙한 시스템은 유지하되 CSS 변수와 파일 분리로 바닐라 CSS에 옮겨 담음
  • CSS 대부분은 컴포넌트별 파일로 나누고 고유 클래스를 둬, 한 컴포넌트 수정이 다른 컴포넌트를 몰래 깨뜨릴 가능성을 줄임
  • Tailwind를 떠나는 배경에는 최신 Tailwind의 빌드 시스템 의존성, 2.8MB tailwind.min.css, 바닐라 CSS와의 혼재, CSS 제약이 있음
  • 반응형 설계는 breakpoint보다 CSS grid의 auto-fit, grid-template-areas를 더 활용하려 하며 @layer, @scope, container queries도 학습 대상으로 삼음

Tailwind에서 배운 구조를 바닐라 CSS로 옮기기

  • 8년 전 Tailwind를 처음 쓸 때는 CSS 코드를 어떻게 구조화해야 할지 몰랐고, 완전한 혼란보다 Tailwind가 훨씬 나은 선택이었음
  • 최근 약 일주일 동안 몇몇 사이트를 Tailwind에서 시맨틱 HTML + 바닐라 CSS로 옮기며, Tailwind가 제공하던 규칙 중 필요한 부분만 직접 선택해 재구현하게 됨
  • A whole cascade of layersHow I write CSS in 2024를 읽으며, 모든 CSS 코드베이스에는 레이아웃·폰트·색상·공통 컴포넌트 같은 서로 다른 관심사를 관리할 시스템이 필요하다는 점이 분명해짐
  • Tailwind에는 reset stylesheet, 색상 팔레트, font scale 같은 시스템이 이미 있었고, 익숙하고 유용한 부분은 바닐라 CSS에서도 모방할 수 있음

CSS 코드베이스에 둔 주요 시스템

  • 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";
    • 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 관련 글을 쓴 적이 있음

Tailwind에서 벗어나는 이유

  • Tailwind는 2018년 이후 빌드 시스템 의존성이 훨씬 커졌고, 최신 Tailwind를 빌드 시스템 없이 쓰는 것은 불가능해 보여 수년간 Tailwind v2를 사용해 왔음
  • 빌드 시스템 없이 Tailwind를 쓰는 대안으로 litewind가 있는 것으로 보임
  • Tailwind는 원래 빌드 시스템과 함께 쓰는 것이 전제였지만, 실제로는 그렇게 하지 않았기 때문에 많은 프로젝트에 2.8MB짜리 tailwind.min.css 파일이 남아 있었고 다소 어색하게 느껴짐
  • Tailwind를 처음 쓸 때보다 CSS 실력이 더 좋아짐
  • Tailwind에는 결국 제약이 있으며, CSS에서 이상하거나 특수한 작업을 하고 싶을 때 항상 가능하지는 않음
  • 그런 제약은 매우 유용할 수 있고, 실제로 바닐라 CSS로 옮기면서 Tailwind의 일부 제약을 다시 구현하고 있지만, 이제는 필요한 제약만 골라 쓰고 싶어짐
  • 같은 프로젝트 안에서 바닐라 CSS와 Tailwind가 섞인 사이트들이 생겼고, 이를 유지보수하는 것이 즐겁지 않았음
  • 시맨틱한 HTML을 작성하면 어떤 느낌인지 궁금했음

앞으로 배워보고 싶은 CSS 기능

  • @layer는 cascade layer를 다루는 기능으로, 아직 사용하지 않았지만 배워보고 싶은 기능임
  • @scope는 컴포넌트나 특정 범위 안의 스타일을 다루는 데 관심이 가는 기능임
  • container queries는 컨테이너 기준 반응형 설계를 위한 기능으로 배워보고 싶음
  • subgrid는 CSS grid 관련 기능으로 관심 목록에 있음

Tailwind를 완전히 부정하지 않는 결론

  • 지금은 Tailwind에서 벗어나고 있지만, Tailwind를 쓰기 시작한 것 자체는 여전히 만족스러움
  • Tailwind를 사용하면서 많은 것을 배웠고, tailwind.min.css를 삭제한 뒤에도 사이트 안에서 Tailwind의 일부를 계속 사용할 수 있음
  • wizardzines.com의 CSS를 원래 설계하고 작성한 Melody Starling 덕분에 사이트의 멋지고 재미있는 부분이 만들어졌음
  • CSS 작업 중 CSS Tricks, Smashing Magazine 등에서 많은 CSS 글을 읽었고, CSS 커뮤니티가 실천 방식을 많이 공유해 큰 도움이 됨
Read Entire Article