CSS 공부 어떻게 해야 하나요? - 이론편 (feat. figma)

teo·2021년 12월 4일
92

커리큘럼

목록 보기
3/6
post-thumbnail

프롤로그

지난 글인 입문자를 위한 javascript 커리큘럼의 댓글에서 CSS를 어떻게 공부를 해야 되느냐에 대해서 물어보신 분이 계셔서 해당 글을 작성하게 되었습니다. 감사합니다.

크게 1. CSS에 대한 간단한 이론을 익히는 과정2.효과적인 단계로 실습을 할 수 있는 과정으로 생각을 해보았으며 이 역시 2021년 트렌드를 반영해서 늦게 알아도 상관없는 부분을 배제하고 좀 더 중요한 부분만을 추려서 전달하고자 했습니다.

👍 CSS: The Good Parts

javascript: The Good Parts 패러디 맞습니다.

웹과 관련해서 매번 언급하는 내용인데, 웹 스펙은 초기 요구사항에 맞게 만들어집니다. 하지만 발전하는 과정에서 다른 형태로 웹 산업이 발전해 나갈 때 그에 맞는 니즈에 맞게 스펙이 빨리 결정되기는 쉽지 않습니다. 어느정도의 합의가 되어 더 나은 방법이 결정되기까지 현업 최전선에 있는 사람들은 기존의 스펙안에서의 방법을 찾고 무엇이 최선인지는 모르는 상태가 됩니다.

한번 만들어진 스펙은 하위호환성을 고려해서 버릴 수가 없으니 계속 그 스펙이 유지가 되고 그것을 사용하는 방법 배우는 방법등이 기록에 남아 있으면서 배우는 입장에서는 어떤것들이 맞는 방법인지 점점 알기 어려워지죠.

제가 좋아하는 파레토의 법칙입니다.

css에서 상위 20% 스펙이 전체 css 코드의 80%를 차지한다.

실제로 실전에서 자주 쓰이는 css는 몇개 되지 않습니다.

그래서 이번 글에서는 제가 쓰고 있는 현재의 Best Practice를 공유하려고 합니다.
(물론 이 방법이 Best한가에 대한 기준은 순전히 제 주관적이니 판단은 여러분의 몫입니다.)

제가 쌓아온 Best Practice를 근거로 만들어진 결과물이 AdorableCSS이지만 이것을 추천하기에는 다소 급진적이며 사용하지 않는 환경이 아니고선 의미가 없기 때문에 stateofcss 2020을 기준으로 BEM, Sass, Styled Components를 사용하고 있을 유저를 기준으로 설명드리려고 합니다.


선택자(Selector)

첫 번째 주제는 셀렉터입니다.

#app.header div:hover > a[target="_blank"] { color: red; }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* 여기 부분이 선택자(selector)입니다. */

CSS를 처음 배우게 되면 항상 첫번째 챕터에 있는 녀석입니다.

초창기에는 이 셀렉터를 css를 배울때 맨 처음 배우는 부분이며 css를 잘 하기 위해서는 잘 알고 있어야 하지만 현대에 와서는 selector 학습의 중요도가 예전같지는 않습니다.

왜 selector가 덜 중요해졌을까요?

예전에는 html와 css를 분리해서 html을 최대한 건들지 않고 css만으로 디자인을 하는것이 중요했습니다. 하지만 지금은 웹프레임워크 위에서 html과 css를 묶어 컴포넌트로 다루는 방식으로 진화를 했습니다.

그래서 html의 수정과 css의 수정이 한 곳에서 이루어지다보니 selector가 복잡할수록 오히려 html을 수정하는데 문제가 더 발생하기 때문입니다.

selector는 일단 BEM만 알아도 된다.

http://getbem.com/introduction/

그래서 selector는 class방식으로만 작성하고 네이밍 규칙은 BEM 방식으로 하는 것이 대세룰이 되었습니다. 자세한 내용은 링크를 참조해주세요.

.Block__Element--Modifier

<div class="header">
  <div class="nav"></div>
</div>

<style>
.header .nav { (X) } /* 이렇게 하면 nav가 header 구조에 종속이 된다. */
</style>
<div class="header">
  <div class="header__nav"></div>
</div>

<style>
.header__nav { (O) } /* 구조도 표현하면서 종속 관계가 없다. */
</style>

