TailwindCSS보다 더 나은 CSS 만들어보기(feat. figma 디자인을 자동으로 CSS로 만드는 방법)

teo.v·2023년 9월 5일
98

AdorableCSS

목록 보기
2/5
post-thumbnail

이 글에는 Figma 디자인을 CSS로 만드는 꿀팁이 있는 글입니다. TailwindCSS나 AdorbleCSS에 관심이 없어도 아주 큰 도움이 될거에요!

tailwind와 차별화된 adorable-css만의 장점을 좀 더 명확하게 명시하면 좋을 것 같습니다. #54

처음 이 프로젝트를 알게 되고 난 후 공식 홈페이지, /docs 를 읽고 나서 든 생각은 "문법만 살짝 다른 tailwind 아닌가?" 였습니다. 블로그에 작성하신 글도 인상 깊게 읽었지만 tailwind와 차별화된 adorable-css만의 장점을 언급하는 부분은 거의 없어서 아쉬웠습니다. 블로그에서 언급하신 대로 복잡한 selector나 flexbox등 이 프로젝트의 장점을 tailwind와 직접적인 비교를 통해 보여주시면 좋을 것 같습니다.

- AdorableCSS Github Issue #54

10개월이나 지나서야 제안해주신 글이 완성이 되네요. 멋진 제안을 해주신 wirekang님 너무 너무 감사드립니다!

꽤 오랫동안 컨텐츠를 모았고 이제야 정리가 되어 공개를 합니다. 그래서 이 글은 매우 깁니다. 홍보글이지만 테크와 이야기와 꿀팁도 꾸역꾸역 담았으니 CSS에 관심이 있다면 꼭 끝까지 즐겨주시기 바랍니다.


프롤로그

컨셉은 좋아보이지만 막상 사용하기에는 개인적으로는 조금은 불편함이 느껴졌던 TailwindCSS에서 영감을 받아 TailwindCSS의 문제점을 개선하여 제가 실전에서 사용하려고 AdorableCSS라는 새로운 CSS Framework를 한번 만들어보았습니다.

공식 홈페이지
https://developer-1px.github.io/adorable-css/

실제로 지금도 현업에서 사용하고 있으며 함께 쓰는 사람들은 그 편함과 좋음을 누렸지만(?) 다른 회사 사람들에게 현업에서 사용하는 것을 적극적으로 권하기에는 아직 부담이 있기에 주로 CSS에 관한 Tech를 설명하는 방식으로 함께 소개를 하곤 했습니다.

이러한 TailwindCSS와 같은 Utility-First CSS는 기존의 시멘틱한 이름을 짓고 스타일링을 하는 방식을 사용하지않고 스타일링 그 자체를 이름으로 사용하는 방법을 사용합니다.

<button class="button">Click me!</button>

<!-- traditional CSS -->
<style>
.button {
  background-color: blue;
  color: white;
  padding: 10px;
  font-weight:bold;
  padding:2px 4px;
  border-radius: 5px;
}
</style>

<!-- tailwind CSS -->
<button class="bg-blue-500 text-white font-bold py-2 px-4 rounded">
  Click me!
</button>

그 결과 CSS를 작성하지 않아도 되고, 특히 이름을 짓지 않아도 됩니다. 특히 이 이름을 .button-wrap .sidebar-inner-line 과 같이 의미가 없는 시각적인 레이아웃이나 장식등에도 일일히 고민하며 이름을 붙여야하는 수고를 하지 않을 수 있게 되었습니다. 이러한 점은 디자인으로 부터 코드를 자동생성을 해도 실전에서 사용가능한 고품질의 코드를 만들 수 있도록 해주었습니다.

TailwindCSS와 같은 Utility-First라는 컨셉이 어떠한 점이 왜 좋은지를 설명하면서 동시에 그럼에도 실전에 사용하기에는 불편하고 부족한 점이 많아 개선했다는 내용을 얘기했지만 "왜 TailwindCSS를 쓰는지 이해가 됩니다.", "이 내용을 보고 TailwindCSS를 선택하기로 했어요."와 같은 얘기들을 들으면서 정작 TailwindCSS의 홍보를 해준 것 같아 속상하기도 했습니다. (웃음)

여담이지만, 아무래도 개발세계에서 더 좋은 것 보다는 많이 알려져서 다같이 배우고 다같이 쓰이는게 라이브러리 선택에 중요한 점인데 지금은 CSS의 방향성조차 React를 중심으로하는 CSS in JS가 주류가 되어가다보니 다른 프레임워크와 다른 CSS들이 묻혀가는게 아쉬웠습니다.

그렇기에 결을 같이 하는 TailwindCSS의 위상이 CSS에서는 상당히 올라왔다는 점에서 고무적이면서도 Just in time Atomic CSS 라는 카테고리에서는 다른 대체제없이 계속 TailwindCSS만 쓰이고 있는데 이제는 너무 많이 쓰고 있기에 TailwindCSS가 스스로 단점들을 개선하기에는 쉽지 않을 것 같아 실험적으로 더 나은 Atomic CSS Framework을 만들어보고자 했습니다. (자세한 이야기가 궁금하시다면 아래 글도 한번 읽어보세요)

어쩌다 AdorableCSS를 만들게 되었나?
https://velog.io/@teo/adorable-css

CSS의 역사부터 Atomic CSS 까지, 그리고 AdorableCSS!
https://velog.io/@teo/adorableCSS

최초 설명하는 단계에서는 JIT(Just-in-time) 라고 하는 기능이 가장 중요한 차별화 Feature였기에 이것만을 중점으로 설명을 했으나 TailwindCSS도 3.0 부터는 이제 JIT가 기본기능이 되어있기에 이러한 설명만으로는 그 이면에 있는 더 큰 장점들을 설명하는 컨텐츠가 부족했다고 생각이 들었고 그러한 내용을 제보해주셨습니다.

그래서 이 글에서는 TailwindCSS의 어떤 점을 불편하게 느꼈고 그래서 어떤 차별화를 통해서 AdorableCSS는 어떻게 개선하고자 했는지 다른 관점들의 이야기를 해보고자 합니다.

특히 Figma 디자인을 자동으로 코드로 만들어주는 플러그인을 만들면서 느꼈던 이야기들과 함께 디자인을 CSS로 만드는 마크업 팁도 함께 소개해드리고자 합니다.

📌 이 글은 AdorableCSS의 장점을 소개하고자 하는 글이지만, 일방적인 홍보글이 되지 않고 읽는 재미와 보람을 느낄수 있도록 여러가지 CSS 테크 개념과 팁들을 함께 담고자 노력했습니다.

JIT Atomic CSS FrameworkFigma to CSS, Figma 디자인 개념 라고 하는 키워드를 중심으로 AdorableCSS를 선택하지 않도록 충분히 도움이 될만한 글이 되어줄거라고 생각합니다.


TailwindCSS와 HandOff

호랑이 담배피던 시절의 웹 개발 퍼플리싱은 그냥 이미지만 전달을 받거나 일부 가이드를 정도 그려준 이미지를 통해서 CSS를 한땀한땀 다 만들어야 했습니다. 반면 디자이너가 힘이 없는 회사는 가이드 수준을 엄청 요구해서 디자이너들이 죽어나던 시절도 있었죠.

퍼블리싱이 쉬운 일이 아닌데 시간은 상당히 많이 들어가는 일인데 반해 진입장벽은 낮아서 대체가능한 인력이 많다보니 비싼 일도 아니었습니다. 그렇지만 디자이너는 가이드를 만드느라 수정된 부분을 찾아내느라 전체가 다 바뀌면 일일히 이미지 다 교체하느라 잔일에 시간을 정말 많이 잡아먹던 일이었습니다.

이러한 요구사항에 힘입어 스케치, 제플린, figma와 같은 UI 디자인 전용툴과 디자인 HandOff 툴이 발전하면서 이러한 불편함을 해소하면서 퍼블리싱의 생산성은 더 높아졌습니다.

