UI 레이아웃을 위한 CSS 그리드

CSS 그리드는 긴 텍스트 구절을 포함하는 컨텐츠 기반 웹사이트를 위한 훌륭한 레이아웃 도구이며, 다양한 전통적인 UI 레이아웃에도 굉장한 가치가 있습니다. CSS 그리드를 사용해 사용자 인터렉션이나 변경되는 조건에 반응하고 적응하며, 스크롤이 항상 제대로 동작하도록 어플리케이션의 레이아웃을 향상시키는 방법을 보여드리겠습니다.

CSS 그리드는 웹사이트 레이아웃을 구축합니다. CSS 그리드는 웹디자이너가 수년동안 사용해왔던 끝없는 float 꼼수 대신 작은 비트의 지원 코드만을 사용해 아름답고 동적인 레이아웃을 만들 수 있게 해줍니다. 친구이자 동료인 Jen Simmons는 CSS 그리드에 대해 수년간 이야기해왔고 브라우저에 구현되도록 끊임 없이 노력했으며 드디어 그 성과가 나타났습니다. 지난 해 말, 데스크탑과 모바일의 모든 주요 브라우저의 현재 버전에서 CSS 그리드를 지원합니다.

CSS 그리드는 정말 강력하고 이 예제들과 같은 동적 컨텐츠 기반 웹사이트를 쉽게 만들 수 있게 해줍니다. 그런데, 그리드는 컨텐츠 블록을 예쁘게 배치하는 것 이상으로 좋습니다. 그리드는 스크롤링을 포함해 2차원 레이아웃을 완벽하게 제어할 수 있도록 해줍니다. 이는 네이티브 앱에서 당연시 되는 접을 수 있는 사이드 패널과 고정된 툴바같은 기능을 구현하는 것이 이제는 사소한 것이 되었음을 의미합니다. 꼼수나 디버깅은 더 이상 필요 없습니다. 그리드가 있습니다.

저는 수년간 웹 도구를 개발해왔습니다. 다음은 제가 만든 고전 RPG용 게임 제작 도구의 스크린샷입니다. 저는 Flexbox가 처음 등장했을 때부터 바로 사용하기 시작했습니다. 스크롤링과 스트레칭 같은 기능을 위한 몇 가지 유틸 클래스 및 중첩된 가로 세로 상자를 사용하여 복잡한 레이아웃을 만들었습니다.

Flexbox는 절대 위치를 갖는 div와 float 꼼수 보다는 분명 더 생산적이었지만, 여전히 문제가 있었습니다. 패널이 함께 있는 이 확대 이미지를 보세요. 왼쪽 오른쪽 footer의 줄이 맞지 않는게 보이시나요?

다음은 다른 스크린샷입니다. 툴바는 그리기 캔버스 상단에 위치하며, 제 프레임워크에 따르면 이는 상단에 고정되어야 하지만 스크롤을 하기 시작하면 이런 일이 발생합니다. 툴바가 사라집니다:

이런 각각의 문제는 더 많은 위치 조절(positioning)과 float 꼼수로 수정할 수 있지만, 결과는 항상 불안정합니다. 새 패널을 추가할 때마다 모든 레이아웃을 다시 디버깅해야 합니다(리사이즈 하는 동안 어떤 div가 추가 공간을 잡고 있는지 확인하는 것 등). 그리고 마크업이 지저분해집니다. 중첩된 가로 세로 상자는 아주 복잡해지는데, 이 예제는 겨우 두 레벨 깊이일 뿐입니다. 인터렉션과 기능성이 복잡해질수록 디자인은 더욱 까다로워집니다.

<div class='hbox'>
  <div class='vbox'>
    <div class='hbox'>header</div>
    <div class='scroll'>
      <div class='sidebar'>sidebar</div>
    </div>
    <div class='footer'>footer</div>
  </div>

  <div class=vbox>
    <div class='hbox'>button button 
        spacer label spacer button button </div>
    <div class='center'>main content</div>
    <div class='hbox'>the footer</div>
  </div>

  <div class=vbox>
    <div class=’hbox’>header</div>
    <div class=’scroll’>
      <div class=’sidebar’>sidebar</div>
    </div>
    <div class=’footer’>footer</div>
  </div>
</div>

2차원으로 들어가기

Flexbox의 근본적인 문제는 1차원이라는 점입니다. Flexbox는 툴바나 네비게이션 바와 같은 1차원 용도로는 훌륭하지만, 컨텐츠를 가로 및 세로로 동시에 정렬해야할 때 문제가 발생하기 시작합니다. 우리는 진짜 2 차원 레이아웃이 필요하며, 이것이 CSS 그리드가 필요한 이유입니다. 근본적으로 그리드는 2D입니다.

다음은 CSS 그리드로 제작한 비슷한 종류의 레이아웃입니다.

하단의 footer를 자세히 보세요. 완벽하게 위치했습니다. 또한 각 패널에 border를 추가하는 대신 grid-gap을 라인으로 사용함으로써, 일관되지 않은 그리드 라인 너비에 대해 걱정할 필요가 없어졌습니다. 모든것이 제대로 동작합니다.

CSS 그리드의 가장 큰 장점은 변경되는 조건에 적응한다는 것입니다. 종종 제 앱에는 사이드 패널이 있습니다. 저는 그 패널의 펼침 여부에 관계 없이(이상적으로는 Javascript를 사용해 레이아웃을 다시 계산하지 않고도) 레이아웃의 모든 것들이 잘 동작하는지 확인해야 합니다. 사이드바는 header나 footer와 같은 여러 컴포넌트로 구성됩니다. 이러한 모든것들은 하나가 더 크거나 작지 않게 줄이 맞아야 합니다. 그리드의 minmax()라 불리는 마법의 함수를 사용하면 가능합니다.

