내가 하면 더 잘 만들것 같아서 만들어 본 세상 귀여운 on-demand Atomic CSS Library.
최근에 CSS계에서 주목받고 있는 TailwindCSS를 써보셨거나 들어보신 적이 있나요? 혹은 Utility-first CSS, Atomic CSS, Functional CSS이라는 CSS 방법론을 들어 본적이 있나요?
Bootstrap이나 Sass, BEM, 혹은 CSS-in-JS 와는 달리 조금 덜 주류이고 아직은 오해가 많지만 TailwindCSS를 통해서 조금씩 알려지고 있는 사실은 정말 괜찮은 방법인 Atomic CSS 방법론과 함께 이러한 방식으로 만들어본 기존 문제점들을 개선한 자체 개발한 CSS 프레임워크인 AdorableCSS를 소개해보려고 합니다.
Atomic CSS나 TailwindCSS에 관심이 없더라도 이 글은 CSS에 대한 전반적인 내용을 다루고 있으니 CSS 자체에 관심이 있는 분들 이라면 한번 읽어 보시면 좋을 거라고 생각합니다.
웹 어플리케이션 개발에서 CSS를 통해 UI를 만드는 작업은 생각보다 까다로운 작업입니다. 분명 난이도는 높지 않는데 절대적인 작업 공수가 많이 들어가다 보니 여기에 투자되는 시간이 비효율적이라는 생각이 들었습니다.
또한 UI 개발은 결과물을 빨리 낼 수록 디자인과 기획을 검증하는 시간을 줄일 수 있고 이는 곧 더 나은 제품을 만드는 결과로 이어지기에 CSS 개발의 생산성이 높아지는 방법을 찾고 싶었습니다.
그동안 여러가지 CSS 방법론과 프레임워크 및 도구들을 실험해보면서 제가 확립한 저만의 CSS Best Practice의 결정체인 AdorableCSS를 소개하려 합니다.
그러면서 여기에 적용된 패러다임인 Atomic CSS에 대해서도 함께 이야기를 하고 싶었습니다. Atomic CSS는 사실 오래전부터 있었지만 최근에 와서야 다시 재발견되었으며 다소 오해가 많은 패러다임이기에 왜 이러한 방법이 지금에서와서 채택이 되게 되었는지 CSS의 역사을 살펴보며 함께 설명드리려고 합니다.
이 글이 현대 CSS에 대한 이해를 높이고 CSS 생산성을 높일 수 있는 방법에 대한 하나의 인사이트가 될 수 있기를 바랍니다.
목차
1부. AtomicCSS 이해를 위한 최소한의 CSS의 역사 이야기
2부. TailwindCSS의 출현! AtomicCSS가 뭘까요?
3부. TailwindCSS의 의의와 한계점
4부. 그래서 만들었습니다! 세상 귀여운 CSS Framework: AdorableCSS
최초 웹은 문서를 공유하기 위해서 만들어졌습니다. 그리고 이 문서를 표현하기 위해서 HTML이 만들어졌죠.
HTML은 컨텐츠에 의미를 부여하는 태그를 붙여주어 서식을 꾸미는 방식으로 만들어 졌습니다. 이렇게 해서 의미에 맞는 적당한 서식의 형태로 문서를 보여줄 수 있었습니다.
<h1>제목</h1>
<p>문단입니다.</p>
웹 문서가 보편화 되면서 조금 더 다른 형태의 서식으로 꾸미기를 원했고 이를 위해서 style이라는 것이 추가가 되었습니다. 그래서 태그에 style을 입력해서 조금 더 다양한 형태의 문서를 만들 수 있게 되었습니다. 이렇게 태그에 직접 style을 지정하는 방식을 inline-style이라고 합니다.
<!-- style을 통해서 빨간 밑줄 제목을 만들었다.-->
<h1 style="color: red; text-decoration: underline">This is Red Underline Title</h1>
inline-style은 중복서식을 표현할때 코드가 너무 비대해지면서 가독성도 떨어지고 유지보수가 어렵다는 것을 알게됩니다.
그래서 다음과 같은 원칙이 하나 만들어지게 됩니다.
원칙1. inline-style은 나쁘다!
앞서 설명한 이유로 inline-style의 중복을 제거하기 위한 방법을 고안하게 되고 이것이 바로 우리가 현재 사용하고 있는 CSS입니다.
<!-- inline-style 방식은 동일한 서식을 중복해서 써야만하다. -->
<strong style="color: red; text-decoration: underline">This is Red Underline Title</strong>
.... <strong style="color: red; text-decoration: underline">Other Red Unerline</strong>
... <strong style="color: red; text-decoration: underline">Underline Title 333<strong>
CSS는 위와 같이 중복해서 쓰이던 inline-style을 별도의 Rule로 선언을 하고 서식이 필요한 곳을 선택해서 반복해서 적용을 하는 방식으로 만들어졌습니다.
<!-- CSS를 통해 중복된 서식을 하나의 Rule로 만들어 -->
<style>
strong { color: red; text-decoration: underline }
</style>
<!-- 필요한 곳에 적용할 수 있다. -->
<strong>This is Red Underline Title</strong>
.... <strong>Other Red Unerline</strong>
... <strong>Underline Title 333<strong>
CSS를 별도로 작성을 하게 되면서 자연스럽게 컨텐츠와 서식이 분리 되었습니다. 이렇게 컨텐츠와 스타일을 분리하고 보니 컨텐츠와 서식을 꼭 1:1로 매칭을 하지 않고 하나의 컨텐츠에 여러가지 스타일을 선택적으로 적용할 수 있다는 것을 알게 됩니다.
<!-- 컨텐츠를 먼저 만들면 -->
<strong>This is Red Underline Title</strong>
.... <strong>Other Red Unerline</strong>
... <strong>Underline Title 333<strong>
/* 동일한 컨텐츠로 이러한 서식을 적용하거나 */
/* style1.css */
strong { color: red; text-decoration: underline }
/* 저러한 서식을 선택적으로 사용할 수 있다. */
/* style2.css */
strong { color: blue; font-weight:bold }
</style>
이러한 장점은 컨텐츠는 유지하고 디자인만 변경할 수 있는 테마형 솔루션의 형태를 발전을 하게 되면서 다음과 같은 원칙이 만들어집니다.
✌ 원칙2. 관심의 분리: 컨텐츠와 서식을 분리하여 관리하자.
컨텐츠가 수정되면 HTML을 수정하고 서식이 변경될때에는 CSS를 수정하자.
그러면서 유연하게 디자인을 적용할 수 있도록 HTML을 잘 구조화해서 작성을 하고 HTML 변화 없이 CSS만으로 여러가지 스타일을 만드는 것이 중요한 아젠다가 되었습니다.
하나의 컨텐츠에 여러개의 스타일! CSS Zen Garden을 기억하시나요?
이러한 배경으로 HTML을 수정하지 않고 CSS만으로 디자인을 적용하려고 하다보니 스타일을 하나하나 원하는 엘리먼트를 선택해서 스타일을 적용하는 것은 쉬운일이 아니었습니다. 원하는 요소를 찾고 수정하기 위해서는 복잡한 Selector를 써야했고 Selector역시 세분화가 필요했습니다.
그래서 이렇게 복잡해진 Selector를 조금 더 쉽게 만들 수 있는 언어인 Sass와 같은 것들이 등장 하였습니다.
이후 Ajax가 보편화가 되면서 백엔드에서 HTML을 제외한 데이터만 전달을 할 수 있게 되면서 이제는 HTML의 편집권은 백엔드가 아니라 프론트엔드로 내려오게 됩니다.
그렇게 HTML과 CSS를 동시에 편집을 할 수 있게 되면서 이제는 복잡하게 Selector를 쓸 필요가 없다는 것을 깨닫게 됩니다. 이제는 필요할때 HTML을 수정할 수 있으니 CSS를 복잡하게 하는 것보다 HTML을 복잡하게(?) 쓰는 것이 더 낫다는 것을 알게 됩니다.
CSS에서 복잡한 Selector를 잘 쓰기 보다는 HTML에서 미리 잘 지어둔 class 이름이 더 좋구나.
그래서 이후에는 Selector를 어떻게 잘쓰는지 보다 어떻게 class 이름을 더 잘 지을 수 있는지를 고민하는 식으로 흐름이 변하게 됩니다.
복잡한 Selector보다는 단순한 Class Selector를 사용하는 것이 보편화되면서 어떤식으로 이름을 지을 지 고민을 하기 시작하였습니다.
class 이름을 짓는 방식에는 2가지가 있었습니다. 의미를 기반으로 하는 .error
, .title
과 같은 이름과 기능이나 시각적 요소를 기반으로 하는 .red
.bold
와 같은 방식이었죠.
어떻게 이름을 짓는 것이 좋을까?
.error
vs.red
.description
vs.text-right
.title
vs.bold
스타일 변경시 CSS를 수정한다는 원칙에 의거하여 변경된 디자인에 맞게 CSS를 변경하다보니 시각적인 이름을로 짓게 될 경우 .red { color: orange}
라는 이상한 형태가 만들어진다는 것을 알게 되었습니다.
그래서 유지보수와 유연한 대응을 하기 위해서는 class이름을 의미기반으로 짓는 것이 더 좋다는 다음과 같은 원칙이 만들어집니다.
원칙3. 시각적인 이름보다 시멘틱한 이름이 좋다.
그래야 디자인 변경에 유연하고 같은 컨텐츠에 다양한 스타일을 적용할 수 있게된다!
웹이 발전을 하면서 웹은 더 이상 문서나 홈페이지 형태만 있는게 아니게 되었습니다. 구글 지도나 구글 오피스와 같이 웹으로도 어플리케이션을 만들게 되고 CMS와 같은 데이터를 다루는 백오피스등의 웹페이지의 요구사항이 커지면서 웹은 점차 어플리케이션의 형태로 발전을 하게 됩니다.
"이제는 웹 문서뿐만 아니라 웹 어플리케이션도 만들어주세요."
??? : 나는 문서를 꾸미려고 했지. 앱을 만들려던게 아니었어! 😱
웹 어플리케이션은 웹 페이지에 비해 비중은 낮지만 훨씬 더 고부가가치를 만들어 내기에 많은 개발자들에게는 웹 문서보다는 웹 어플리케이션을 만드는 것이 더 중요해집니다. 그러나 CSS는 웹 문서를 잘 꾸미기 위해서 설계되었죠.
그리하여 초기에 문서를 만들기 위해서 설계된 CSS는 웹 어플리케이션 개발 패러다임에서 과도기를 맞이하게 됩니다.
흔한 CSS로 개발하면서 겪게되는 상황들...
- HTML을 복사-붙여넣기 했는데 CSS가 제대로 적용이 안됨.
- CSS를 수정했는데 엉뚱한 곳이 틀어져 보이는 문제
- Selector가 안 먹어서 !important로 덮어써야 하는 경우
- 안쓰이는 코드 찾기가 진짜 어려운 문제 (특히 JS와 결합된 class)
- 도무지 CSS가 재사용이 되지 않는 문제
CSS는 어플리케이션을 만들기 위해 설계가 된 것이 아닌데 이미 JS는 Component와 Framework 기반의 개발방식으로 변해가고 있었습니다. 당시에는 flexbox와 같은 어플리케이션을 위한 레이아웃 스펙은 존재하지 않았기에 float등을 억지로 사용하고 문서의 간격을 만들기 위한 margin등을 통해서 레이아웃을 하는 스펙의 부재도 있었지만 결정적으로 큰 2가지 설계상 문제들이 존재했습니다.
1. Global Scope: 전역변수가 나쁜 것은 다 아시죠? 😫
- 내가 수정한 코드가 모든 프로젝트에 영향을 준다.
- 그래서 엉뚱한 곳이 문제가 생기기에 관리 비용이 증가한다.
- 기존에 한번 사용한 이름을 피해가며 작성해야한다.
2. Specificity: 왜 작성된 순서대로 적용이 되는게 아닌거죠? 😥
- HTML에서 지정한 class순서가 아니라 CSS의 순서에 의해 서식 우선순위가 결정된다.
- 코드 순서도 있지만 무엇보다 Selector가 복잡할수록 서식이 나중에 적용된다.
- 다른 서식을 덮어 쓰기 위해서는 Selector를 더 복잡하게 작성을 해야한다.
- 이걸 간단한 Selector로 덮어쓰려면 !important를 해야한다.
- !important를 한 속성을 덮어쓰려면 복잡한 Selector에 !important를 해야한다. ...
처음부터 CSS를 작성하는 규칙을 잘 짜면 이러한 문제들을 해결할 수 있지 않을까? 하는 생각에서 나온 것이 CSS 방법론입니다.
어떤 규칙으로 CSS를 만들어야 이런 문제들을 안 발생 할 수 있을까요? 여러가지 고민을 하면서 각자만의 방법론들이 만들어지기 시작했습니다.
SMACSS, OOCSS, BEM, ITCSS, ATOMIC CSS ...
Winner is BEM!
- Specificity를 하나로 통일하면서 단순하여 기억하기 쉬운 컨벤션
하지만 이러한 방법론으로는 복잡성을 줄이거나 더 나은 생산성을 가져오는 것은 아니었고 CSS의 본질적인 문제를 해결해주지는 않았습니다.
'어쩌면 CSS로는 태생적으로 해결을 할 수 없는게 아닐까? 그러면 JS의 도움을 받아보자!' 라는 생각으로 CSS 자체보다는 JS의 도움을 받는 식으로 해결을 하고자 하는 움직임이 생겨납니다.
CSS의 범위를 컴포넌트를 벗어나지 않도록 해주자! Global Scope 문제의 해결책
CSS의 문제인 Global Scope를 막기 위해서 Component 단위에서 사용되는 CSS에 hash를 추가하여 CSS가 더 이상 Global하지 않도록 하는 방식을 통해서 해결을 하고자 하는 방법이 만들어졌습니다.
이후 React가 대세가 되면서 React에서 Style을 다루는 불편함을 해소하기 위해서 JS에서 HTML을 쓰기 위해 JSX를 만든 것처럼 JS에서 style을 쓰기 위한 방법으로 CSS-in-JS 라는 방법이 등장하게 됩니다.
CSS는 비단 Global Scope와 Specificity 말고도 사실 문제가 많다. JS에서 CSS를 해보면 어떨까?
최초 CSS가 아니라 JS를 통해서 문제를 해결해보자는 시각이 제기 되었고 이러한 방식은 이후 CSS-in-JS라는 방법으로 구체화되게 됩니다.
그러면 CSS를 JS의 컴포넌트 방식으로 작성을 해보자!
그리고 그러한 방식의 대표주자가 되는 StyledComponent가 탄생을 하게 됩니다.
이후 지금은 CSS-in-JS가 새로운 흐름이 되어 계속 발전을 하고 있는 중입니다.
그래서 CSS의 발전 방향을 보면 다음과 같이 CSS를 컴포넌트 방식에 맞춰가는 형식으로 발전을 하고 있다는 것을 알 수 있었습니다.
복잡한 Selector → 간단한 Selector → No Selector
Global Scope → Local Scope
HTML과 CSS의 분리 → 컴포넌트로 결합
그렇다면 CSS의 최종 종착지는 결국 CSS-in-JS인 걸까요?
“Best practices” don’t actually work.
Utility-First CSS Framework
그 이후 지금까지의 Best practices는 사실 제대로 동작하지 않는다며 만들어진 새로운 시각의 CSS Framework, TailwindCSS가 등장을 합니다.
하지만 이 TailwindCSS는 다른 CSS의 새로운 기술과는 달리 많은 Hater들을 가지고 있습니다. 새로운 기술인데 이렇게 호불호가 갈리는 이유는 무엇일까요?
그 이유를 설명하기 위해 지금까지 CSS의 역사적 맥락이 필요했습니다. 😅
다음 장에서는 본격으로 TailwindCSS의 근간이 되는 Atomic CSS의 개념을 이해하면서 왜 논란이 되는지도 한번 살펴보려고 합니다.
Note
Utility-First, Atomic CSS, Functional CSS 는 사실상 모두 같은 것을 의미합니다. 해당 방식이 비주류다보니 인식의 전환을 위해 서로가 키워드를 선점하고자 새로운 키워드를 제시하고 있습니다.. 인지도가 가장 높은 TailwindCSS는 이 중 Utility-First를 밀고 있지만 일단 이 글에서는 Atomic CSS라고 통일해서 부르도록 하겠습니다.
“Best practices” don’t actually work.
지금까지 해왔던 방법은 틀렸다고 말하면서 시작된 TailwindCSS! 과연 지금까지의 Best Practice는 뭐였을까요?
이전 장에서 알아본 다음과 같은 원칙들이었습니다.
원칙1. inline-style은 나쁘다.
원칙2. 컨텐츠와 서식을 분리하자.
원칙3. class 이름은 시멘틱한게 좋다.
하지만 문서에서 앱으로 넘어 오면서 우리는 이러한 방식에서 힘들어 하면서 의문을 가지게 되었습니다.
정말 지금도 이 "Best practices"가 유효할까?
의문1. inline-style이 정말 나쁜 걸까?
의문2. 컨텐츠와 서식의 관점분리가 가능한걸까?
의문3. 정말 시멘틱한 이름이 좋은 걸까?
정말로 inline-style하게 컨텐츠와 서식의 관점 분리를 하지 않고 시멘틱하지 않고 시각적인 이름을 쓰는게 정말 나쁜 것일까요?
컨텐츠와 서식을 분리 하지 않는다면 어떻게 작성을 하는 것일까요?
우리는 분명 CSS가 만들어지고 초기 자연 발생했던 .bold
.hidden
.red
.text-right
.mt10
과 같은 Class를 만들어서 분명히 편하게 사용했던 경험들이 있었습니다. 그러나 이러한 방식은 시멘틱하지 못했기에 일종의 편법으로 여겨졌었죠. 하지만 편리한것은 분명한 사실이었습니다.
이 방식이 편리한 방식이라면 일부만 이러한 편법이 아니라 그냥 전부다 이러한 방식으로 만들어 보는 것은 어떨까요?
bg-gray-100
p-8
w-32
h-32
.text-center
.text-lg
.font-semibold
.pt-3
.pt-0
self-start
flex-wrap
mb-1
This is Atomic CSS!
👀 의미기반이 아닌 시각적 기능에 기반한 이름을 지은 변하지 않는 단일 클래스를 이용하자.
🎨 변하지 않는 CSS를 먼저 만들어두고 HTML에서 스타일을 작성하자.
이와 같이 의미기반이 아닌 미리 만들어둔 시각적인 이름을 바탕으로 HTML에서 필요한 스타일을 적용하는 방식으로 개발하는 방법론이 바로 Atomic CSS 입니다.
기존까지 역사적으로 합의된 원칙과는 정반대로 작성을 하는 이유는 무엇일까요?
"그것은 바로 의미론적으로 이름짓기가 아주아주 어렵기 때문입니다." 🤯
.button
.card
.gnb
.side-bar
시멘틱한 이름 좋아요!
.homepage-section
.collection-module
.section-content
.main-content
조금만 범위를 넓혀보면 시멘틱한 이름...? 어떤 모양인지 상상이 되나요?
.inner-main
.wrap_cont
.cp_more_wrap
.inner_item
.wrap_title
이런 이름들은 어떤가요? 어떤 의미가 있죠?
의미가 없는데도 의미를 부여해서 이름을 짓는것은 더 어렵습니다.
하지만 주어진 디자인을 구현하기 위해서는 이렇게 선 하나, 배경색이나 글자색, 여백등을 넣기 위해서 우리는 이러한 이름들을 지어야만 합니다.
(위 예시들은 지어낸 것이 아니라 실제로 사용하고 있는 이름들에서 가져왔습니다.)
.wrap_title
.title_wrap_container
.inner_g
이렇게 만들어진 CSS들은 어떠한 서식이라 하더라도 다른 프로젝트에서는 아마 재사용이 불가능할 겁니다. 다른 프로젝트에서는 다른 의미를 가지는 컨텐츠들로 만들어졌을테니까요.
또한 이렇게 지어놓은 이름은 프로젝트 내에서 중복해서 사용할 수 없기 때문에 새로운 이름을 지을때면 항상 기존에 만든 CSS를 피해가야 합니다.
.title
.section-title
.main-title
.footer-title
그렇지 않으려면 결국 Selector를 조립 해야하는 데 ex) #main a.title > span
이런식으로 Selector를 복잡하게 작성하게 되면 Specificity 문제가 그대로 발생하게 됩니다.
Traditional CSS
이름짓기도 어려운 CSS를 계속 만들어야 하고
만들어 놓은 CSS를 피해야 하니 점점 복잡해져가서 파일 크기가 점점 커지지만
재사용이 불가능하기에 매번 계속 작성해야하는 악순환...
시각적 기능 기반 쉬운 이름을 가지며
미리 만들어 두기 때문에 1번 외워두면 계속 재사용이 가능하며
CSS가 일정 크기 이상으로는 더이상 커지지 않습니다.
무엇보다 필요없는 이름을 짓는 고통에서 해방이 된다!
뿐만 아니라 의도하지 않더라도 누구나 동일한 형태의 코드 스타일을 작성하게 된다.
=> 협업에서 컨벤션을 맞추기 위한 노력이 줄어든다.
=> 컨벤션과 방법론의 역할을 함.
구조가 바뀌어도 문제되는 분야가 국지적이다.
기존에 만들었던 코드를 의식하지 않고 작성해도 된다.
코드를 수정하고 구조가 바뀌어도 컨텍스트 파악이 쉽다.
= Global Scope (X) = Local Scope (O)
어떤가요? AtomicCSS가 괜찮아 보이나요?
하지만 이러한 AtomicCSS는 지금껏 주류는 고사하고 늘 논란의 대상이었습니다.
이러한 장점이 있음에도 해당 방식은 그 동안 주류가 되지 못했습니다.
왜 TailwindCSS는 왜 AtomicCSS가 아니라 Utility-First 라고 이름을 지었을까? Functional CSS는 이들이랑 뭐가 다른 걸까요? 왜 같은 방법에 이렇게나 이름이 많을까요?
사실 AtomicCSS는 TailwindCSS가 시초가 아닙니다. 앞서 설명했듯이 이러한 방식은 CSS가 생긴 초창기 시절부터 꾸준히 그 편리함으로 인해서 제기되었으나 언제나 시멘틱한 방법이 옳다는 방식으로 CSS가 발전해왔습니다.
그래서 처음에는 FunctionalCSS 라는 이름으로, 그 다음에는 AtomicCSS라는 이름으로, 이제는 Utility-First라는 이름으로 기존과는 다른 방식이라고 인식전환을 시도했으나 번번히 올바르지 않은 방법이라고 인식되고 거론되었고 이러한 방식은 소수의 마니아들이 사용하는 방식이 되었습니다.
하지만 TailwindCSS가 유명해진 것은 커뮤니티를 통해 이러한 인식의 전환을 하기 위해서 부단한 노력을 했다는 점입니다. 또한 이러한 패러다임이 일부 편리함을 위한 차용이 아니라 전면적으로 사용해도 된다는 패러다임의 변화를 가져오고 지금까지 꾸준히 업데이트를 하고 있는 점이 인정을 받게 만들었습니다.
저 또한 이렇게 서론이 길었던 이유는 역시 제가 만들었던 프레임워크 역시 이러한 AtomicCSS방식에 대한 인식의 전환 설득이 필요하기 때문입니다.
😡 "이미 10년도 전부터 안 좋다고 결론이 난 방법을 왜 또 계속 들고 오는 건가요?" 90년대나 있었던 inline-style과 뭐가 다른거죠?
왜냐하면 시대가 변했으니까요...
이제는 CSS가 굳이 시멘틱 하지 않아도 됩니다. 특히 WebFramework를 사용한 Component 기반 개발 시대인 지금은 Web Framework의 컴포넌트가 시멘틱과 중복방지 역할을 대신 해주고 있습니다.
지금 시대는 하나의 컨텐츠에 여러가지 디자인을 할 필요성이 줄어들었습니다. 디자인이 곧 아이덴티티인 시대이기에 더 이상 컨텐츠와 서식을 분리할 필요가 없어졌습니다.
= 디자인이 곧 아이덴티티
= 솔루션이 아닌 서비스의 시대!
= 시멘틱 하지 않아도 된다.
뿐만 아니라 비주류였던 AtomicCSS로 알게 모르게 조금씩 진화를 하고 있었습니다.
FunctionalCSS -> Atomic CSS -> Utility First -> on-demand Atomic CSS
그래서 그때는 틀렸지만 지금은 어떨까요? 이 다음 장에서는 Atomic CSS 패러다임이 어떻게 진화해 왔고 왜 TailwindCSS는 과거와 달리 사용할 수 있는지 그리고 어떤 점에서 아직은 아쉬운지 이야기해보려고 합니다.
잘못된 방법이라고 믿고있는 방법을 주류에 올려놓기 위한 노력들
TailwindCSS의 가장 큰 의의은 이러한 AtomicCSS 방식을 주류 패러다임에 편입 시키기 위해서 여러가지 커뮤니티 활동과 함께 이 패러다임을 믿고 거대한 생태계를 만들어 낸 것입니다. 조금 더 AtomicCSS 방식의 미래와 장점을 한번 생각해봅시다.
"inline-style처럼 생겼지만 inline-style이 아닙니다."
inline-styler과 달리 AtomicCSS는
1. 미디어 쿼리도 사용할 수 있고
2. 한번에 여러속성을 포함하는 스타일을 만들 수도 있고
3. 의사 선택자인 의사요소를 추가할 수도 있습니다. (:hover, :active)
4. Selector와 함께 결합해서 사용 할 수도 있으며
5. inline-style보다 훨씬 더 유연한 방식으로 제공할 수 있습니다.
"컨텐츠와 서식 관심의 분리가 과연 반드시 좋은 것일까요?"
jQuery
HTML과 JS의 관심의 분리를 해야지!
html + JS
<button id="button">click me!</button> <h1 id="title">title</h1>
$("#button").on("click", (e) => {...} $("#h1").text("제목")
const title = (prop) => {
return <h1>{prop.title}</h1>
}
WebFramework
관심이 같은 것끼리 모아두자!
HTML과 데이터를 하나의 템플릿에 넣으면 좋더라! = 컴포넌트
Component
const Button = () => {
const onClick = {...}
return <button onClick={onClick}>click me!</button>
}
결국 HTML과 JS가 서로 종속성이 있기에 관심의 분리보다 하나의 구조로 결합하는게 관리하기에 더 좋았던 것 처럼 HTML과 CSS역시 서로간의 관심을 분리하기 보다는 하나의 구조로 결합하는 편이 더 낫지 않을까 하는 생각을 하게 되었습니다.
"시멘틱하게 이름을 붙여야만 디자인 변경에 유연할까요?"
하지만 지난 10년간 CSS는 그 시멘틱한 방법안에서 복잡함과 CSS 관리의 어려움에 맞서왔지만 어플리케이션 개발 환경에서는 그러한 패러다임이 유효하지 않다는 것을 알게 되었을 뿐입니다.
디자인의 컨셉이 하나뿐이라면 컴포넌트 기반 프레임워크 환경이라면 시멘틱한 이름의 역할을 이제 컴포넌트가 충분히 상쇄를 해줄 수 있습니다.
지난 if(kakao) 이야기
https://if.kakao.com/session/89
앱만 만들던 사람들과 웹앱으로 변환했던 경험이 있었습니다. 당시 앱만 했던 사람들은 CSS를 훨씬 어려워했으며, inline, 관심의 분리, 시멘틱 아무상관없이 attibute에 직접 값을 넣는 방식을 훨씬 더 선호했고 아무런 문제가 없었으며 서비스는 잘 오픈했습니다.
"그렇게 하면 HTML이 너무 못생져지고 가독성이 완전 떨어져요!"
대부분 사람들이 지적하는 TailwindCSS의 문제는 HTML의 가독성 문제를 꼽습니다. 그렇다면 현재 CSS의 주류 3인방의 코드는 어떨까?
현재 class이름을 짓는 정석(?)에 가까운 BEM 방식도 초창기에는 가독성 문제를 지적받았습니다. CSS Modules나 CSS in JS 역시 그 가독성이 높은 편은 아닙니다. 언제나 새로운 것은 낯설기 마련이며 이제는 결과로적인 가독성보다 쓰기 편하고 문제가 생기지 않는 방향으로 가고 있다는 것을 알게 됩니다.
하나의 컨텐츠에 여러 테마의 서식으로 적용해야하는 기능이 필요하다면, 혹은 웹 프레임워크를 사용하지 않고 개발을 한다면 TailwindCSS는 맞지 않는 옷일 수도 있습니다. 하지만 현대의 웹 서비스 개발에서는 하나의 디자인을 중심으로 웹 프레임워크를 통해 개발을 할 경우가 훨씬 더 많습니다!
.bold
.text-center
.hidden
.grid-6
.clearfix
초창기 이러한 Utility CSS는 그냥 일부 편리한 CSS였을 뿐이었습니다. 그리고 이러한 방식은 일부 수정을 간단하고 빠르게 처리하는 일종의 꼼수로 취급받았습니다. 그래서 이러한 방식은 그 동안 주류 기술이 되지 못했습니다.
그러나 TailwindCSS의 경우 이러한 패러다임을 완전히 벗어나서 단순히 편리한 class모음 몇가지가 아니라 그 편리한 방식을 모든 곳에 적용하려는 방식으로 개발하고 기존의 실험적인 라이브러리를 넘어 기존 프레임워크 및 개발 생태계와의 쉬운통합, IDE 지원, 기존방식과 적절히 결합해줄 @apply과 같이 하이브리드한 브릿지 기능, 사람들이 우려하는 반복처리, 용량문제 등을 해결할 PurgeCSS와 같이 본격적인 대형 라이브러리의 행보를 보였습니다.
그 과정에서 많은 패러다임의 충돌이 있었고 Hater들도 존재했고, 저 역시 어렴풋이 이 방식이 좋을 수도 있겠다는 생각은 있었지만 작정하고 써 볼 생각은 안 했었는데 이러한 설득에 넘어가 저도 TailwindCSS를 현업에서 쓰기 위한 노력을 해봤습니다.
TailwindCSS를 현업에서 쓰기위해 적용을 해보니 당시에는 몇가지 문제들이 있었습니다.
🎨 변하지 않는 CSS를 먼저 만들어두고 HTML에서 스타일을 작성하자.
=> 하지만 디자인이 없으면 CSS를 먼저 만들지를 못합니다. 😭
그러니 초창기 TailwindCSS는 크기와 색상을 미리 만들어 둘 수 밖에 없었습니다. 전부 다 만들어 둔다면 용량이 무한정 늘어나니 자주 쓰는 일부 크기와 색상만 만들어 두었습니다. 하지만 저는 대부분 실전에서 디자이너가 만들어 달라는대로 작업을 해야했기에 미리 지정된 크기와 색상으로 작업하지 않습니다.
이러한 부분들은 디자인을 받아가며 수정을 하는 과정에서 미리 수치나 색상을 서로 맞춰두고 작업을 해야한다는 의미였습니다.
TailwindCSS는 그것이 디자인시스템이고 그렇게 맞춰두고 작업을 하는 것이 좋은 디자인과 좋은 설계라고 했지만 실전에서는 디자인의 수정과 개발의 작업을 불편하게 만들어 줄 뿐이었습니다. 실무에서는 디자인 시스템이 만들어지기 까지에는 많은 시행착오가 존재하게 되고 수많은 요구사항들을 정해진 몇 가지 팔레트로만 해결을 하는 것은 결코 쉬운일이 아입니다.
이것은 최근에 3.0이 출시되며 JIT(Just-In-Time)이라는 방식이 나오면서 해결을 합니다만 나중에 설명하겠습니다.
뿐만 아니라 w-12는 12px이 아니라 48px로 당시 머터리얼 디자인에서 사용하던 4px grid 기반의 체계는 계속 계산을 해서 개발 과정을 멈칫거리게 만들었습니다.
또한 TailwindCSS에서 만들어둔 inlineCSS의 이름은 CSS 스펙과 이름이 미묘하게 달라서 매번 문서를 봐야했어요. CSS를 많이했던 저의 개발 경험과 미묘하게 어긋남을 느꼈습니다.
무엇보다 모든 CSS의 기능을 쓸 수 있는 것은 아니었어요. 조건부 class 서식이나, Child Selector를 쓸 수도 없었습니다. 코드 가독성이 떨어지는 부분들은 inline이라서가 아니라 이렇게 조건부 class들이라는 것들도 알게 되었습니다.
결국 TailwindCSS가 기존 CSS 개발경험을 완전히 대체를 할 수 없다보니 디자인이 없는 프로토타입에는 유리하나
디자이너와 주로 협업을 하는 현업환경에서 쓰기에는 상당히 부담이 되었습니다.
'AtomicCSS는 좋은 것 같은데 TailwindCSS 자체는 아직 조금 아쉽다. 이거보다 더 좋은 AtomicCSS 프레임워크를 만들수 있지 않을까?'
라는 생각에 "내가 현업에서 쓸 수 있는 CSS 프레임워크" 라는 컨셉으로 한번 만들어보기로 하였습니다!
Atomic CSS 패러다임은 사실 괜찮은건데 TailwindCSS가 아쉬운거라면 더 괜찮은 AtomicCSS 라이브러리를 만들 수 있지 않을까?
TailwindCSS의 아쉬운 점 정리
- 커스텀을 하려면 복잡한 설정을 해야만
한다.했었다.- 용량이 크다. purge를 하면 되지만 속도가 느리다.
- w-16은 16px이 아니다. 4배수 계산 이슈.
- HTML이 복잡해진다.
- 미묘하게 아쉬운 스펙과 문법 = 러닝커브 발생 (특히 flexbox)
- 모든 CSS 기능을 제공하는 것이 아니다.
수치나 색상을 미리 만들어 두지말고 HTML이 변할때마다 만들어 주면 되지 않을까?
이것을 떠올렸을때는 이것만으로도 혁신이라고 생각했었습니다 😅
AtomicCSS 방법을 실전에서 쓸 수 있게 만들게 해준 일등공신 패러다임입니다. 미리 CSS를 만들어야만 사용이 가능했던 방식에서 이제 실시간으로 입력을 할 때마다 그에 준하는 style을 만들어 내면서 마치 진보된 inline-style처럼 함수처럼 쓸 수 있는 형태가 되어 이러한 방식의 실전성이 한층 더 높아졌습니다.
✨ AtomicCSS의 Next Level! ✨
이 내용이 이 글 전체에서 가장 중요한 이야기입니다. AtomicCSS는 on-demand 라는 패러다임으로 인해 한단계 진화했으며 앞으로의 발전이 기대가 되는 이유입니다.
기존에는 CSS를 미리 만들어두고 HTML에 적용을 하는 방식이었기에 미리 수치나 색상등을 만들어야 했고 이 전후관계로 인해서 이 방식은 초기 생산성이 높지 않았습니다. 이제는 번들툴과 MutationObserver등을 이용하여 개발을 할 때에는 수정사항을 바탕으로 실시간으로 style을 생성할 수 있게 되어 수치나 색상입력에 대해서 자유롭게 되었습니다.
특히 최근의 HMR(Hot Module Replace) 방식과 결합이 되어 정말 실시간으로 디자인을 수정을 하고 건드는 것은 큰 생산성을 가져다 주고 있습니다.
또한 이후 빌드 과정에서는 다시 필요한 style만 생성하도록 하여 사용되지 않는 죽은 코드를 CSS에 포함하게 하는 문제 역시 해결할 수 있도록 해주고 있습니다.
🤔 어떤 문법을 제공해야할까!?
다시 배우지 않았으면 좋겠다.
수치나 값이 눈에 잘 보였으면 좋겠다.
타이핑은 많이 하지 않았으면 좋겠다.
가독성이 높았으면 좋겠다.
손에 익은 타이핑 방식이면 좋겠다.
px이 근본이었으면 좋겠다.
여러가지 원칙들을 바탕으로 고심을 하면서 문법들을 한번 정리해보았습니다.
타이핑을 줄이면서도 CSS를 새로 배운지 않게 할 수 있도록 중간점을 찾는 고민을 많이 하였습니다.
- 이미 1~2글자로 줄여서 부르고 있는 것들은 최대한 짧게 줄인다.
ex)class="w(32) h(32) r(8) p(10/16) m(4/8/10/12) z(9999) bg(#000) c(#fff) b(#480ff)"
w = width
h = height
r = border-radius m = margin
b = border
p = padding
z = z-index bg = background c = color
mt = margin-top
bbw = border-bottom-width pr = padding-right
- 유니크한 CSS value라면 그대로 쓴다.
ex).inline
.block
.none
.visible
.hidden
.bold
.underline
.100
.200
.absolute
.relative
.sticky
.fixed
.border-box
.content-box
.space-between
.space-around
.pointer
- 긴 프로퍼티는 핵심만 남겨서 가급적 1번만
ex).text-left
.text-right
.text-center
.snap-start
.snap-x
.pointer-events-none
- 모든 기본적인 CSS의 문법은 쓸 수 있게
모든 CSS Prop:value 제공.box-shadow(0/0/10/#000.2)
// 띄어쓰기는 /로 구분
모든 Selector 제공>div.selected:touch-action(pan-y)
모든 Pseudo 제공>>a:nth-child(2n+1):hover:bg(red)!!
tailwindCSS를 쓰면서 또 아쉬웠던 부분은 flexbox 및 layout 관련 문법들이었습니다. CSS에서 가장 많이 쓰이는 속성들인데 직관적이지 못한 방식들과 길어지는 타이핑으로 인해 복잡하게 보이게 만드는 주범이라고 생각을 했습니다.
items-*
content-*
justify-content-*
justify-*
align-items? align-content? justify-content? justify-items?
flexbox를 다루다보면 정말 헷가리는 속성들! 조금더 쉽게 다룰 수는 없을까?
이러한 문법은 가장 많이쓰는 디자인 핸드오프 툴인 figma에서 영감을 받아 AutoLayout과 유사한 형태로 작성할 수 있게 하여 간결함과 생산성을 높였습니다.
flexbox와 figma의 AutoLayout
- 방향 2. gap, 3. padding, 4. 배치
뿐만 아니라 absolute나 fixed를 이용한 배치의 경우도 빈번이 일어나는데 top:0; left:0; right:0; bottom:0; width:100%; height:100%
와 같은 배치구문들도 보다 직관적인 방식을 제공하여 훨씬 던 간결하면서도 생산성 있는 문법을 제공하였습니다.
그밖에도 여러가지 진보된 AtomicCSS의 기조를 따르면서도 불편했었던 많은 부분들을 수정, 보완하는 방법들을 추가하였습니다.
TailwindCSS를 하다보면 TailwindCSS로 할 수 없는 상황이 나오곤 했습니다. class선택자나 자식 선택자나 복잡한 셀렉터를 써야 하는 경우도 마찬가지였습니다. 기본적으로 CSS에서 제공하는 모든 기능들을 제공하려고 하였습니다.
All-in-one package!
- 모든 CSS Property 사용 가능
- :nth-child, ::after등 모든 pseudo 사용 가능
- 모든 Selector 사용 가능
- 모든 Media Query 사용 가능 (예정)
뿐만 아니라 적게쓰고 짧게 축약하면서도 직관적으로 다 담을 수 있도록 만들어 보았습니다.
기타 센스 있는 문법들
w(32~100%) = min-width: 32px; max-width: 100%;
font(16/1.5/-1%) = font-size, line-height, letter-spacing
c(--primary) = color: var(--primary)
@w(~768): @media max-width(768) { ... }
nowarp... = 말줄임...
ratio(3:2)
백문이 불여일견! 한번 보러오세요 :)
아직 계속 개발중이지만 figma의 AutoLayout로 작성한 경우 자동으로 AdorableCSS로 추출해주는 플러그인을 만들었습니다.
이 플러그인으로 인해서 디자인을 CSS로 개발하는 생산성이 한층 더 높아졌습니다.
Handshake figma 플러그인 🤝
최초에는 컨텐츠와 서식이 한데 모여 있었습니다. 그리고 컨텐츠와 서식을 한데 모으면 중복등을 관리하기가 어렵다는 것을 깨닫고 컨텐츠와 서식을 분리하려는 시도가 생겼습니다. 이렇게 CSS는 문서의 서식만을 별도로 꾸미기 위해서 태어났고 발전했습니다.
컨텐츠와 서식을 분리하니 하나의 컨텐츠에 여러가지 서식을 적용할 수 있다는 것을 알게되면서 하나의 컨텐츠에 여러가지 테마라는 방식을 통해서 CSS는 성장해나갔습니다. 그러면서 HTML과 CSS의 방향은 디자인을 위한 시각적인 정보보다는 컨텐츠의 의미를 중심으로 작성을 하는 시멘틱한 방법을 중심으로 발전을 했습니다.
그러나 웹은 예상보다 훨씬 더 규모가 커졌고 문서나 홈페이지가 아닌 대규모의 어플리케이션 역시 웹 산업에 속하게 되었습니다. 하나의 문서에 여러가지 디자인을 적용할 수 있도록
설계되었고 발전해온 CSS는 이러한 어플리케이션의 변화방향에 맞지 않는 것들이 발견이 되면서 어플리케이션에서 CSS작업은 골칫거리가 되었습니다.
이를 극복하기 위해서 BEM을 비롯한 다양한 방법론과 CSS Modules, CSS in JS 까지 여러가지 해결책들이 나오면서 CSS로 대규모 어플리케이션을 만들어내는 방법들이 자리를 잡아가는 중입니다.
한편에서는 이러한 변화에 따라 기존까지의 방식인 시멘틱한 CSS가 아니라 시각적인 방식으로 작성을 하는 CSS 패러다임을 다시 꺼내들려고 하고 있습니다. 컨텐츠에 직접 서식을 입히려고 하는 이 방식은 이미 최초에 좋지 않은 방식으로 여겨졌기에 주류가 되지 못했지만 시대가 변했습니다.
AtomicCSS 방식은 모든 상황에 다 좋은 더 최신화된 방법은 아닙니다. 다만 특정한 상황에서는 이러한 방법이 더 좋을 수도 있다는 점이 확인되었고 누군가는 이러한 방식을 쓰려고 하고 있고 누군가는 여전히 이 방식에 대해서 회의적입니다.
어쨌든 AtomicCSS는 각자의 방식으로 on-demand라는 방법을 통해 한단계 진화를 했고 여전히 개선할 수 있는 여지와 발전 가능성이 있습니다. CSS in JS와는 달리 StateofCSS에는 아직 섹션은 없지만 생태계는 발전중이기 한번 관심을 가지고 지켜봐주었으면 좋겠습니다.
최신 on-damand AtomicCSS!
최초의 Programming Atomic CSS Atomizer - https://acss.io/
제일 유명하지만 개인적으로 조금은 아쉬운... https://tailwindcss.com/
tailwindCSS를 그대로 사용하면서 JIT 모드를 먼저 도입한 https://windicss.org/
attribute를 이용한 자동 css https://unocss.antfu.me/
Just-in-time CSS https://asmcss.com/
MutationObserver를 이용한 VirtualCSS https://styles.master.co/
ㄴ 최근 관심을 가지고 보고 있는 중이랍니다.
"AtomicCSS is not Silver Bullet. But it is good enough."
끝으로 AdorableCSS도 많은 관심 부탁드립니다. 깃헙 이슈에 개선요구사항이나 문의사항 올려주시면 항시 대기중이며 수정하고 있습니다.
이 글이 AtomicCSS 방식에 대한 인식의 개선과 함께 그리고 CSS에 대한 유용한 정보과 인사이트가 있고 도움이 되기를 바랍니다.
감사합니다. 🥳
저희 시니어님이 저한테 자주 얘기해주시는 것 중 하나가, 어떤 것을 공부할 때 흐름을 따라가며 공부하라는 말입니다.
그래야 깊이 알 수 있으며 동시에 기억이 오래 간다고 생각합니다.
그런 맥락에서 테오님의 글은 항상 흐름을 잘 설명해주셔서 도움이 많이 됩니다.
좋은 글 감사드립니다.
그리고 Adorable css은 정말 매력적인거 같네요! 추후에 개인 프로젝트를 진행하게 되면 꼭 사용해보겠습니다(아이콘이 너무 귀여워요!)
테오는 흐름을 정말 잘 이해하고 있는 분인거 같아요. 스토리텔링은 재미있고 기억이 잘나고 왜라는 질문에 정말 효과적이죠. 그런 부분에서 테오 글을 읽고나면 참 얻어가는게 많습니다. tailwind류는 별로 좋아하지 않았는데, 이제는 쓰지 말아야할 이유가 별로 없네요 ㅎㅎ
저는 아직 scss를 주로 쓰는 편이지만 프레임워크를 공부하면서 css 컴포넌트도 작게나마 써보고 있는 중입니다. BEM, 기본 가이드 클래스를 혼용해서 쓰다보니 css 프레임워크 처럼 길어 지는 부분이 늘어 나게 되긴 하더라구요. 그리고 변수 및 svg로 백그라운드 이미지 작업 중이다 보니 scss 만한게 아직 없더라구요. for, if, var, function 등 활용할게 많아서요. 혹시 svg, png , background-image 등 이미지 컨트롤 가능 한 부분에 대한 구현이 가능할가요??
제가 퍼블리싱이다 보니 이미지 컨트롤에 대한 제어도 필요할떄가 많아서요.
역시 먼 옛날부터 현업에 몸담고 계신 시니어기에 웹의 발전과정에 대한 식견을 이렇게 풀어쓸 수 있으시군요.
포스트 잘 봤습니다. ㅎㅎ 개인적으로도 시멘틱 웹을 처음 봤을 때 의미론적 네이밍을 보고 이걸 왜 이렇게 하는지 의문점이 많았습니다. 결국 디자인에서 재사용성이 떨어지는 문제가 많았거든요. 재밌게 읽고 갑니다
테오님 안녕하세요~ 테오콘 후기를 보다가 이 글까지 정독하게 되었습니다. 왜? 라는 질문에 답을 해가며 설명하는 글은 언제나 읽기 좋고 행복한 것 같아요. 덕분에 새로운 점을 또 하나 알아가게 됐습니다. 아직은 개발을 배우고 있는 학생 입장이지만 언젠가 제 프로젝트에 한 번 사용해보고 싶네요! 잘 읽었습니다 :)
새로운 관점에서 CSS를 바라보게 하는 좋은 글입니다.
개인 프로젝트에서 tailwindcss를 사용하고 있었는데, adorableCSS도 써봐야겠어요~
(추가로, 문장 오류가 있는 부분이 있어서 말씀드립니다. "일정 크기 이상 파일이 안 커지지 않습니다.(커진다는 의미가 됨)"=>"일정 크기 이상 파일이 커지지 않습니다."로 바꿔야 하지 않을까요?)
감사히 잘 읽었습니다.
CSS-in-JS 에서 해결되지 않는 것들이 하나하나 곪아가더니 해결책이 필요하던 차에 글을 읽게되었는데,
덕분에 생각이 어느정도 정리되었습니다.
adorableCSS 한 번 사용해보겠습니다. :D
Atomic CSS에 대해 깔끔하게 정리해주신 내용 정말로 재밌게 읽고 갑니다!
프론트엔드 생태계는 매년 크게 바뀌고 있지만, 알게모르게 CSS쪽도 정말 트렌드가 빠르게 변한다고 느껴지네요.
Traditional CSS - SASS - CSS selector 방법론 / module - CSS in JS - Tailwind CSS - Atomic CSS까지
특히 웹 어플리케이션 개발이 주류를 이루고부터는 엄청난 속도로 혁신적으로 변해온거 같습니다.
저도 sass에서 부터 시작해서, styled-components, tailwind css, windicss를 거쳐 현재는 UnoCSS를 이용해보고 있었는데, 테오님의 Adorable CSS도 한번 사용해봐야겠어요!
그리고 Adorable CSS의 시그니처 아이콘이 너무 귀엽습니다 :)