그리고 이러한 도구들의 발전으로 인해서 더 쉬워지는 것을 넘어, '디자인을 자동으로 HTML+CSS코드로 뽑아줄 수 없나?' 하는 생각으로 Figma to Code와 같은 자동 코드 생성도구 들이 만들어지고 연구되기 시작했습니다.

저 역시 이러한 방법들을 시도하고 연구해보면서 디자인을 코드로 자동화를 하는 Figma 플러그인등을 만들면서 생산성을 높이고자 해보았습니다.

if(kakao) 2021 : Functional CSS와 Figma를 이용한 디자이너와의 웹프론트 협업이야기
여기에서 언급했던 figma 플러그인에 대한 이야기가 잠깐 나옵니다.
https://www.youtube.com/watch?v=Mu_yTinxtHM

일부 디자인을 미리 CSS로 변환하여 힌트식으로 보여주는 경우는 유용하나, 디자인전체를 코드로 생성하는 경우에는 아직은 대부분 코드의 품질이 아직은 그다지 좋지 않습니다.

Auto Code Generator의 품질이 나쁜 이유

디자이너가 만든 디자인을 그대로 기계적으로 코드로 생성하는 경우에는 다음과 같은 부분들이 문제가 됩니다.

  1. 디자이너에게는 선과 네모, 간격들이지만 개발자에게는 컴포넌트 단위의 개념과 각각의 이름이 필요하다.
  2. 디자이너는 절대좌표와 절대크기로 그려내지만 개발은 반응하는 상대크기가 필요하다.
  3. 디자이너에게는 그림이지만 개발에게는 구조와 컴포넌트가 필요하다.

자동생성된 코드에서의 이름짓기 문제

일반적으로 코드를 자동으로 생성하면 다음과 같은 형태가 만들어집니다. 코드를 들여다보면 Frame33, Text, Image42 와 같이 미처 정리되지 못한 이름들을 자주 만날 수 있게 됩니다.