이전에 CSS 그리드를 공부하셨다면 행과 열을 위한 템플릿을 사용해 여러분만의 레이아웃을 정의할 수 있다는 것을 아실겁니다. 200px 1fr 200px과 같은 템플릿은 200px 너비의 사이드바와 나머지 공간을 차지하는 중간 컨텐츠 영역을 제공합니다. 하지만 패널이 접히면 무슨일이 발생할까요? 지금은 컨텐츠가 축소되더라도 너비가 200px로 유지됩니다. 대신에 max 파라미터로 min-content 키워드를 사용해minmax를 사용하실 수 있습니다.

#grid {
  display: grid;
  box-sizing: border-box;
  width: 100vw;
  height: 100vh;
  grid-template-columns: 
      [start] minmax(auto, min-content) 
      [center]1fr 
      [end] minmax(auto,min-content);
  grid-template-rows: 
      [header]2em 
      [content]1fr 
      [footer]2em;
  grid-gap: 1px;
  background-color: black;
}

이제 그리드의 너비는 무슨 내용을 포함하든 최소 너비를 사용해 항상 충분히 넓은 공간을 갖게됩니다. 따라서 열의 한 부분(예로, header)이 다른 것보다 넓으면, 너비가 다른 모든 너비에 맞도록 확장됩니다. 모두가 같이 더 좁아지거나 사라진다면, 마찬가지로 너비가 조절됩니다. 본질적으로 Flexbox의 확장/축소 기능을 복제한 것이지만, 열의 한 항목이 아니라 모든것과 함께 동작합니다. 진짜 2D 레이아웃입니다.

다음은 나머지 데모 코드입니다.


.start {
  grid-column: start;
}
.center {
  grid-column: center;
}
.end {
  grid-column: end;
}
header {
  grid-row: header;
}
footer {
  grid-row: footer;
}
.sidebar {
  overflow: auto;
}

<div id="grid">

<header class="start">header</header>
<header class="center">
  <button id="toggle-left">toggle left</button>
...
</header>

<header class="end">header</header>

 
<div class="start sidebar">sidebar</div>
<div class="center content">the center content</div>
<div class="end sidebar">
  sidebar<br/>
...
</div>
 
<footer class="start">left footer</footer>
<footer class="center">center footer</footer>
<footer class="end">right footer</footer>

</div>

상단 header의 토글 버튼이 실제로 슬라이더를 숨길 수 있도록 다음 코드를 추가했습니다. 최신 DOM API와 화살표 함수를 사용해 단지 몇 줄로 JQuery를 본질적으로 복제할 수 있습니다:

const $ = (selector) => document.querySelector(selector)
const $$ = (selector) => document.querySelectorAll(selector)
const on = (elem, type, listener) => elem.addEventListener(type,listener)

on($('#toggle-left'),'click',()=>{
  $$(".start").forEach((elem) => elem.classList.toggle('closed'))
})
on($('#toggle-right'),'click',()=>{
  $$(".end").forEach((elem) => elem.classList.toggle('closed'))
})

또한 CSS 그리드는 Flexbox를 반하지 않습니다. Flexbox 사용이 타당한 경우, 즉 툴바와 같은 1차원 컨텐츠에서는 여전히 사용합니다. 다음은 header를 구성하는 툴바에 사용되는 스타일입니다:



<header class="center">
  <button id="toggle-left">toggle left</button>
  <button>open</button>
  <button>save</button>
  <span class="spacer"></span>
  <span>filename.txt</span>
  <span class="spacer"></span>
  <button>delete</button>
  <button id="toggle-right">toggle right</button>
</header>

header {
  background-color: #ccc;
  display: flex;
  flex-direction: row;
}

.spacer {
  flex: 1;
}

spacer 클래스는 엘리먼트가 나머지 모든 공간을 차지하도록 합니다. 버튼 사이에 두 개의 spacer를 사용함으로써 필요에 따라 툴바를 좁히거나 늘일 때도 파일명을 항상 중앙에 위치시킬 수 있습니다. 이는 네이티브 툴바와 유사합니다.

다음 Codepen에서 라이브 데모 및 이것 저것 시도해보실 수 있습니다.

See the Pen CSS Grid for UI Layouts by Josh Marinacci (@joshmarinacci) on CodePen.

CSS 그리드는 2차원 복잡도를 갖는 인터렉티브한 어플리케이션을 디자인하는데 훌륭합니다. 마크업을 의미있게(semantic) 유지합니다. 패널과 툴바가 제대로 정렬됩니다. grid-gap은 border를 자동으로 설정해줍니다. Javascript 코드 없이도 복잡한 레이아웃을 조정할 수 있고, 가로 세로 모두에 대한 제어를 할 수 있도록 해줍니다. 그리고 이 모든 것이 무거운 CSS 프레임워크 없이 가능합니다.

Jen Simmons는 새로운 YouTube 채널 Layout Land를 시작해 그리드 동작 방식을 이해할 수 있도록 돕고있습니다. 웹 앱이나 아주 인터렉티브한 웹사이트 작업을 하고 계시다면 CSS 그리드를 한 번 사용해시기 바랍니다.

이 글은 Josh MarinacciCSS Grid for UI Layouts의 한국어 번역입니다.

* “float hacks”는 마땅한 단어가 생각나지 않아 “float 꼼수”로 번역하였습니다.

작성자: Seul Gi Choi

Open Source // Web // Javascript // Map engineer

Seul Gi Choi가 작성한 문서들…


댓글이 없습니다.

댓글 쓰기