자주 묻는 질문

BEM에서 하위요소의 하위요소는 어떻게 해야 되나요? `.header__nav__item 이런식으로 막 길게 붙여서 쓰면 되나요?

정해진 답은 없지만 대부분 __를 하나만 쓰는 것을 권장합니다.
.header__nav {...}
.nav__item {...}

그리고 2depth 표현이 필요하다는 것은 컴포넌트가 분리되어야 한다는 신호이니 적당히 컴포넌트로 쪼개어 주세요.


속성과 값(Property & Value)

https://developer.mozilla.org/ko/docs/Web/CSS/Reference

CSS는 속성이 굉장이 많습니다. 일단은 머리속으로 레이아웃과 관련된 속성과 그렇지 않은 것에 대해서 이분법적으로 생각을 하면 좀 쉽습니다.

레이아웃이 아닌것

레이아웃이 아닌 것은 그냥 하시면 됩니다. 진짜 드릴 말씀이 없어요.
다만 글자 속성은 하위 엘리먼트에 전부 영향을 미친다 정도만 기억하면 될 것 같아요.

레이아웃이 아닌 것

  • 글자
  • 색상, 배경
  • 테두리
  • 그림자
  • 투명도
  • 필터

그중 꼭 알아야할 중요한 속성은 figma등 디자인 툴에서 UI로 제공하는 기능들입니다. 이러한 값들을 중심으로 속성을 이해하시면 됩니다.

나머지 속성들은 훑어보고 그냥 알고만 있으면 됩니다. 필요할 때 찾아 쓰다보면 자연스럽게 외워집니다. (그래도 알고는 있어야 찾겠죠?)


🌻 레이아웃

사실상 이 글의 핵심 주제 입니다.

여기서 부터가 이 글의 메인주제입니다.
CSS의 꽃은 레이아웃이며 학습에서 난이도가 올라가는 지점이기도 합니다.

CSS 레이아웃이 어려운 이유

CSS는 레이아웃에 대한 역사가 되게 오래되었습니다.
웹 초창기 출판의 레이아웃 개념에서 시작한 float부터 table을 거쳐 지금의 flexbox, grid에 오기까지 웹 서비스의 변화에 따른 레이아웃에 대한 방법은 다양하게 발전했습니다.

새로운 스펙이 등장할 때 마다 레이아웃을 이렇게 해야 된다 저렇게 해야 된다라는 어떤 여러 가지 해법들이 있었고, 또 브라우저마다 해법이 다르고 하나의 정답이 있지 않다보니 무엇이 맞는 방법인지 혼란스러움이 첫번째 이유입니다.

뿐만 아니라 사소하게는 내가 원하는 배치를 위해서 margin을 어디에 둘지, padding을 어디에 둘지도 같이 개발하는 사람끼리 천차만별입니다.

사실 여기에는 정답이 존재하는 것은 아니기 때문에 매번 작업을 할때마다 '이게 맞나?'라는 생각이 드는 점도 CSS를 어렵게 하는 이유 입니다.

😎 애정남! 입문자를 위한 CSS 레이아웃

그래서 Best Practice를 정해두고 그 철학에 맞게 개발을 하면 마음도 편하고 좋습니다.
그것이 바로 글 서두에서 밝힌 저의 Best Practice를 설명 하고자 함입니다.

margin을 가급적 쓰지마라!

CSS가 애매해지고 복잡해지는 첫 번째는 바로 margin입니다.

margin이 처음부터 어렵지는 않지요. 그러나...

  • margin collapse (마진 상쇄 원리)라는 요상한 말이 뭔지도 알아야하는 것을 차치하고
  • 두 엘리멘트 사이의 간격을 만들기 위해 어느 엘리먼트에 margin을 걸어야 하는 선택장애 문제
  • 내가 놓고자 하는 엘리먼트 주변의 margin으로 인해 위치가 틀어지는 현상과
  • 음수 마진들을 동원해 아슬아슬한 균형잡기를 하고 있노라면
  • 이제는 프레임워크에서 margin이 있는 컴포넌트를 배치하면 어디서는 잘 나오는데 어디선가를 틀어지고 있는 현상을 겪고나면...

아... 그래서 margin을 좀 적당히 쓰라고 하는거구나.. 를 깨닫게 됩니다.

margin은 상당히 특이한 개념입니다.

내 주위에 보이지 않는 밀어내는 힘을 만들어서 주위에 영향을 미치는 구조죠. 자석마냥 서로가 마진을 가지고 있다면 서로간의 상쇄를 통해 위치가 부여됩니다.

이게 스펙상으로는 상당히 직관적인것 같은데 반해 막상 코드로 구현된 결과물은 전혀 그렇지 않습니다.

그래서 레이아웃을 해결하는 방법에 있어서 margin보다 좋은 방법들이 많으니 꼭 margin을 써야 되는가를 생각해보세요.

실제로 figma는 margin이라는 개념이 없지만 충분히 Layout이 가능합니다.

이제 레이아웃은 거의 대부분 Flexbox로 가능하다!

CSS의 레이아웃의 과도기는 지나갔고 이제 거의 대부분의 레이아웃은 flexbox로 가능합니다. 그러니 일단 flexbox로만 레이아웃을 하도록 하세요.

다음 쳅터에서는 margin을 사용하지 않고 flexbox를 통해서 레이아웃을 만들어내는 방법을 알려드리도록 하겠습니다.

Overlay는 아쉽지만 다음 다음 기회에...

컨텐츠가 겹쳐서 z축으로 쌓이는 레이아웃을 Overlay라고 부릅니다. 여기 레이아웃도 공부가 필요한 부분이지만 여기까지 포함하면 너무 길어질것 같아서 아래와 언급한 부분들과 함께 따로 묶어서 기회되면 글을 작성해보도록 하겠습니다.

  • Overlay (position, scroll, ...)
  • Interaction (cursor, :hover, :active, ...)
  • Responsive (media query, max-width, ...)
  • Overflow (scroll, ellipsis, line-clamp, ...)
  • Animation (transform, animation, ...)

🖼 flexbox

거의 모든 레이아웃이 가능한 CSS 스펙입니다. 그리고 더 최신 스펙인 grid로도 대체할 수 없는 레이아웃이기 때문에 꼭 알고 있어야 합니다.

IE11에서도 다행히(!) 사용가능한 아주 소중한 스펙입니다.

flexbox가 어려운 이유

직관적이지 않은 스펙 이름

flexbox의 기능이 훌륭하고 구성이 어렵지 않음에도 배울때 헷갈리는 이유는 바로 스펙이 직관적이지 못하기 때문입니다.

가로 혹은 세로로 배치하기 위한 flex-direction: row | column 만 보더라도 개인적으로 조금 마음에 들지 않습니다.

그러니까 우리말로 행과 열은 항상 헷갈리지 않나요? 가로 세로가 조금더 명확 한것 같고... 사람마다 다르겠지만 저는 좀 그랬습니다.

그밖에 align-items: flex-start , justify-content: flex-end 도 조금 헷갈리죠.

굉장히 naming 센스가 좋다고 생각하는 CSS인데 flexbox는 조금 아쉽게 스펙만 보고서 어떤 화면이 그려질리 바로 그려지지 않아요.

그래서 처음 익혀야 할 것은 flexbox를 시각적으로 이해하는게 필요합니다.

figma의 AutoLayout과 비교

figma의 AutoLayout은 위와 같이 구성이 되어있습니다.

  1. 세로, 가로의 방향
  2. 엘리먼트간의 간격
  3. 4방향 padding
  4. 9방향 배치
  5. space-beetween

실제 figma을 설치해서 한번 어떤식으로 배치가 되는지 시각적으로 이해해 보세요.
백번의 설명보다 한번의 그림으로 이해하는 것이 훨씬 더 이해하기 좋습니다.

헷갈려서 저는 Wrapping을 택했습니다.

저도 처음에는 계속 헷갈렸습니다. 연습을 계속 해도 헷갈리길래 이걸 연습으로 커버하기 보다는 좀더 직관적인 스펙으로 만드는게 낫겠다라는 생각이 들었습니다.

보통 API가 좀 마음에 안 드는 부분들을 좀 더 예쁘게 정리하는 과정을 Wrapping이라고 하는데요.

조금더 직관적인 형태로 스펙을 만들어서 사용해야겠다는 생각이 들었습니다.

row | column 보다는 horizontal | vertical
align-items | justify-content 보다는 top+right

이렇게 한번 변경해서 만들어보니 쓰기도 편할 뿐더러 나중에 스펙을 더 이해하는데 도움이 되었습니다.

왜 CSS 스펙이 조금 더 직관적이고 시각적인 이름을 쓰지 않았을까요?

모든 언어권이 왼쪽에서 오른쪽으로 글자를 읽지는 앖습니다. css direaction: rtl(right to left)을 키워드로 한번 검색해보세요. 아랍권등에서는 문자를 오른쪽에서 왼쪽으로 읽게 됩니다. 그러니 같은 CSS를 가지고 다국어 대응등을 위해 방향만 뒤집기 위해서는 left나 right가 아니라 start, end 라고 표기를 해야 문제가 없거니와 반응형에서도 row와 column만 바꾸는 경우에 방향이 고정이 되어 있으면 이상하게 보일 수도 있기 때문입니다.

그럼에도 Wrapping을 하는 이유는 실전에서 저런 경우의 수를 고려해야 하지 않는 상황이 거의 대부분이기 때문입니다. 필요할때는 필요한 것을 찾아서 하면 되고 그때 배워도 됩니다.


실전!

AdorableCSS에서 사용하는 스펙을 css로 구현해봅시다.

한번 만들어두고 html에 적용을 해서 개발을 해보면 참 쉽구나 할 수 있습니다. Sass나 Styled Component를 사용하신다면 mixin이나 function으로 한번 만들어 보세요.

wraping를 하는 과정을 통해서 flexbox에 대해서도 한번 배워봅시다.

flex-direction

가로로 배치하는 flexbox를 만들어 봅시다.
row라는 이름보다는 horizontal로.. horizontal은 너무기니 horizontal flexbox를 따와서 hbox로 지었습니다.

.hbox {
  display: flex;
  flex-direction: row;
}

마찬가지 방법으로 세로도 만들어봅시다.

.vbox {
  display: flex;
  flex-direction: column;
}

@TODO: sass로 해보기

@TODO: styled-component로 해보기

align-items

두 번째는 어디에 배치하는 것인가 입니다.
배치하는 방향과 cross한 축의 위치를 결정하는 것이 align-items입니다.

hbox의 경우 대부분이 Toolbar와 같은 UI이므로 대부분 가운데 정렬이니 hbox를 아래와 같이 만들겠습니다.

.hbox {
  display: flex;
  flex-direction: row;
  align-items: center; /* hbox는 가운데 정렬이 default이면 편하다! */
}

cross한 축의 위치라고 했으니 남은 곳은 위 아니면 아래 입니다.

align-items: flex-start 면 위,
align-items: flex-end면 아래 입니다.

.hbox\(top\) {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
}

.hbox\(bottom\) {
  display: flex;
  flex-direction: row;
  align-items: flex-end;
}

위, 아래가 아니라 꽉 채우는 방식도 있습니다.

.hbox\(fill\) {
  display: flex;
  flex-direction: row;
  align-items: stretch;
}

stretch은 오타를 많이 내서 fill이라고 이름을 지어봤습니다.

justify-content

배치하는 방향과 나란한 축의 배치를 결정하는 속성입니다.
기본은 왼쪽이니까 가운데와 오른쪽의 경우만 만들어보면 될 것 같습니다.

.hbox(center) {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
}

.hbox(right) {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end
}

justify-content: space-beetween

나란한 축의 특징은 space-beetween이라는 스펙이 존재한다는 것입니다. 이는 조립해서 쓰기 좋은 속성이므로 따로 만들어 주겠습니다.

justify-contentspace-beetween을 세트로 외워두시면 align-items와 헷갈리지 않습니다.

.space-beetween {
  justify-content: space-beetween;
}
<div class="hbox(top) space-beetween">...</div>

pack

컨텐츠를 가운데에 배치하는 것은 매우 빈번한 작업입니다. hbox(center)와 같이 쓸 수도 있겠지만 빈도를 고려해서 더 짧은 이름의 유틸리티를 두고 사용하면 좋습니다.

.pack {
  display: flex;
  align-items: center;
  justify-content: center;
}

margin:auto 를 이용해서 가운데 정렬을 하는 방법도 배울텐데요. 가급적 margin을 쓰지 않는다는 원칙에 따라 위 방식을 추천드립니다.

기타

figma에는 없는 아래와 같은 스펙들을 그냥 이런게 있구나 정도만 알고 있으면 될것 같습니다.

flex-wrap
flex-direaction:row-reverse
order:0
justify-content: space-around

figma에서 지원하지 않는데에는 다 이유가 있습니다. 굉장히 특수한 목적에서만 사용이 되므로 그냥 기억만 하고 있다가 그런 상황이 닥쳤을때 생각에서 꺼내어 검색해서 활용하세요.

사용법

<div class="tool-bar hbox(top) space-beetwen">
  <div class="tool-bar__item">h</div>
  <div class="tool-bar__item">b</div>
  <div class="tool-bar__item">o</div>
  <div class="tool-bar__item">x</div>
</div>

저는 이와 같이 유틸리티 클래스를 만들어서 조립하는 방식을 추천합니다. flexbox 레이아웃은 HTML의 구조에 영향을 받도록 만들어져 있기 때문에 HTML에서 레이아웃을 잡는 편이 훨씬 더 관리하기가 쉽습니다.

하지만 그러기 싫다면 Sass나 Styled Component에서 mixin이나 함수를 한번 만들어서 사용해보는것도 그것도 싫다면 지금의 과정으로 인해 flexbox스펙이 익숙해 지길 바랍니다.

vbox는 숙제입니다.

어렵지 않으실 거예요. vbox는 hbox와 방향만 다를 뿐 동일합니다.
hbox와 달리 vbox는 align-items: stretch으로 만드는 것이 좋기 때문에 저는 아래와 같이 만들어서 사용하고 있습니다.

.vbox {
  display: flex;
  flex-direction: column;
  align-items: stretch; /* vbox는 기본값이 stretch 가 편하다 */
}

하지만 vbox 기준으로도 상하좌우 배치를 만들어봐야 align-items나 justify-content에 대한 이해도가 완성되기 때문에 꼭 연습을 하시길 바랍니다.

padding

패딩은 어렵지 않기 때문에 자세히 쓰지 않겠습니다. 컨테이너를 기준으로 내부로 여백을 두는 스펙이며 공통적으로 쓰이는 내부 여백이 존재한다면 패딩을 사용하시면 되겠습니다.

gap

그다음에 이제 각각의 콘텐츠들이 있을 때 이 콘텐츠들의 간격을 만들어내는 방법인 건데
이 부분들은 이제 사실 굉장히 최근의 해법이 나왔습니다. (뭐 그렇게까지 최신은 아닙니다만...)

바로 margin을 쓰지 않고 간격을 만들 수 있는 gap이라는 속성이 생겼습니다.

그래서 갭을 입력하시면 그 사이의 간격을 일정하게 만들수가 있습니다.

대부분의 디자이너들은 일단 이 간격을 균등하게 만들고 싶어 하기 때문에 각각의 엘리먼트에 마진을 얼마씩 주면서 작업을 복잡하게 할 필요가 전혀 없어졌습니다.

.bar {
  display: flex;
  flex-direction: horizontal;
  gap: 8px
}

특히 웹 프레임워크의 컴포넌트를 배치를 할 경우에는 margin을 전달하는 것이 굉장히 복잡하고 컴포넌트에 margin이 있을 경우 배치 위치에 따라 처리를 해줘야 하는 복잡함들을 사라지게 할 수 습니다.

그래서 컴포넌트가 아닌 배치를 하는 컨테이너에 수치나 스펙을 기술하게 해서 컴포넌트를 레이아웃에서 분리할 수 있습니다.

최신 스펙이면 언제나 불안한 마음... Can I use ___ 아시죠?

https://caniuse.com/

우연히 css-trick이나 외쿡 블로그에서 새로운 것을 접하고선 오오! 하는 마음으로 can I use에 가면... 아... 이놈의 IE11은 언제까지 해야하나... 애플은 돈 벌어서 뭐하나... 제발 사파리좀 어떻게 해줘라... 이런 마음 아시죠?

아쉽게도 이 gap는 한 가지 문제가 있습니다. 이게 최신 스펙이기 때문에 (이젠 그렇게 최신도 아닌데 ㅠㅠ) 에 가보시면 갭을 쓸 수 없는 브라우저들이 보입니다.

당연히(?) IE11에서 쓸 수가 없고요 그다음에 사파리 같은 경우에도 14이하 버전에서는 쓸 수가 없습니다. 문제는 아직은 둘다 현역이라는 거죠. ㅠㅠ

다행히 해법이 있습니다. 이거 같은 경우에는 이른바 올빼미 표기법이라고 불리는 이런 css 셀렉터 방식을 사용할 건데요. * + * 요 모양이 올빼미 같다고 해서 붙여진 이름입니다. 귀엽죠?

.bar > * + * { margin-left: 8px; }
https://alistapart.com/article/axiomatic-css-and-lobotomized-owls/

셀렉터는 필요없다고 했지만 요런거 하면서 겸사 겸사 익히는 거죠. 간격을 어떻게 만들 수 있는지 그냥 위 링크를 통해서 한번 이해하고 오세요.

이 방식을 통해서라도 각 엘리먼트에 margin을 붙이지 말고 gap 방식으로 레이아웃을 해보세요.

.bar {
  display: flex;
  flex-direction: horizontal;
  gap: 8px /* 표준 스펙 */
}
.bar {
  display: flex;
  flex-direction: horizontal;
}
.bar > * + * { margin-left: 8px } /* IE나 safari 14를 지원하려면 이렇게 써야 한다. */

[정리] gap이라는 속성은 표준이나 나름 최신기능인 만큼 구 브라우저인 IE와 Safari 14.0.0 이하에서는 작동하지 않습니다.

그래서 혹시나 현업에서 IE와 Safari 14.0.0이하를 지원해야 한다면 gap 속성을 바로 쓰실 수가 없습니다.
그러면 gap을 쓰지 않고 gap과 같은 방법을 구 브라우저에서 쓸 수 없을까? 하는 것이 바로 > * + * 를 사용하는 방식입니다.
서비스가 IE를 지원을 하지 않을거라면 gap을 써도 무방할 것이며 IE를 지원해야 된다면 올빼미 표기법을 써야만 합니다.

space

margin을 안쓰고 우리에겐 gap이 있지만 그럼에도 디자인에 따라 다른 간격을 넣어야 하는 경우가 생깁니다.

그래서 이것 때문에 사실 또 마진을 써야 되는 경우가 생기거든요.

하지만 우리는 margin을 쓰지 않을 거기 때문에 2가지 해결법을 제시합니다.

1. gap 방식을 쓰기 위해서 둘 엘리먼트만 묶어서 별도의 컨테이너를 만든다.

조금 귀찮지만 figma에서는 이러한 방법 밖에 없기도 하고 좋은 방법입니다.

<style>
  .gap\(4\) { gap: 4px; } /* 표준 스펙 */
  .gap\(8\) { gap: 8px; } /* 표준 스펙 */ 

  .hgap\(4\) > * + * { margin-left: 4px; } /* IE, Safari 14 지원용 polyfill */
  .hgap\(8\) > * + * { margin-left: 8px; } /* IE, Safari 14 지원용 polyfill */
</style>

<div class="hbox gap(4)"> <!-- 최신 브라우저에는 gap을 쓰자. -->
  <div>h</div>
  <div>b</div>
  <div class="hbox hgap(8)"> <!-- IE, Safari 14이하를 지원해야 한다면 hgap형태로 쓰자! -->
    <div>o</div>
    <div>x</div>
  </div>
</div>

2. 그냥 빈 <div></div> 를 만들고 width나 height를 입력한다.

이것도 전혀 나쁘지 않은 방법입니다. 간격을 위한 빈 엘리먼트를 만드는 것에 대해서 부정적일수 있지만 사실 전혀 문제되지 않습니다.

대부분 디자인 명세는 엘리먼트와 엘리먼트 사이의 간격을 표기해줍니다.

코드상으로도 그렇게 구현이 되어있다면 더 직관적으로 여기에 대한 간격이 얼마큼 떨어져 있구나라는 거를 좀 알 수 있기 때문에 좋습니다.

<style>
  .hspace\(4\) { width:4px }
  .hspace\(8\) { width:8px }
</style>

<div class="hbox">
  <div>h</div>
  <div class="hspace(4)"/>
  <div>b</div>
  <div class="hspace(4)"/>
  <div>o</div>
  <div class="hspace(8)"/>
  <div>x</div>
</div>

flex

반응형 작업의 마무리 격인 flex 프로퍼티 입니다. 저는 보통 이렇게 만들어두고 사용합니다.

.flex {
  flex:1
}

컨텐츠는 보통 부모의 크기에 따라가며 자동으로 크기가 늘어나야 하는 영역이 존재합니다. 일반적으로 툴바에서 버튼이나 메뉴를 제외한 제목 영역등이 그러하죠.
그런 남는 영역에 flex를 지정하여 자동으로 늘어나야 할 크기를 확보해줍니다.

<div class="hbox">
  <button>버튼</button>
  <div class="flex">여기가 늘어나는 제목 영역</div>
  <button>버튼</button>  
</div>

또 양 옆으로 배치를 해야하는데 element개수가 여러개라서 space-beetween으로 좌우를 벌리기 힘들때에도 space의 공간으로 빈 엘리먼트에 flex를 사용하기도 합니다.

<div class="hbox">
  <button>버튼</button>
  <button>버튼</button>  
  <div class="flex"/>
  <button>버튼</button>  
</div>

레이아웃에서 엘리먼트의 크기는 아래와 같은 3가지 타입이 있다고 생각하면 될 것 같아요.

  1. 크기를 지정하면 해당 크기로 보여지고
  2. 크기를 부여하지 않으면 콘텐츠를 따라가는 것이고
  3. 내가 flex를 부여하면 남는 공간을 꽉 차게 배치한다.

근데 flexbox로 작업을 하다보면 갑자기 왜 이러지 하는 순간이 찾아옵니다.
분명히 컨텐츠가 다 보여져야 하는데 공간이 막 쪼그라드는 경우요.

Tip: CSS Reset에 flex-shrink:0 추가하기

*{margin:0;padding:0;box-sizing:border-box;font:inherit;color:inherit;flex-shrink:0;}

제가 쓰는 CSS Reset입니다. flex-shrink:0이 좀 특이하죠?

flexbox에서 컨텐츠를 배치를 하다보면 크기가 지정이 되지 않은 auto에 대한 해석을 하는 과정에서 공간 배치가 이상할때가 있습니다. flex-shrink의 속성은 자동으로 flexbox의 공간을 어떻게 줄일지 하는 옵션을 초기값은 1입니다.

그러다 보니 특히 img태그나 scroll과 함께 쓰이다보면 모든 엘리먼트가 보이지 않고 크기를 강제로 줄여버리는 현상이 발생합니다. 그런 엘리먼트에는 flex-shrink:0을 설정해주면 원본크기가 제대로 나타납니다.

저 같은 경우에는 일반적으로 당연히 내가 뭘 조치하지 않으면 컨텐츠 사이즈 그대로 노출이 되는 것이 default라고 보고 reset에 flex-shrink:0을 세팅을 하였습니다.

대신 기존의 말줄임과 같은 기능을 구현해야 할때에만 flex-shrink:1 을 입력하도록하였습니다.

.nowrap\.\.\. {
  white-space:nowrap;
  text-overflow:ellipsis;
  overflow:hidden;
  flex-shrink:1;
}
<div>
  <div class="nowrap...">여기가 너무 작아지면 말줄임으로 보여주세요.</div>
</div>

끝으로...

쓰다보니 길게 설명을 드렸는데 입문자 입장에서는 여전히 헷갈리실 겁니다.
css 같은 경우에는 스펙들이 이제 워낙 많이 발전되어 있고 많이 만들어지고 있는데 어떤 것은 써라 어떤 것은 쓰지말라고 하니 뭐가 맞는건지 헷갈릴 거라고 생각합니다.
쓰지말라고 하는 것이 또 언젠가는 필요할 것 같고 실제로도 그런 순간이 오기는 하고 결국에는 내가 좋은 것과 나쁜 것을 알고 안 쓰는 순간이 와야겠죠

지금 알려 준 것만 쓰면 된다. 써야 한다. 그런 얘기는 아니구요. 일단은 헷갈리면 이 방식을 본인의 Best Practice로 하시라는 겁니다.
이 방법은 figma를 바탕으로 만들어졌기 때문에 절대로 나쁘지 않으실 겁니다.

이 Best Practice를 연습하는 방법에 대해서는 또 따로 다음 편인 실전편으로 적어 볼 예정입니다. 다음 글은 그냥 간단하게만 팁 정도로 끝날 것 같아요.

아직 다 설명하지 못한 Overlay나 Interaction, Animation에 대해서도 언젠가는 정리해볼까 하지만 CSS에서 레이아웃을 제외하면 나머지는 정석이란게 존재해서 다른 자료와는 크게 차별화가 될 것 같지는 않아요. 나머지들은 그냥 편안하게 하라는대로 공부하시면 됩니다.

혹시 css 레이아웃을 하면서 굉장히 헷갈리거나 잘 모르겠다하며 힘들었던 분들에게는 도움이 됐으면 좋겠습니다.

감사합니다 :)

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

14개의 댓글

comment-user-thumbnail
2021년 12월 4일

대충 어떤느낌인지만 알고 있어 가려웠던 부분들이 이렇게나 시원하게 긁힐 수 있다니..!!!!! 정말 벨로그 하면서 가장 좋은 블로그를 드디어 찾았네요.. 언제나 항상 감사합니다..!!!!

1개의 답글
comment-user-thumbnail
2021년 12월 6일

안녕하세요! 글 너무 잘읽어서 댓글 남깁니다! 최근 css를 공부중인데, 입문 이상을 알려주는 자료가 많이 없어서 css를 잘하려면 어떻게해야하나 괴로웠는데 이 글을 발견하게돼서 너무 감사해요 ㅠㅠ
그리고 속성과 값(Propery & Value) 여기 부분이 오타가 있는 것 같아요! 속성과 값(Property & Value)이 맞지 않을까 싶습니다..!👀

1개의 답글
comment-user-thumbnail
2021년 12월 7일

정말 많은 도움이 되었습니다.. 감사합니다!!

1개의 답글
comment-user-thumbnail
2021년 12월 10일

진짜 하나 버릴 글이 없네요... 오늘도 잘 읽고 갑니다~

1개의 답글
comment-user-thumbnail
2021년 12월 11일

오늘도 여전히 잘 읽고 갑니다.
이렇게 공유를 해주시니, 개발문화도 좋아지고 좋은 인력들이 많이 유입되고 또 성장을 하는거 아닌가라는 생각이 들었습니다!

처음에 CSS 할때 진짜 W3Schools 달고 살았던게 기억이나네요.
시간이 지나고 확실히, 테오님 말 처럼 실제 사용하는거는 같습니다. 하지만.. 사람은 망각을 하기에 예전에 했던 레이아웃 배치법 까먹어서 찾고 또찾고 찾고.........ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

그리고 팀원이 늘면서
https://www.facebook.com/groups/vuejs.korea/permalink/3330152813704813
이런것도 써서 공유하고 규칙정하고도 했었는데 CSS 관련해서도 패러다임이 변해서 이번에는 다른 전략을 취해야할거 같습니다.

또 혼자서 말이 많았네요 -_-;;ㅋㅋㅋ
쨋든 글 잘 보고 가고, 너무 감사합니다!

1개의 답글
comment-user-thumbnail
2021년 12월 23일

좋은 글 읽으며 공부하던 중 gap spcae 부분에서 첫번째 방법에 대한 글이 이해가 잘안돼서 질문 남깁니다.. 마진을 쓰지 않을 것이기에 제시되는 방법이라는 말과는 반대로 1번 코드 예제에서는 margin-left 를 쓰고 있고, 또 1번 방식은 "gap방식을 쓰기 위해서... "라고 했는데 gap을 쓴 .gap 클래스는 태그에 적용을 하고 있지 않고 오히려 margin-left와 올빼미를 사용한 hgap만 적용 중이라 문장과 코드가 다른것처럼 느껴지는데 제가 글을 잘못 이해를 하고 있는건지 어렵네요 ㅠㅠ 올빼미 표기법과 margin-left, margin-top을 함께 사용하는 경우는 margin을 쓴게 아니라 아니라 gap 방식과 같은 것으로 취급되는걸로 이해해도 될까요? 그런거라면 예제 코드에서 .gap 은 왜 있는건지도 궁금합니다

1개의 답글