<!--- 블로그 가독성을 위해서 CSS는 1줄로 정리했습니다. -->
<style>
.ReplyMsg {align-self:stretch; display:flex; flex-flow:row; align-items:center; justify-content:flex-start; padding:12px 12px 0; background:#f2f5f7;}
.ItemReply {flex:1; display:flex; flex-flow:row; align-items:flex-start; justify-content:flex-start; gap:8px;}
.Frame33 {flex:1; display:flex; flex-flow:column; align-items:flex-start; justify-content:flex-start; gap:2px;}
.Text {align-self:stretch; font-size:13px; line-height:16px; font-weight:700; font-family:'Noto Sans KR'; color:#141414; }
.Text {font-size:13px; line-height:16px; font-family:'Noto Sans KR'; color:#141414; max-width:100%; overflow:hidden; display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:1px; opacity:.5;}

.Character {
  position:relative;
  flex-shrink:0;
  width:24px;
  height:24px;
  border:1px solid #00000014;
  border-radius:99px;
  overflow:hidden;
}

.Image42 {
  position:absolute;
  left:0px;
  top:0px;
  width:24px;
  height:24px;
  border-radius:100%;
}
</style>

<!-- 아래처럼 Image42, Frame33, Text등 이름이 지어지지 않은 코드들이 생기기 마련이다. -->
<div class="ItemReply">
  <div class="Character">
    <img class="Image42">
  </div>
  <div class="Frame33">
    <div class="Text">제목입니다.</div> <!-- 심지어 다른 스타일인데 이름이 같다 -->
    <div class="Text">설명 설명</div>
  </div>
</div>


<!-- Styled 느낌은 이런식 -->
<ItemReply>
  <Character>
    <Image42>
  </Character>
  <Frame33>
    <Text>제목입니다.</Text>
    <Text>설명 설명</Text>
  </Frame33>
</ItemReply>

이게 짧게 보면 이정도는 괜찮지 않나 싶겠지만, 제가 예시를 일부만 가져와서 그렇지 실제로 디자인을 코드로 자동생성해보면 이게 무엇인지 어떻게 써야할지 힘든 가독성이 떨어지는 코드가 됩니다.

자동으로 생성하는 코드인데도 가독성이 필요한 까닭은 단순히 디자인과 똑같은 결과를 만든다고 해서 끝이 아니라 결국 코드 위에 비지니스 로직과 동적인 디자인을 아직은 개발자가 입혀야 하기 때문이죠.

이러한 모호한 이름들은 개발자의 입장에서는 쓰기 곤란한 품질이 낮은 코드가 됩니다. var temp, var tt2929 와 같은 의미가 불분명한 코드는 유지보수 관점에서는 사용하면 안되는 코드니까요.

디자인을 코드로 만드는 것은 누구의 역할일까?

이를 해결하기 위해서는 디자이너가 처음부터 빠짐없이 요소하나하에 좋은 이름을 붙이고 좋은 구조를 계속 유지 하도록 해야하는데 현실에서 쉽지는 않습니다. 같은 이름인데 디자인이 다른경우도 종종 발생하기에 관리를 해야하겠죠.

왜냐하면 디자이너에게 완벽한 이름짓기가 주요 기대역할이 아니기 때문입니다. 애매한 장식들의 이름을 적절히 짓는다는 것은 상당히 괴로운 일입니다. 뿐만 아니라 디자인을 코드로 만들었을 어떤 것들이 더 나은지를 이해하기 위해서는 상당히 개발적 지식과 감각을 요구하는데 디자인과 개발을 동시에 잘하는게 쉽지 않은 일이죠. 코드를 잘 만들어내는 것은 여전히 개발자의 몫입니다.

현대에 와서는 이러한 개념인 디자인 시스템을 만들어내는 것을 디자이너와 개발자들이 함께 만들어야 하는 것로 규정하고 플랫폼의 형태로 만들려고 하는 시도들은 있으나 일반적인 디자인 모두에게 이러한 것들을 디자인 단계에서 전부 요구하는 것은 아직은 무리인 상황입니다.

TailwindCSS에서 가능성을 본 점

TailwindCSS의 컨셉은 이름을 별도로 짓지 않고 시각적인 정보를 그대로 이름으로 사용하기에 디자이너가 이러한 이름을 관리를 하지 않더라도 실무에서 사용이 가능한 코드를 만들어 줄 수 있다는 점에서 괜찮다고 생각했습니다.

또한 컨텐츠를 다룰때에도 Style(CSS)와 Component(HTML)를 두벌로 관리하지 않고 HTML혹은 JSX내부에서만 다루면 되기 때문에 관리의 범위가 줄어드는 것도 좋아보였습니다.

<!-- 이름을 표기한 주석은 가독성을 위해 달아둔 부분입니다. -->

<!-- Item / Reply -->
<div class="flex-1 flex flex-row items-start justify-start gap-[8px]">

  <!-- Character -->
  <div class="relative shrink-0 w-[24px] h-[24px] border-[1px_solid_#00000014] rounded-[99px] overflow-hidden">
    <!-- Img -->
    <img class="absolute left-[0px] top-[0px] w-[24px] h-[24px] rounded-full" src="profile.img"></img>
  </div>
  
  <!-- Frame 33 -->
  <div class="flex-1 flex flex-col items-start justify-start gap-[2px]">
    <!-- Text -->
    <div class="self-stretch text-[13px] leading-[16px] font-bold font-['Noto_Sans_KR'] text-[#141414]">제목입니다.</div>
    <!-- Text -->
    <div class="text-[13px] leading-[16px] font-['Noto_Sans_KR'] text-[#141414] max-w-[100%] overflow-hidden -webkit-box -webkit-box-orient-[vertical] -webkit-line-clamp-[1px] opacity-[.5]">설명 설명</div>
  </div>
</div>

<!-- Text의 이름이 같더라도 상관없이 디자인을 중심으로 표기할 수 있다. -->

💡 꼭 Tailwind가 아니더라도 최근에 와서는 Chakra UI와 같이 Box, HStack, Text와 같이 시멘틱한 이름기반이 아니라 시각적인 구성을 기반으로 하는 방식들이 늘어나고 있고 이런 방식들이 나쁜 것들은 아니다라는 인식은 이제 충분히 생긴것 같습니다.

정확히는 이제는 시각적인 구성이 시멘틱보다 더 낫다가 아니라 의미부여와 중복방지를 위해 시멘틱이 필요하지만 모든 것을 시멘틱으로 만들어야 할 필요는 없다. 정도로 생각하면 좋을 것 같습니다.

이렇게 시작적인 이름기반으로 코드를 작성하는 방식들은 자동으로 코드를 생성했을때 시멘틱에 비해 상대적으로 더 적은 노력으로 더 나은 품질의 코드를 생성할 수 있습니다. 왜냐하면 이러한 시각적 기반 작성 방식은 자동화된 코드의 형태와 실제로 작성하는 코드의 차이를 최소화하기 때문입니다.

그럼에도 TailwindCSS가 별로인 이유

"TailwindCSS는 HTML이 너무 지저분해져서 싫어요."

TailwindCSS를 좋아하지 않는 사람들이 말하는 Tailwind의 단점의 1위를 꼽자면 바로 "더러운(?) HTML이 만들어진다라는 것" 입니다.

왜 그럴까요? 기본적으로 CSS 속성과 1:1 매칭으로만 거의 구성이 되어있다보니 inline-style보다 더 적게 작성을 하더라도 이미 너무 많은 코드를 class에 작성해야하만 합니다.

심지어 완벽하게 1:1도 아니라서 애매하게 배워야 하는 허들이 있으며 JIT 개념이 있기 전에 만들어져서 w-4 가 16px인 것은 상당히 코드를 덜 직관적으로 보이게 만듭니다.

디자인을 코드로 옮기는 것을 도와줄 뿐, Figma 자체로 완벽한 프로그램을 만들어 내는 것이 아니기에 결국 개발자가 계속 보고 사용해야 하는 코드를 만들어내야 하므로 조금 더 가독성이 있는 코드를 만들어 내고 싶었습니다.

AdorableCSS: 어떻게 더 간결하고 배우기 쉬운 문법으로 만들수 이을까?

TailwindCSS로 개발을 하면서 불편함을 몸으로 체감해보고나니, 다음 4가지 문제는 꼭 더 낫게 만들어야겠다고 생각을 했습니다.

TailwindCSS의 단점들
1. class가 너무 지저분하고 길어진다.
2. CSS와 1:1매칭이 아니라서 애매한 학습허들이 존재한다.
3. CSS의 모든 기능을 완벽하게 지원하는 게 아니다.
4. HTML와 CSS간의 스위칭이 없고 이름짓기 문제가 없어 UI를 만드는 일이 빨라지지만, 그렇다고 더 쉬워지는 건 아니다. (결국 CSS와 다를게 없다.)

그래서 다음과 같은 목표로 문법을 만들기 시작했습니다.

AdorbleCSS의 목표
1. 깔끔하고 가독성이 있는 문법을 제공하면서
2. 학습허들을 최소화하고
3. CSS의 모든 기능을 지원하면서
4. UI를 더 쉽고 직관적으로 만들 수 있는 방법을 제공하자!

여러가지 시행착오를 겪으며 마크업 개발자분들의 자문을 얻어가며 현재는 아래와 같은 사고의 흐름을 통해서 큰 문법의 틀을 잡게 되었습니다.

1. 모든 CSS를 쓸 수 있어야 한다.
<div style="position: absolute; top: 0; margin: 0 20px; color: #f00; font: 18px/1.5 bold;"></div>

2. 클래스로 바꿔보자. 클래스는 띄어쓰기를 쓸 수 없으니 /로 구분하자.
<div class="position:absolute; top:0; margin:0/20px; color:#f00; font:18px/1.5/bold;"></div>

3. 값에 대한 가독성이 떨어지니 :; 대신 ()로 바꾸자.
<div class="position(absolute) top(0) margin(0/20px) color(#f00) font(18px/1.5/bold)"></div>

3. 뻔한 값(bold, absolute, px)등은 제거해서 타이핑을 줄이자.
<div class="absolute top(0) margin(0/20) color(#f00) font(18/1.5) bold"></div>

4. 더 극단적으로 줄여볼까? 예측이 되는것도 있고 그렇지 않는것도 있구나. 학습비용 최소화!
<div class="abs t(0) m(0/20) c(#f00) f(18/1.5) b"></div>

- 1) 1~2글자로도 예측이 가능한 속성만 줄여서 쓴다.
<div class="w(32) h(32) r(8) p(10/16) b(#480ff) m(4/8/10/12) z(9999) bg(#000) c(#fff)"></div>

- 2) 원래 CSS Keyword는 수정없이 그대로 유지하자.
<div class="relative inline-block bold underline hidden none"></div>

5. mt-10과 같이 이미 줄여서 쓰고 있는 것들만, 줄였을때 의미훼손이 되지 않을것들만 줄이자.
<div class="absolute y(0) m(0/20) c(#f00) font(18/1.5) bold"></div>

6. 그 밖에 
c(--primary) -> color(var(--primary): CSS Variable 지원
rgba(255, 255, 255, .5) -> #fff.5와 같은 더 쉽고 단순한 hexa color포맷 지원

CSS의 모든 기능을 제공하기 위해서, CSS의 문법에 맞는 기능을 1:1으로 대응하는 Rule을 세팅하되 기존 CSS와 최대한 유사한 문법을 제공하여 CSS의 모든 기능을 사용할 수 있도록 만들어 보았습니다.

1. prop: value; -> prop(value)로 모든 CSS속성 지원
<div class="-webkit-line-clamp(2) user-select(none)"></div>

2. !important; -> !
<div class="color(red)! color(blue)"></div>

3. Selector: -> &를 통해 모든 Selector 지원, 띄어쓰기가 안되어 하위선택자는 >>로 대체
<div class="&.selected:c(red) selected"></div>
<div class="&>a:hover:underline"><a>link</a></div>
<div class=":nth-child(2n+1):bg(#000.2)">:nth-child 등도 가능</div>

4. @ Rule: Media Query, Dark Mode 등 
<div class="@w(1280~):none"><a>1280이상에서는 안보이도록</a></div>
<div class="~lg:none">lg 크기이하</div>
<div class="dark:c(#fff)">다크모드</div>

과도기를 가진채로 외부에 공개가 되어 수정에 제약이 많은 TailwindCSS에 비해 쓰는 사람이 저를 비롯한 주변사람이 전부였던 터라 여러가지 문법을 실험해보고 문법을 다듬기가 용이했습니다.

그리하여 AdorableCSS는 TailwindCSS보다 훨씬 더 직관적이고 일관적인 문법을 만들 수가 있었고 더 낮은 학습곡선보다 직관적이면서도 더 풍부한 기능과 성능을 제공할 수 있었습니다.

그렇지만 이정도의 특징만으로는 이미 유명세가 있고 많이 사용하고 있고 또한 관련 컨텐츠가 많은 TailwindCSS에 비해 외부에 전달하는 설명만으로는

... 읽고 나서 든 생각은 "문법만 살짝 다른 tailwind 아닌가?" 였습니다. ...

라고 할 수 있을 정도로 문법측면에서만 살짝 더 나아진 정도의 더 쉬워진 프레임워크로로 인식될만큼 큰 차별화를 말하기는 어려웠습니다.

왜냐하면 이렇게 만들어진 AdorableCSS를 쓴다고해도 당장은 TailwindCSS보다 더 드라마틱하게 class의 코드량이 줄지는 않았기 때문에 복잡해지는 class와 다른 UI Framework와 달리 더 쉽게 UI를 만드는 방법은 제공하지 않은채로 결국 CSS를 잘 알아야만 잘 쓸 수 있다는 단점은 여전히 가지고 있었기 때문입니다.

Figma에서 답을 찾다! 💡

어쨌든 TailwindCSS에서 영감을 얻고 AdorableCSS를 만들어야겠다고 느낀 것은,

  1. Figma의 Plugin을 자체적으로 개발을 할 수 있을만큼 자유도가 높아서,
  2. 디자인을 자동으로 코드로 만들어낼수 있겠다는 생각이 들었는데,
  3. TailwindCSS와 같이 Utility First 기반의 CSS는 자동으로 생성해도 실제 코드와 동일한 품질의 코드가 나오기에,
  4. JIT 기능을 붙여서 딱 맞는 CSS를 뽑아내고자 함이었습니다.

그리고 이러한 플러그인을 만들면서 Figma의 디자인을 어떻게 하면 CSS로 뽑아내야 하는지를 분석하면서 왜 CSS 코드가 길어지는지 알 수 있게 되었습니다.

Figma 디자인 개념은 CSS보다 단순하지만 더 강력하다.

Figma가 UI 디자인 프로그램의 1등이 된 이유는 웹기반의 동시 편집가능이라는 협업을 중시하는 말도 안되는 차별화 기능도 있지만 본질적으로 UI 디자인 툴이 갖춰야할 잘 만들어진 디자인 개념에 입각한 속성과 기능이라는 측면에서도 figma는 너무나 월등합니다.

figma는 협업을 강조하기에 디자인을 개발로 옮기는 과정 또한 협업의 workflow로 인식하고 있으며, 단순히 절대적인 디자인을 그리는 것이 아니라 반응형으로 디자인을 할 수 있도록 AutoLayout, Fixed/Hug/Fill Size, Min-Max Size, Constranints, Layout Grid 등 상당히 "Design in dev-friendly systems" 한 디자인 개념을 제공합니다.

무엇보다 이러한 Figma의 디자인 개념과 제공하는 인터페이스들은 CSS의 속성보다 훨씬 더 직관적이며 적은 속성으로도 실무에 필요한 대부분의 디자인을 만들어내는데 손색이 없을 정도입니다.

어차피 배워야 한다면 Figma를 배우게 하자.

학습곡선을 늘리고 싶지는 않았지만 더 편리한 기능을 제공하기 위해서는 새로운 기능을 만들어야하고 이러한 기능의 제공은 다시 학습곡선을 높이는 딜레마를 가져오게 만듭니다.

맨땅에서 CSS를 해야하는 경우도 있겠지만, 우리는 대부분 디자이너가 만들어주는 결과물을 HTML과 CSS로 마크업을 하는 작업을 하게 됩니다. 그리고 대부분의 경우 그 결과물은 이제 figma일거라고 생각합니다.

figma가 가지고 있는 디자인의 개념은 훨씬 더 간단하지만 더 직관적기이에 figma가 제공해주는 기능을 그대로 제공을 한다면 훨씬 1)더 적은양의 코드2)직관적인 표기 그리고 3)강력한 기능을 제공해 줄거라고 생각했습니다.

