스타일

display: grid

richready2011 2022. 8. 25. 14:17

@참조 :

grid 는 css 로 레이아웃을 구현을 도와준다. 이전에 table 태그로 레이아웃을 설계했을 때처럼, 중앙정렬 이라던지, 격자형태의 레이아웃 구현을 가능하게 한다.

현재의 레이아웃 구현방식은 block element 에 높이나 너비를 조정하고, floatposition 을 통해서 해당요소를 배치하는 형태이다.

gridflex 와 성격이 비슷한 부분이 있기 때문에, 비교대상이 된다.

gridflex

flexgrid가 박스모델을 배치한다는 성격의 유사함 때문일까? 표준문서에서도 이를 서두부터 비교하고 있다. (https://www.w3.org/TR/css-grid/#intro)

flex가로축 혹은 세로축 기준의 1차원배열식 으로 나열 한다면, grid가로,세로축을 가지는 2차원배열식 으로 나열하는 방식이다.

즉 한방향으로 배치하는 것(가로축 혹은 세로축)에는 flex 가 맞다.

가로세로축을 생각해야 하는 배치에는 grid 가 더 어울린다.

flex와 grid는 분명한 용도의 차이 가 있고, 성격적으로 보자면, 구글의 이미지검색 서비스처럼, 적층식으로 나열하는 방식에는 flex 가 어울리고, 2차원 형태의 레이아웃 구현 을 위해서는 grid 가 좋아 보인다.

예제로 비교해 보자

<!doctype html>
<html>
<head></head>
<body>
<header> 
    <div>홈</div> 
    <div>검색</div> 
    <div>로그 아웃</div> 
</header>
<style>
* { margin:0; padding:0; }
header { background: gold; }
div { color:hotpink; padding:10px; }
</style>
</body>
</html>

여기에 flex 를 적용하자

<!doctype html>
<html>
<head></head>
<body>
<header> 
    <div>홈</div> 
    <div>검색</div> 
    <div>로그 아웃</div> 
</header>
<style>
* { margin:0; padding:0; }
header { display:flex; background: gold; }
div { color:hotpink; padding:10px; }
</style>
</body>
</html>

여기서 로그아웃 버튼을 우측에 배치한다면 아래와 같은 코드가 될 것이다.

<!doctype html>
<html>
<head></head>
<body>
<header> 
    <div>홈</div> 
    <div>검색</div> 
    <div>로그 아웃</div> 
</header>
<style>
* { margin:0; padding:0; }
header { display:flex; background: gold; }
div { color:hotpink; padding:10px; }
div:nth-child(3) { margin-left: auto; }
</style>
</body>
</html>

가로형 배치에 대해서 예제를 보았다. 이것을 grid 로 변경하면 다음과 같이 된다.

<!doctype html>
<html>
<head></head>
<body>
<header> 
    <div>홈</div> 
    <div>검색</div> 
    <div>로그 아웃</div> 
</header>
<style>
* { margin:0; padding:0; }
header { 
    display:grid; grid-template-columns : repeat(10, 1fr); 
    background: gold; 
}
div { color:hotpink; padding:10px; }
div:nth-child(3) { grid-column: 10; }
</style>
</body>
</html>

grid 는 사용할 때, column 을 어떻게 나눌지를 grid-template-columns 를 사용해서 지정한다. flex 는 해당 컬럼을 어떻게 나눌지 지정을 안해도 자동으로 배치되는 것과 다르다.

만약 grid-template-columns 를 지정하지 않으면, column에 대한 지정이 없으므로, 종렬로 자동 등분된다.

<!doctype html>
<html>
<head></head>
<body>
<header> 
    <div>홈</div> 
    <div>검색</div> 
    <div>로그 아웃</div> 
</header>
<style>
* { margin:0; padding:0; }
header { 
    display:grid; 
    background: gold; 
}
div { color:hotpink; padding:10px; }
div:nth-child(3) {  }
</style>
</body>
</html>

본격적으로 grid 의 속성들을 들여다보자.

grid 컨테이너가 가지는 속성

display: grid 를 설정하면 grid 속성을 사용할 수가 있다.

이 속성은 6가지 다른 속성에 대한 축약형이고, 기본값은 none 이다.

  • grid-template-rows : 세로축 지정하기
  • grid-template-columns : 가로축 지정하기
  • grid-template-areas : 미리지정된 그리드영역의 이름을 이용해서 배치
  • grid-auto-rows : 배치되는 아이템의 높이 지정
  • grid-auto-columns : 배치되는 아이템의 너비 지정
  • grid-auto-flow : 배치의 흐름을 지정한다.

grid: none|grid-template-rows / grid-template-columns|grid-template-areas|grid-template-rows / [grid-auto-flow] grid-auto-columns|[grid-auto-flow] grid-auto-rows / grid-template-columns|initial|inherit;

grid-template, grid-template-rows, grid-template-columns

그리드 아이템들의 너비,높이 를 어떻게 가져갈 것인가에 있다.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid"> 
    <div class="grid-item">1</div> 
    <div class="grid-item">2</div> 
    <div class="grid-item">3</div>
    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>
    <div class="grid-item">7</div>
    <div class="grid-item">8</div>
    <div class="grid-item">9</div>
    <div class="grid-item">1000000</div> 
</div>
<style>
* { margin:0; padding:0; }
.grid { 
    display:grid; 
    grid-template-columns : 20px 20px 100px 20px 30px; 
    background: gold; 
}
.grid-item { 
    color:hotpink; 
    padding:10px; 
}
</style>
</body>
</html>

grid-template-columns 에 5가지를 대입하였기 때문에, .grid-item 의 배치들이 5컬럼으로 표현되었다.

grid-template-rows 를 대입해 보자.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid"> 
    <div class="grid-item">1</div> 
    <div class="grid-item">2</div> 
    <div class="grid-item">3</div>
    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>
    <div class="grid-item">7</div>
    <div class="grid-item">8</div>
    <div class="grid-item">9</div>
    <div class="grid-item">1000000</div> 
</div>
<style>
* { margin:0; padding:0; }
.grid { 
    display:grid; 
    grid-template-columns : 20px 20px 100px 20px 30px; 
    grid-template-rows : 50px 50px 50px;
    background: gold; 
}
.grid-item { 
    color:hotpink; 
    padding:10px; 
}
</style>
</body>
</html>

rows 로 3가지를 지정했더니, 50px 3줄이 생겼다.

auto 값도 가능한데, 중간에 auto 를 넣어보면,

<!doctype html>
<html>
<head></head>
<body>
<div class="grid"> 
    <div class="grid-item">1</div> 
    <div class="grid-item">2</div> 
    <div class="grid-item">3</div>
    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>
    <div class="grid-item">7</div>
    <div class="grid-item">8</div>
    <div class="grid-item">9</div>
    <div class="grid-item">1000000</div> 
</div>
<style>
* { margin:0; padding:0; }
.grid { 
    display:grid; 
    grid-template-columns : 20px auto 100px auto 30px; 
    grid-template-rows : 50px 50px 50px;
    background: gold; 
}
.grid-item { 
    color:hotpink; 
    padding:10px; 
}
</style>
</body>
</html>

이와 같이 명시된 px 외에는 자동으로 너비를 넓혀주고 있는데, 2번째와 4번째의 너비가 동일하다는 것을 주의깊게 보자. 나머지 auto 적용되는 요소들은 남은 너비를 등분해서 가져같다는 것을 확인할 수 있다.

grid-template-rows 도 동일한 공식이 적용된다.

기타 속성값으로 max-content, min-content 등을 지정할 수 있는데, 해당컬럼 혹은, 해당로우에 최대값 혹은 최소값 기준으로 적용된다.

이 외에 값에 대한 단위로 fr 단위를 쓰는 경우가 있다. 분수(fraction) 를 표현하는 단위로 grid 로 설정된 아이템들에게 적용된다. 쉽게 얘기해서 남는 공간에 대한 비율이다.

.grid {
    display: grid;
    grid-template-columns: auto 100px 1fr 2fr;
}

3번쨰는 1/3 공간을 차지하고, 4번째는 2/3 공간을 차지하는데, grid-template-columns: auto 100px 200px auto; 라고 했을때 auto 는 남는공간을 같은 크기로 등분하는데 반해 fr 단위를 사용했을 때에 auto 적용하는 부분은 최대값으로 너비가 결정되는 차이가 있다. 이렇게 단위가 충돌함으로 인해, 계산이 변칙적인 성격을 가지게 되면 오류의 요소를 찾기 어렵기 때문에, auto와 fr은 혼용해서 사용하지 않는 것이 좋다.

축약표현으로 grid-template: 150px / auto auto auto; 이렇게도 사용한다.
grid-template: rows / cols

grid-auto-columns, grid-auto-rows

grid-template-columns 가 일일히 칸을 지정한다면 grid-auto-columns는 한번에 지정한다.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid"> 
    <div class="grid-item">1</div> 
    <div class="grid-item">2</div> 
    <div class="grid-item">3</div>
    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>
    <div class="grid-item">7</div>
    <div class="grid-item">8</div>
    <div class="grid-item">9</div>
    <div class="grid-item">1000000</div> 
</div>
<style>
* { margin:0; padding:0; }
.grid { 
    display:grid; 
    grid-auto-columns: 60px;
    background: gold; 
}
.grid-item { 
    color:hotpink; 
    padding:10px; 
}
</style>
</body>
</html>

columns 를 지정했는데, 가로로 배치되지가 않았다. 그래서 이 속성은 혼자서 사용할 수 없다. 그리드를 좀더 구체화 할 수 있는 다른속성과 같이 사용해야 한다.

예를들어 그리드아이템에 적용할 수 있는 grid-column 같은 속성과 같이 사용하면 너비를 참조해서 렌더링 해준다.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid"> 
    <div class="grid-item">1</div> 
    <div class="grid-item">2</div> 
    <div class="grid-item">3</div>
    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>
    <div class="grid-item">7</div>
    <div class="grid-item">8</div>
    <div class="grid-item">9</div>
    <div class="grid-item">1000000</div> 
</div>
<style>
* { margin:0; padding:0; }
.grid { 
    display:grid; 
    grid-auto-columns: 60px;
    background: gold; 
}
.grid-item {
    color:hotpink; 
    padding:10px; 
    grid-column: 2/4;
}
</style>
</body>
</html>

grid-auto-columns 에 지정된 60px 을 기준으로 2칸을 차지하였다.

grid-auto-columns, grid-auto-rows 는 그리드의 남는 공간을 채우는 하나의 옵션으로 이해하면 될 거 같다.

grid-auto-flow

그리드의 흐름을 정한다. 기본값은 row 이다.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid"> 
    <div class="grid-item">1</div> 
    <div class="grid-item">2</div> 
    <div class="grid-item">3</div>
    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>
    <div class="grid-item">7</div>
    <div class="grid-item">8</div>
    <div class="grid-item">9</div>
    <div class="grid-item">1000000</div> 
</div>
<style>
* { margin:0; padding:0; }
.grid { 
    display: grid; 
    grid-auto-flow: row;
    grid-template-columns: 50px 50px 50px;
    background: gold; 
}
.grid-item {
    color:hotpink; 
    padding:10px; 
}
</style>
</body>
</html>

이게 기본이라면 column 으로 지정하면 배치가 달라진다.

위와 같이 자식으로 있는 그리드아이템이 지정된 그리드영역에 배치되는 흐름에 대한 설정이다.

dense 속성값이 있는데, 이것은 배치하다가 남는 공간을 기준으로 자동배치 인데, row densecolumn dense 같은 row 기준에 남는공간배치column 기준에 남는공간배치 같은 개념이 있다.

만약에 100px 100px 100px 이 있을 경우에 해당 그리드 아이템이 100px을 넘으면 넘길거야? 같은 옵션으로 생각하면 된다.

이것은 그리드에 대한 명시가 명확하지 않고, 논리적으로 지정하는 그리드에서 사용이 용이하다. 예를 들어 grid-column, grid-row 같이 논리적 배치에 대한 단서가 제공될 때 배치를 어떻게 가져갈 것인가에 대해서 활용도가 있다. (반응형 설계에 적합)

이 배치방법은 그리드를 통한 반응형 예제를 통해 따로 살펴봐야 겠다.

grid 가 되는 그리드 컨테이너 가 가질 수 있는 속성에 대해서 알아보았다. 위에 속성들을 축약해서 grid: 100px/ 70px 70px 70px 로 표현할 수 있다.

.grid { 
    display: grid; 
    grid: 100px/ 70px 70px 70px;
    background: gold; 
}

.grid { 
    display: grid; 
    grid-template-columns: 70px 70px 70px;
    grid-template-rows: 100px;
    background: gold; 
}

grid: none|grid-template-rows / grid-template-columns|grid-template-areas|grid-template-rows / [grid-auto-flow] grid-auto-columns|[grid-auto-flow] grid-auto-rows / grid-template-columns|initial|inherit;

이 공식에 맞춰서 다른 설정되지 않는 것들은 기본값으로 설정된다.

grid-gap, grid-column-gap, grid-row-gap

이 외에 그리드 컨테이너가 가지는 속성중에서 이 속성은 그리드 사이에 여백을 지정하는 방법이다.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid"> 
    <div class="grid-item">1</div> 
    <div class="grid-item">2</div> 
    <div class="grid-item">3</div>
    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>
    <div class="grid-item">7</div>
    <div class="grid-item">8</div>
    <div class="grid-item">9</div>
    <div class="grid-item">1000000</div> 
</div>
<style>
* { margin:0; padding:0; }
.grid { 
    display: grid; 
    grid-auto-flow: row;
    grid: 100px/ 70px 70px 70px;
    grid-row-gap: 10px;
    grid-column-gap: 10px;
    background: gold; 
}
.grid-item {
    color:hotpink; 
    padding:10px; 
}
</style>
</body>
</html>

위에 설정은 축약형으로 grid-gap: 10px; 으로 할 수 있다.

그리드아이템이 가지는 속성에 대해서 알아보자.

grid 아이템이 가지는 속성

  • grid-area
  • grid-column
  • grid-row

grid-area, grid-column, grid-row

grid 영역에 대한 이름을 지정한다. 예를 들어 그리드아이템에

.header {
    grid-area: hd;
}
.footer {
    grid-area: ft;
}
.content {
    grid-area: main;
}
.sidebar {
    grid-area: sd;
}

이런 이름을 지정하고,

.grid {
    display: grid;
    grid-template-columns: repeat(9, 1fr);
    grid-template-areas: 
      "hd hd hd hd   hd   hd   hd   hd   hd"
      "sd sd sd main main main main main main"
      "ft ft ft ft   ft   ft   ft   ft   ft";
}

위와 같이 나누어진 그리드의 영역을 배치하는 것이다.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid">
    <div class="header">Header</div>
    <div class="sidebar">Sidebar</div>
    <div class="content">Content</div>
    <div class="footer">Footer</div>
</div>
<style>
* { margin:0; padding:0; }
.grid { 
    display: grid;
    grid-template-columns: repeat(9, 1fr);
    grid-template-rows: 200px auto 100px;
    grid-template-areas: 
      "hd hd hd hd   hd   hd   hd   hd   hd"
      "sd sd sd main main main main main main"
      "ft ft ft ft   ft   ft   ft   ft   ft"; 
}

.header {
    grid-area: hd;
    background: goldenrod;
}
.footer {
    grid-area: ft;
    background: goldenrod;
}
.sidebar {
    grid-area: sd;
    background:indianred;
}
.content {
    grid-area: main;
    background: grey;
}
</style>
</body>
</html>

위의 예제는 모든배치를 지정한 것이지만, 필요한 부분만 지정해두고, 해당 미디어쿼리에서 배치순서를 변경할 수 있다는 것이 장점이다.

위와 같이 이름을 지정할 수도 있지만, 숫자로의 지정도 된다. 지정법은 grid-column: start/end 이다.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid">
    <div class="header">Header</div>
    <div class="sidebar">Sidebar</div>
    <div class="content">Content</div>
    <div class="footer">Footer</div>
</div>
<style>
* { margin:0; padding:0; }
.grid { 
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    grid-template-rows: 100px auto 50px;
}

.header {
    grid-column: 2/5;
    background: goldenrod;
}
.footer {
    grid-column: 1/11;
    background: goldenrod;
}
.sidebar {
    grid-column: 4/7;
    background:indianred;
}
.content {
    grid-column: 4/7;
    background: grey;
}
</style>
</body>
</html>

이렇게 컬럼의 시작과 끝을 지정해서 배치할 수도 있고, grid-row 를 넣으면 겹치게도 가능해진다.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid">
    <div class="header">Header</div>
    <div class="sidebar">Sidebar</div>
    <div class="content">Content</div>
    <div class="footer">Footer</div>
</div>
<style>
* { margin:0; padding:0; }
.grid { 
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    grid-template-rows: 100px auto 50px;
}

.header {
    grid-column: 2/5;
    grid-row: 1/4;
    background: goldenrod;
}
.footer {
    grid-column: 1/11;
    background: goldenrod;
}
.sidebar {
    grid-column: 4/7;
    grid-row: 2/7;
    background:indianred;
}
.content {
    grid-column: 4/7;
    background: grey;
}
</style>
</body>
</html>

위를 축약형으로 사용하면 grid-area: grid-row-start / grid-column-start / grid-row-end / grid-column-end | itemname; 이렇게 된다.

grid를 통한 일반적인 레이아웃 예제

그리드에 대한 속성은 다 보았고, 실제로 적용할 레이아웃을 만들어 보자.

일반적인 레이아웃은 상단헤더, 좌측메뉴, 우측컨텐츠, 하단푸터 이므로, 이것을 기준으로 하면

우선 html,body높이 100% 를 주고, .grid에 height:100% 가 높이를 상속받도록 한다.

컬럼은 10컬럼으로 나누고 header, footer 만 우선 배치해보자

<!doctype html>
<html>
<head></head>
<body>
<div class="grid">
    <div class="header">Header</div>
    <div class="sidebar">Sidebar</div>
    <div class="content">Content</div>
    <div class="footer">Footer</div>
</div>
<style>
* { margin:0; padding:0; }
html,body { height:100%; }

.grid {
    height: 100%;
    display: grid;
    grid-template: 100px auto 50px / repeat(10, 1fr);
}

.header {
    background: goldenrod;
    grid-area: 1/1/1/11;
}
.sidebar {
    background:indianred;
}
.content {
    background: grey;
}
.footer {
    background: goldenrod;
    grid-area: 3/1/3/11;
}
</style>
</body>
</html>

이제 sidebar, content 자리만 잡으면 된다.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid">
    <div class="header">Header</div>
    <div class="sidebar">Sidebar</div>
    <div class="content">Content</div>
    <div class="footer">Footer</div>
</div>
<style>
* { margin:0; padding:0; }
html,body { height:100%; }

.grid {
    height: 100%;
    display: grid;
    grid-template: 100px auto 50px / repeat(10, 1fr);
}

.header {
    background: goldenrod;
    grid-area: 1/1/1/11;
}
.sidebar {
    background:indianred;
    grid-area: 2/1/2/3;
}
.content {
    background: grey;
    grid-area: 2/3/2/11;
}
.footer {
    background: goldenrod;
    grid-area: 3/1/3/11;
}
</style>
</body>
</html>

grid-arearow-start/column-start/row-end/column-end 지정법이 조금 헷갈리긴 하는데, 이렇게 간단한 설정만으로도 100% 레이아웃 을 구성했다는 것에 상당히 만족스럽다. 혹여 html,body의 100% 높이지정으로 인해, 컨텐츠가 안밀려 내려가지 않을까 했는데, 다행이 아주 정상적으로 밀려 내려갔다.

<!doctype html>
<html>
<head></head>
<body>
<div class="grid">
    <div class="header">Header</div>
    <div class="sidebar">Sidebar</div>
    <div class="content">Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content<br>Content</div>
    <div class="footer">Footer</div>
</div>
<style>
* { margin:0; padding:0; }
html,body { height:100%; }

.grid {
    height: 100%;
    display: grid;
    grid-template: 100px auto 50px / repeat(10, 1fr);
}

.header {
    background: goldenrod;
    grid-area: 1/1/1/11;
}
.sidebar {
    background:indianred;
    grid-area: 2/1/2/3;
}
.content {
    background: grey;
    grid-area: 2/3/2/11;
}
.footer {
    background: goldenrod;
    grid-area: 3/1/3/11;
}
</style>
</body>
</html>

이렇게 간단하게 사용할 수 있는 grid 를 사용하지 않을 이유가 없다.