Figma의 디자인 개념을 CSS로 만들고 AdorableCSS로 만들어보자!

Figma의 디자인 개념을 CSS로 만들어내는 과정Figma의 개념과 속성을 어떻게 더 직관적으로 보여줄지를 고민하면서 AdorableCSS의 문법들을 만들어 보았습니다.

다음 글에서는 이러한 과정을 소개하면서 TailwindCSS에 비해서 AdorableCSS는 어떻게 더 나은 문법을 제공하는지를 설명하면서 차별화와 장점을 어필해보고자 합니다.

꼭 AdorableCSS가 아니더라도 Figma의 디자인 개념을 이해하고 CSS로 바꾸는 것에 대해서 공부하면서 정말 중요한 CSS가 무엇인지 역으로 알 수 있는 시간이 되었습니다. 모든 CSS를 다 사용하지 않고 Figma의 디자인을 만들어내는 CSS만 잘 다룰 줄만 알아도 최소 CSS로 피그마로 만들어진 모든 디자인을 만들어 낼 수 있다는 의미가 됩니다.

그러니 다음 내용은 AdorableCSS뿐만 아니라 다른 프레임워크를 쓰고 있더라도 디자인을 코드로 만들어내는 과정에 대한 많은 인사이트를 얻어 갈 수 있으리라 생각합니다.


Figma to CSS

Figma의 디자인 개념들을 CSS로 만들어보고 다시 TailwindCSS와 AdorableCSS로 만들어가는 모습을 보면서 어떤식으로 더 간결하고 직관적으로 작성할 수 있는지 알아보고자 합니다.

CSS와 관련된 Figma의 주요 디자인 개념들

  1. AutoLayout
  2. Fixed/Fill/Hug Size, Min-Max Size
  3. Position & Constraints
  4. Text Align
  5. Text Truncate

1) Auto Layout

전통적인 디자인 이미지와 마크업 개발을 통해서 만들어진 결과물의 결정적인 차이는 반응형 디자인에 있습니다. 인쇄로부터 출발한 디자인은 절대크기와 절대좌표를 기반으로 디자인을 만들면 되지만 웹이나 앱에서 사용되는 디자인은 디스플레이의 크기가 포함하는 컨텐츠가 변화할 수 있기 때문에 같은 디자인을 표시하더라도 디스플레이의 크기나 컨텐츠의 양에 맞게 적절히 위치와 크기가 가변적으로 조정 되어야 합니다. 가령 크기가 고정된 상태로 글의 내용이 많아진다면 그 글이 프레임밖으로 삐져나와 잘려보이거나 다른 영역을 침범할테니까요.

이렇게 겹치지 않게 적절히 자동으로 컨텐츠를 배치할 수 있는 Layout을 만들기 위해서 여러가지 디자인 개념들이 고안되었는데 CSS에서서는 Flexbox가 가장 대표적인 이러한 Layout의 개념이라고 할 수 있습니다. 이러한 개념은 ios의 Stack이나 andorid의 LinearLayout, Compose의 Row와 Column등으로도 많이 제공이 되고 있습니다.

Figma 역시 이러한 컨텐츠를 가변적으로 배치를 도와줄 수 있는 디자인 개념을 Auto Layout 이라는 이름으로 제공을 하고 있습니다. 우리는 Figma의 Auto Layout 개념을 이해하고 CSS의 Flexbox로 변환을 해보려고 합니다.

Figma의 디자인 개념을 알고 있으면 좋은 이유!

Figma를 기반으로 디자인을 이해하면 좋은 것은 Figma가 웹뿐만 아니라 앱과 다른 디자인도 고려하면서도 정말 최소한의 UI와 개념으로 반응형 디자인을 할 수 있도록 정말 많은 생각을 해서 만들어놓은 결과물이라는 점입니다.

때문에 CSS의 어려운 점 중에 하나인 '같은 화면을 만들기 위해서 너무 많은 방법이 존재한다.'라는 점에서 Figma가 제시하는 개념으로만 CSS를 사용해도 대부분의 디자인 결과물을 만들 수 있기에 Best Practice로 삼을 수 있다는 점에서 매우 유용합니다. 또한 이러한 개념이 웹에만 한정되는 것이 아니라 앱이나 다른 디자인에 대한 개념까지 확장할 수 있다는 점에서도 좋습니다.


Figma

우선 AutoLayout을 구성하는 UI Panel을 살펴보면서 어떤 개념으로 구성이 되어있는지 알아봅시다.

Figma Auto Layout 공식문서

https://help.figma.com/hc/en-us/articles/360040451373-Explore-auto-layout-properties#Layout_flow

Figma의 AutoLayout은 Flow, Alginment, Spacing, Resize 라고 하는 큰 줄기의 개념으로 기본은 다음과 같은 4가지로 구성이 되었습니다.

  1. 방향
  2. 배치
  3. 컨텐츠 간격
  4. 패딩

1. 방향 (가로, 세로, 줄바꿈)

Vertical Layout Horizontal Layout Wrap

2. 배치 (9방향)

Algin(Top/Middle/Bottom + Left/Center/Right)

3. 간격

gap: 8px gap: Auto

4. 패딩

padding-left padding-top padding-right padding-bottom

이미지를 통해서 각 역할에 따라 어떻게 컨텐츠가 배치가 되는지 한번 이해해보세요. 실제로 Figma를 이용해서 수치를 건들여보면서 해보는 걸 추천드립니다. 눈으로 어떤 속성으로 인해 어떻게 컨텐츠가 배치가 되는지 이해한다면 훨씬 더 큰 도움이 됩니다.


CSS

Figma의 AutoLayout은 CSS의 Flexbox로 구현할 수가 있습니다. Figma의 AutoLayout은 CSS와 다음과 같이 매칭하여 적용할 수 있습니다.

.AutoLayout {
  /* 1. Use AutoLayout */
  display:flex; 

  /* 2. Flow */
  flex-flow:row; /* or column, wrap */
  
  /* 3. Alginment */
  align-items: flex-start; /* or center, baseline, flex-end */
  justify-content: flex-start; /* or center, flex-end */

  /* 4. Gap */
  gap:8px;
  /* or */ justify-content: space-between; /* gap: Auto */

  /* 5. Padding */
  padding: 10px 20px 30px 40px; /* top right bottom left */
}

TailwindCSS

이러한 AutoLayout 속성을 TailwindCSS로 옮겨보면 다음과 같은 모양의 코드들이 만들어지곤 합니다.

<div class="flex flex-row align-start justify-start gap-[10px] pt-[10px] pr-[20px] pb-[20px] pl-[20px]"></div>

<div class="flex flex-col align-end justify-between p-[10px]"></div>

TailwindCSS 뿐만 아니라 CSS를 할 때 가장 헷갈리는 부분이 바로 row|col 그리고 align-*justify-*의 개념이라고 생각을 합니다. 개념만 놓고 하나씩 이해를 하는 것이 어렵진 않지만 가로방향과 세로방향에 따라서 alignjusify의 개념이 달라지고 추후 grid와 함께하면 align-itemsalign-content의 역할이 어떻게 다른지 많이 헷갈리게 하고 코드가 복잡해보이는 이유라고 생각을 했습니다.

그래서 이러한 부분을 최대한 Figma에서 제공하는 개념과 유사하게 문법을 만들어보고 싶었습니다.

AdorableCSS

1) flex-row|flex-col|flex-wrap -> hbox|vbox|wrap

저는 이라는 rowcolumn보다는 가로세로라는 horinontalvertical이라는 용어가 훨씬 더 시각적이고 직관적이라고 생각했습니다. 따라서 방향성의 앞글자인 hv와 함께 flexbox의 명칭을 합해서 hbox, vbox 라고 명명을 하였습니다.

<div class="hbox"></div>
<div class="vbox"></div>
<div class="wrap"></div>

2) align-*|justify-* -> top|middle|bottom + left|center|right

Figma에 있는 9개의 방향성 개념을 그대로 제공하고 싶었습니다. 그래서 다음과 같이 방향성을 표기하면 각 레이아웃 방식에 맞게 적절히 align과 justify를 만들어주고자 하였습니다.

<div class="hbox(top+left)"></div>
<div class="vbox(bottom+center)"></div>
<div class="wrap(middle+right)"></div>

3) justify-between -> gap(auto)

또한 Figma에서 표현하는 gap(auto)space-between이 될 수 있도록 하여 gap을 통해서만 표현을 할 수 있도록 하였습니다.

또한 figma의 gap:Auto 의 경우 컨텐츠가 하나밖에 없다면 가운데 정렬을 하도록 되어 있습니다. 이러한 부분 역시 스펙으로 반영하여 gap(auto)를 justify-between보다 더 적은 코드더 더 직관적으로 사용할 수 있도록 하였습니다.

.gap\(auto\) { justify-content:space-between; align-content:space-between; }
.gap\(auto\)>:only-child { margin:auto; }

4) AutoLayout와 AdorableCSS

그리하여 AutoLayout을 사용하는 Frame의 경우, 다음과 같이 TaliwindCSS에 비해 간결하고 더 직관적인 형태의 코드를 제공할 수 있게 되었습니다.

<!-- TailwindCSS -->
<div class="flex flex-row align-start justify-center gap-[10px] pt-[10px] pr-[20px] pb-[20px] pl-[20px]"></div>

<!-- AdoarbleCSS -->
<div class="hbox(top+center) gap(10) p(10/20/30/40)"></div>

2) AutoResize: Fixed width, Hug contents, Fill container + Min~Max Width

반응형 디자인에서는 절대좌표과 절대크기 대신 컨텐츠나 컨테이너에 맞게 자동으로 크기와 위치가 조절이 되는 것이 핵심이라고 했습니다. 그렇기에 크기를 지정하는 width와 height의 값이 특정한 값 뿐만 아니라 적절한 값이 될 수 있도록 하는 것이 필요합니다.

width와 height의 경우 figma는 다음과 같이 3가지로 구분합니다.

Fixed width
: 수치를 입력하면 입력한 크기를 가집니다.

Hug contents
: 글자나 이미지등 내부에 속한 컨텐츠의 크기를 따라갑니다.

Fill container
: 부모의 크기를 따라갑니다.

CSS에서는 각 경우마다 조금의 사정들이 있습니다.

width: fixed

Fixed width는 간단합니다. width: 320px와 같이 그냥 width에 값을 넣어주면 됩니다.

한 가지 특수한 상황이 있다면 display: flex; flex-flow: row; 인 컨테이너의 컨텐츠들은 width: 320px과 같이 특정한 값을 지정하더라고 flexbox의 기본특성인 컨테이너가 스스로 크기를 조절한다는 성격과 flex-shirink의 기본값이 1로 설정되어 자리가 부족하면 스스로 크기를 줄이도록 되어 있습니다.

따라서 간혹 내가 특정한 지정한 크기를 지정했음에도 해당 크기보다 작게 출력이 되는 경우가 있습니다. flexbox에서는 정확한 크기를 지정하기 위해서 flex-basis 라고 하는 속성을 고려해볼 수 있습니다. 그렇지만 이 속성은 width가 아니라 flexbox의 메인축 이기에 flex-basis가 경우에따라 width에도 height에도 적용이 될 수 있습니다. 따라서 이 경우에는 flex-basis를 쓰기보다는 flex-shirink:0 을 이용해서 지정된 width의 크기가 가변이 되지 않도록 해야 Figma 디자인 개념과 동일하게 설정을 할 수 있습니다.

.fixed-width-320px {
  flex-shirink:0;
  width:320px;
}

width: hug-contents 을 만들기 위해서는,

CSS에서 width의 기본값은 width: auto 입니다. CSS에서 width: auto는 상황에 따라서 각기 다른 성격을 가집니다.

width:auto의 상황별 변화
1. Normal Flow에서의 block 엘리먼트의 width: auto는 부모 블록의 크기를 따라가며 패딩과 보더를 제외한 나머지 영역을 가득 채우는 것으로 합니다.
2. Flexbox 내에서 width: auto의 경우에는 기본적으로 컨텐츠를 크기를 따라가도록 되어 있습니다.
3. 단, Flexbox의 컨테이너의 속성이 flex-flow:column; align-items: stretch 등으로 stretch 라면 컨테이너 크기를 따라갑니다.
4. position:absolute 혹은 inline 이라면 컨텐츠를 따라가도록 되어 있습니다.

Figma의 경우 Hug는 AutoLayout에서만 발생하고 Figma의 AutoLayout은 stretch 라고 하는 개념이 없으므로 width: auto 속성만으로도 충분히 Hug를 표현할 수 있기 때문에 특별히 다른 조치를 하지 않아도 됩니다.

다만 강제로 width: hug 속성을 지정해야한다면 CSS의 width:max-content 속성을 통해 지정할 수가 있습니다. width:max-content 속성은 상황과 관계없이 항상 컨텐츠의 크기를 따라가도록 할 수 있습니다.

.width-hug {
  width: max-content;
}

width: fill-container 를 만들기 위해서는,

CSS로 figma의 fill-container을 표현하기 위해서는 다음과 같은 상황들을 고려해야합니다.

  1. 부모가 block element라면 width: auto 로 가능합니다.
  2. 부모가 row flexbox라면 flex:1이 필요합니다.
  3. 부모가 column flexbox라면 align-self:stretch가 필요합니다.

각 경우에 맞는 적절한 CSS를 작성하면 width: fill-container에 대응할 수 있습니다.

3) Min width, Max width

그리고 최소, 최대 너비와 높이를 조절하여 원하는 적절한 크기의 범위를 지정할 수 있습니다.

CSS에서는 1:1로 대응하는 min-width max-width 개념이 존재하므로 해당 코드로 간단히 입력을 할 수 있습니다.

Height는 반대의 개념이니 따로 적지는 않겠습니다.

CSS

종합해보자면 CSS의 width(or height)를 Figma의 개념으로 다루기 위해서는 다음과 같은 템플릿 내에서 적절한 값을 조립하여 사용할 수 있습니다.

.width-something {

  /* 1. Fixed width */
  flex-shirink: 0;
  width: 300px;

  /* 2. or Hug contents */
  /* width: auto; */
  width: max-content; /* force */

  /* 3. or Fill Container */
  flex: 1; /* 메인축 */
  /* or */ align-self: stretch; /* 교차축 */

  /* 4. Min Width, Max Width */
  min-width:100px;
  max-width:600px;
}

TailwindCSS

TailwindCSS의 경우, 이러한 개념들을 조립해서 적절히 대응되는 TailwindCSS의 속성을 입력하여 작성을 할 수 있습니다.

<div class="flex flex-row align-center gap-[20px]">
  <div class="shrink-0 w-[32px] h-[32px]"></div>
  <div class="flex-1">Title</div>
  <div class="w-max min-w-[100px] max-w-[300px]">Button1</div>
  <div class="flex-1 self-stretch">Button2</div>
</div>

AdorableCSS

AdorableCSS의 경우는 Figma을 기반으로 조금 더 시각적이고 직관적인 형태의 코드를 작성할 수 있도록 하여 코드만 보고도 어떤 모습일지 상상하기가 쉽도록 만들어보았습니다.

w(hug), w(fill) 속성을 추가해서 hug contents와 fill container를 지원할 수 있도록 하여 내가 조건에 맞는 CSS 속성을 고민하기 보다는 직관적이고 시각적인 표현을 사용할 수 있도록 하였습니다.

min-width, max-width의 경우 min-x(30), min-w(50%)도 지원하지만 조금 더 시각적으로 표기할 수 있도록 w(30~), w(~50%), w(30~50%) 이런식의 표기도 지원을 하고 있습니다.

<!-- AdorableCSS는 코드만 보아도 어떤 모양인지 쉽게 상상할 수 있는 것이 목표! -->

<div class="hbox gap(20)">
  <div class="w(32) h(32)"></div>
  <div class="w(fill)">Title</div>
  <div class="w(hug) w(100~300)">Button1</div>
  <div class="w(fill) h(fill)">Button2</div>
</div>

AutoLayout: Advanced auto layout settings

1) 음수 Gap

CSS에서는 음수 gap는 지원하진 않지만, 겹쳐서 표기하는 아바타 프로필 같은 디자인에 따라 필요할 수도 있다. Figma에서는 음수 gap을 공식적으로 지원을 하고 있다. 이건 CSS로 어떻게 구현을 하면 좋을까?

전통적인 CSS에서는 간격표기를 margin 을 통해서 해왔다. margin의 경우 컨테이너 내부의 갭이 아니라 컨텐츠를 중심으로 작성하는 간격이기 때문에 자식 컨텐츠에 전부 margin을 추가하면 gap처럼 만들기 위해서는 아래 그림처럼 첫번째 컨텐츠에도 margin이 적용이 되기 때문에 의도하지 않은 결과물이 나올 수 있습니다.

이때 > * + * 라는 CSS Selector를 사용한다면 margin을 통해서 gap과 동일한 디자인을 구현할수가 있습니다. margin은 음수도 지원을 하므로 음수 gap을 만들 수 있게 됩니다. flexbox의 gap은 방향과 관계없이 가능하나 margin-left와 margin-top은 flex-flow의 row와 column에 따라 적용을 해야합니다.

.hgap(-10) > * + * {
  margin-left: -10px;
}

.vgap(-10) > * + * {
  margin-top: -10px;
}

tailwind의 경우 .space-x-*, .space-y-* 라는 형태로 유틸리티를 제공하고 있습니다.

.space-y-3 > * + * { margin-top: 0.75rem; /* 12px */ }

adorableCSS의 경우 gap이 음수라면 자동으로 동작할 수 있도록 만들고자 하고 있습니다만, CSS가 너무 복잡해지는 관계로 hgap(), vgap() 처럼 명시적으로 가로와 세로 방향은 최소 사용자가 지정해야하는 방식으로 우선 고려되었습니다.

<div class="hbox gap(-10)"></div> <!-- 개발중 -->

<div class="hbox hgap(-10)"></div> <!-- 현재스펙 -->

2) Canvas Stacking: First on Top

CSS의 경우에는 같은 z-index가면 HTML에 나중에 그려진 순서대로 덮어쓰도록 되어 있습니다. 하지만 디자인에 따라서는 앞에 있는 컨텐츠가 더 앞으로 와야 하는 경우도 필요합니다.

Figma의 경우 이를 First on Top 이라고 부르고 있는데 이러한 기능을 CSS에는 딱 맞는 스펙이 존재하지 않습니다.

현재는 실험적으로 아래와 같이 .FirstOnTop을 만들어보았으나 사이드 이펙트가 너무 염려되는 방식이다보니 고민중에 있습니다.

/* FIXME: */
* {z-index: 11;}
.FirstOnTop > *:nth-child(1) {z-index: 10;}
.FirstOnTop > *:nth-child(2) {z-index: 9;}
.FirstOnTop > *:nth-child(3) {z-index: 8;}
.FirstOnTop > *:nth-child(4) {z-index: 7;}
.FirstOnTop > *:nth-child(5) {z-index: 6;}
.FirstOnTop > *:nth-child(6) {z-index: 5;}
.FirstOnTop > *:nth-child(7) {z-index: 4;}
.FirstOnTop > *:nth-child(8) {z-index: 3;}
.FirstOnTop > *:nth-child(9) {z-index: 2;}
.FirstOnTop > *:nth-child(10) {z-index: 1;}

추후에는 이러한 기능들도 figma와 같은 형태로 제공을 하고자 간단히 사용할 수 있도록 하는 방법을 제공할 예정입니다,.

<div class="hgap gap(-20) firstOnTop">
  <Avatar>
  <Avatar>
  <Avatar>
  <Avatar>
</div>

3) Position & Dimension

수치를 이용한 좌표방식은 그 자체로 충분히 직관적으로 CSS로 표현할 수 있습니다.

CSS

이러한 Figma의 속성들을 CSS에서는 다음과 같이 표현할 수 있습니다.

.Frame {
  /* Use Absolute Position */
  position: absolute;
  
  /* X */
  left: -8901px;

  /* Y */
  top: 2336px;

  /* W */
  width: 409px;

  /* H */
  height: 308px;

  /* Rotation */
  transform: rotate(90deg);

  /* Corner radius */
  border-radius: 0;

  /* Clip content */
  overflow:hidden;
}

TailwindCSS

TailwindCSS에서는 다음과 같이 표현할 수 있습니다.

<div class="absolute left-[-8901px] top-[2336px] w-[409px] h-[308px]
            rotation-[90deg] rounded-[20px] overflow-hidden">

AdorableCSS

AdorableCSS에서는 직관적인 범위 안에서 가능한한 코드를 더 짧고 figma와 유사한 키워드를 쓰고 싶었기에 다음과 같은 x, y, r, clip, rotate 와 같은 속성을 추가하여 조금 더 간결하게 사용할 수 있도록 하였습니다.

x(-8901) = left: -8901px;
y(2336) = top: 2336px;
r(20) = border-radius: 20px;
clip = overflow:hidden;
rotate(90) = transform: rotate(90deg);

<div class="absolute x(-8901) y(2336) w(409) h(308) rotate(90) r(20) clip">

Text

Figma Text 공식문서
https://help.figma.com/hc/en-us/articles/360039956634

Figma

Figma는 다음과 같이 글자에 대한 속성들을 구성해두고 있습니다.

주요 속성과 키워드는 다음과 같습니다.

Font type

Font Weight Font size

Line height Letter spacing

Paragraph spacing

Auto width Auto Height Fixed size

Text Align left Align top

Underline Strike

Upper Case lower case small caps

Vertical trim

List style

Paragraph spacing

Truncate text

대부분은 CSS의 개념들과는 크게 상이 하지 않으며 특이할만한 것들만 몇가지만 짚고 가보려고 합니다.

Text Resizing 와 Text Align Vertical

기본적으로 CSS의 Text정렬은 text-align을 이용하여 left , center, right, justify 정도로만 표현되고, vertical-align의 경우에는 inline간 정렬을 하기 때문에 실제로 자주 쓰이는 속성들이 아닙니다.

Figma의 경우에는 Text 정렬에 대해서 Text ResizingText Align Vertical 이라는 개념을 추가해서 텍스트를 정렬하도록 하고 있습니다.

Text Resizing은 Auto Width, Auto Height, Fixed size 라는 3가지의 옵션이 있으며, Text Align VerticalTop, Center, Bottom 의 3가지 옵션이 있습니다.

Text Align Vertical은 Center나 Bottom일 경우에는 display:flex를 이용하여 정렬을 해줄 수 있고 Auto Width일 경우에는 사용 할 필요가 없습니다.

.AutoWidth {
  white-space:nowrap;
}

.AutoHeight {
  width: 200px; /* Fixed Width */
}

.FixedSize {
  width: 200px; /* Fixed Width */
  height: 200px; /* Fixed Height */
}

.Text-Vertical-Center {
  display:flex;
  flex-flow:column;
  justify-content:center;
}

Truncate text (= ...)

말줄임은 실전에서도 상당히 빈번하게 사용되면서 많은 CSS가 복합적으로 사용해야 하는 경우가 많아서 유틸리티 CSS에서 가장 많이 나오는 예시입니다. 1줄을 말줄임하는 경우와 여러줄을 말줄임하는 경우가 달라서 다음과 같이 CSS를 준비해보았습니다.

.truncate {
  flex-shrink:1;
  max-width:100%;
  overflow:hidden;
  white-space:nowrap;
  text-overflow:ellipsis;
}

.max-lines\(3\) {
  max-width:100%;
  overflow:hidden;
  display:-webkit-box;
  -webkit-box-orient:vertical;
  -webkit-line-clamp:3;
}

Paragraph spacing

문장과 문장간의 간격을 별도로 설정하는 Paragraph Spacing이라고 하는 속성은 CSS에는 없는 속성입니다. 글자내 문장간 간격등을 만들어 내기 위해서는 다음과 같은 CSS를 이용해서 만들어 볼 수 있을 것 같습니다.

.Text > br {
  display:block;
  margin-top:20px;
  content: "";
}

/* or */

.Text > p + p {
  margin-top:20px;
}

CSS

종합해서 Figma의 속성들을 CSS로 만들기 위한 템플릿을 작성해보았습니다. CSS가 문서 서식을 기반으로 시작한만큼 거의 대부분의 속성들은 1:1로 매칭이 가능합니다. 아래는 Figma 속성이 어떤 CSS와 대응이 되는지 확인할 수 있습니다.

.Text {
  /* 1. Font Type */
  font-family:'Noto Sans KR';

  /* 2. Font Weight */
  font-weight:700;

  /* 3. Font Size */
  font-size:14px;

  /* 4. Line Height */
  line-height:22px;

  /* 5. Letter Spacing */
  letter-spacing:-0.01em;

  /* 6. Text Decoration */
  text-decoration:underline; /* or line-through */

  /* 7. Text Transform */
  text-transform:uppercase; /* or lowercase, capitalize */
  /* or */ font-variant-caps:small-caps;

  /* 8. Text Align */
  text-align:left; /* or center, right, justify */
  
  /* 9. Text Resizing & Text Align Vertical*/
  white-space: nowrap; 
  /* or */ display:flex;
  flex-flow:column;
  justify-content:center; /* or flex-end */

  /* 10. Vertical-trim */
  leading-trim:both;
  text-edge:cap;

  /* 11. Truncate text */
  max-width:100%;
  display:-webkit-box;
  -webkit-box-orient:vertical;
  -webkit-line-clamp:1;

  /* 12. Fill */
  color:#fff;
}

/* 13. Paragraph spacing */
.Text > p + p {
  margin-block-start: 30px;
}

.Text > br {
  display:block;
  margin-block-start: 30px;
  content: "";
}

TailwindCSS

TailwindCSS에서는 아래와 같이 작성을 하게 됩니다.

<div class="text-[#fff] leading-[22px] tracking-[-0.01em]
            underline uppercase 
            text-center flex flex-col justify-end 
            truncate"></div>

AdorableCSS

AdorableCSS에서는 line-height letter-spacing line-through와 같이 길어져야 하는 것들을 최소화 하고 싶어서 font(size/line-height/letter-spacing)을 한번에 묶어서 기입하고자 했습니다.

letter-spacing은 %를 지원할 수 있도록 해서 -0.01em 과 같은 표기를 줄이게 하였습니다.

text-align의 경우 text(left), text(right+center), text(pack) 등으로 가로+세로 정렬을 더 직관적으로 입력할 수 있도록 했으며,

nowrap... max-lines(3) 등의 표현으로 말줄임 텍스트에 대해서 조금 더 시각적으로 이해할 수 있도록 하는 표현들을 만들었습니다.

<div class="font(14/22/-1%) bold underline uppercase c(#fff) text(pack) nowrap..."></div>

기타

그밖에 Constraints, Fills 등에서도 AdorableCSS만의 특유의 간결하고 직관적이며 시각적인 UI를 넣기 위해서 많은 노력을 하고 있습니다.

absolute(x,y)x(center+50px) 과 같은 표현들

layer layer(top) 와 같은 표현들


TailwindCSS와 차별화되는 AdorableCSS만의 장점

  1. 보다 더 간결한 문법, 훨씬 더 적은 양의 코드
  2. 직관적이고 시각적인 코드, 마치 코드로 figma를 하는 느낌
  3. 훨씬 더 가벼운 학습곡선 (어차피 배울거라면 애매한것 보다 확실하게)
  4. figma개념으로 완성된 CSS Framework

최대한 코드 그 자체에서 디자인을 떠오를 수 있도록 시각적으로 코드와 문법을 갖추고자 했습니다. 그러다 보니 자연스레 figma의 개념들을 많이 가져오게 되었습니다.

이렇게 만들어진 AdorableCSS를 쓰면서 좋았던 점은 figma에서 코드를 자동으로 가져오는 기능을 통해서 개발의 속도가 향상될 뿐만 아니라 이후 수정을 해야할때도 함께 개발했던 디자이너도 Chrome Inspect를 보고 어디를 어떻게 수정해야하는지 직관적으로 바로 파악을 하면서 디자인 필터링을 하는 과정에서도 상당히 좋았습니다.

HTML이 더 이상 지저분하지 않은 TailwindCSS라면 어떠신가요?

끝으로...

"문법만 살짝 다른 tailwind 아닌가?"

하지만 문법만 살짝 달라져도 정말 다른 경험으로 CSS와 UI개발을 할 수 있다는 것을 끊임없이 문법을 개발하고 더 직관적인 표현을 찾기 위해서 노력하게 되면서 알게 되었습니다.

좋은 문법은 생각할 시간을 적게 만들고 더 적은 타이핑으로 더 많은 것들을 하게 만들어 줍니다.

뿐만 아니라 좋은 구조와 개념을 가지고 있다면 훨씬 더 나은 개념과 차원에서 개발을 할 수 있도록 만들어 준다는 것을 느꼈습니다.

계속해서 현업에서 실험을 하면서 문법을 더 다듬고 실전에서 마주하는 불편한 점들을 개선하고 디자인 시스템과 코드 자동화 도구를 개량하여 누구나 쓸 수 있는 좋은 버전을 만들어 가고자 합니다. 많은 관심 부탁드립니다.

AdorableCSS는 과정에서 Figma가 제공하는 디자인 개념을 이해하고 CSS로 만들어 가는 과정을 학습하면서 상당히 많은 것들을 이해하고 학습할 수 있었습니다.

CSS가 어려운 이유중에 하나는 같은 화면을 만들기 위해서 여러가지 방법이 있다. 라는 점인데 Figma 디자인 개념에 입각해서 CSS를 만들어보는 것을 연습해보는 것은 CSS를 학습하고 나만의 Best Practice를 정립하는데 참 도움이 되겠다는 생각이 들었습니다.

꼭 AdorableCSS가 아니더라도 이러한 개념에서 라이브러리나 유틸리티, 혹은 컴포넌트등을 생각해보는 것도 좋을 것 같습니다.

이 글이 Figma와 디자인 그리고 CSS에 대해서 전반적인 인사이트와 도움이 되는 글이기를 바라며 앞으로의 AdorableCSS의 행보에도 많은 관심 가져주시고 의견 내주시면 감사하겠습니다.

고맙습니다 :)

AdorableCSS 공식 홈페이지
https://developer-1px.github.io/adorable-css/

github
https://github.com/developer-1px/adorable-css

profile
AdorableCSS를 개발하고 있는 시니어 프론트엔드 개발자입니다. 궁금한 점이 있다면 아래 홈페이지 버튼을 클릭해서 언제든지 오픈채팅에 글 남겨주시면 즐겁게 답변드리고 있습니다.

25개의 댓글

comment-user-thumbnail
2023년 9월 6일

저번에 보았을 때, 정확히 '문법만 다른 tailwind 아닌가?' 라는 생각이였던 사람 중 하나입니다.
일단 지치지 않으시고 앞으로 전진 하시고 계시는 것에 대한 리스펙트를 드리고 싶네요 ㅎㅎ

저희 회사 또한 피그마 플러그인을 이용한 코드화 방향성을 고민하고 있고 tailwind로 구현하고 사용해보았습니다. 피그마 컴포넌트 네이밍을 통한 코드화에 좀더 가깝긴 합니다만 비슷한 고민의 흔적을 보니 반갑네요.

이 방향성은 웹/앱밥 먹고 있는 사람들의 공통적인 고민 같습니다. 좀더 훈수를 보태자면 아예 피그마에 종속된 css 프레임워크의 방향성이 사람들에게 더 어필되지 않을까 합니다. (아예 figmaCSS라는 이름으로 어그로를 풀로 채운다던지..)🤔

아무튼 고민의 흔적을 지속적으로 남겨주시어 감사드립니다. 다음번에도 고민의 흔적을 남겨주시면 감사히 얻어가겠습니다.

1개의 답글
comment-user-thumbnail
2023년 9월 7일

항상 고민하던 문제를 같이 고민하는 사람이 있다는걸 알게된 오늘
존재 자체로 위안이 되네용

1개의 답글
comment-user-thumbnail
2023년 9월 7일

혹시 anchor, shape-outside, scroll-snap, video:buffering, :current(p, a) , :has(), container query 등 추가 되는 부분에도 추가적으로 지원 예정 있으실가요??

1개의 답글
comment-user-thumbnail
2023년 9월 7일

너무 재밌게 읽었고 경험한 문제를 직접 풀고자 하시는 모습이 정말 멋지십니다 :) 저도 더 좋은 FE 엔지니어가 되기 위해서 열심히 노력하겠습니다!

1개의 답글
comment-user-thumbnail
2023년 9월 8일

프론트엔드 개발을 조금 배웠고, 최근 테오의 스프린트에서는 프로젝트의 디자이너로 figma를 접하며 디자인과 프론트엔드의 간격을 더 쉽고 편하게 줄일 수 있는 툴이 있다면? 그리고 제가 프론트엔드를 접하면서도 더 편하고 예쁘게 디자인을 하고싶은데 과정이 번거롭지 않을수만 있다면? 고민했는데 그것에 대한 해답과 고민들이 있는 아티클인것 같습니다. 개인적으로 figma의 직관적인 디자인법칙이 마음에 들어서, 이러한 원칙을 반영하셨다니 기대됩니다..! 천천히 음미하면서 읽어볼게요 :) 감사합니다!

1개의 답글
comment-user-thumbnail
2023년 9월 8일

테오는 신이야...

1개의 답글
comment-user-thumbnail
2023년 9월 12일

안녕하세요:)
21년에 발표자료와 해당 글을 읽고 정말 많은 생각을 통해 제작이 된 것을 알 수 있었습니다.

저도 현재 현직에서 근무중인데요, 항상 많은 고민중에 하나가 어떻게 하면 다양한 컴포넌트를 쉽게 표현을 할 수 있을까 인것 같습니다.

제가 요즘 드는 고민이 있어 해결방법에 조금 더 다가갈 수 있어 이 글에 너무나 감사함을 얻습니다.

추가로 여쭈어볼 내용이 있는데요.

먼저, 제가 하고 있는 서비스에서는 특성상 200여가지의 아이콘을 스프라이트 이미지를 이용하여 작업을 합니다.
이럴 경우 <span>, <div>:before 를 이용하여 구조에 틀을 잡고 아이콘 자체를 가운데 정렬을 하고 있습니다.

물론 icomoon, svg를 이용도 해보았지만, 다양한 색상이 존재하는 아이콘은 만들 수 없다는 결론에 도달하여 스프라이트 이미지를 사용하고 있습니다.
이럴경우 AdorableCSS로 해결이 가능할지 궁금합니다.

두번째로, 최근 작업중 다크모드 이슈가 있었는데요, 미디어 쿼리를 이용하여 다크 모드 대응을 한 경험이 있습니다.
그래서 만약 AdorableCSS에도 다크모드가 되는 미디어 쿼리가 있으면 좋겠다라는 생각을 하였습니다.
공식 홈페이지에는 디바이스의 너비에 따른 미디어쿼리는 보이는데, 다른 구문은 보이지 않아 아직 없다면 개발이 되면 너무 좋을거 같습니다:)
이미 개발이 된 거라면 알려주시면 너무나 용이하게 사용할 수 있을 거 같습니다:)

1개의 답글
comment-user-thumbnail
2023년 9월 13일

tailwind도 그렇고 adorableCSS도 그렇고, 작동원리가 어떻게되는지 알 수 있을까요?
클래스 이름을 정의해둔대로 쓰면 어떻게 css가 생성되는지 궁금합니다.

3개의 답글
comment-user-thumbnail
2023년 9월 15일

GOAT

1개의 답글