• [CSS] CSS Grid (그리드) 배우기

    2020. 1. 29.

    by. 나나 (nykim)

    320x100

     

     

    프롤로그

     

    레이아웃을 구현할 때 flexbox를 쓰면 참 편합니다. 

    플박만으로 레이아웃을 구현하는 데 큰 문제는 없지만, 보다 정교하고 복잡한 레이아웃에는 그리드가 좋다는 소문(?)을 들었거든요.

    그래서 이번에는 grid를 배워서 좀 더 업그레이드를 해보려고 합니다.

     

    아, 당연하지만 구 버전 IE에 대한 지원은 눈물을 머금고 포기해야 합니다.

    caniuse에 따르면 IE 11부터 부분 지원하고 있는데요, 그냥 Edge부터 잘 먹겠구나~ 라고 보면 될 것 같아요.

     

    파이어폭스(특히 Developer Edition)는 개발자도구에서 CSS 그리드를 더 잘 나타내주고 있으니 학습에 참고하시면 좋겠습니다.

     

     

     

     

     

    그리드, 일단 써봅시다

     

    display

     

    플렉스박스를 display: flex; 으로 선언하여 썼던 것처럼, 그리드도 display:grid;를 선언해서 쓸 수 있습니다.

    일단 컨테이너가 될 요소에게 grid를 주면 그때부터 자식 요소들은 Grid Items이 됩니다.

     

    .container {
      display: grid;
    }

     

    grid를 주면 자식 요소들은 Block 속성이 되고, inline-grid를 주면 Inline 속성이 됩니다. (플박과 비슷한 느낌이죠!)

    파이어폭스의 개발자 도구를 열어, grid라고 표시된 부분을 클릭하면 격자 모양으로 컨테이너를 볼 수 있습니다.

     

     

     

     

    grid-template-*

     

    그리드에는 특이하게도 column, row 개념이 존재합니다. 흔히 열과 행이라고 부르는 거죠.

    한글로 작성했더니 좀 헷갈려서 여기선 영어로 부르겠습니다.

    column은 👇(세로) , row는 👉(가로)라고 기억하시면 됩니다.

     

    그리드 시스템에선 이 column과 row를 트랙(Track)이라고도 부릅니다.

     

    자, 그럼 아래 레이아웃에서 column과 row는 몇 개일까요?

     

     

    답은 3개의 column, 2개의 row 입니다.

    아래와 같이 세어보면 바로 감이 오실 거에요.

     

     

     

    자, 그럼 위 형태를 저희가 직접 만들어보겠습니다.

    grid-template-columns와 grid-template-rows라는 속성을 써서 지정해 줄 수 있습니다.

     

    이때, "column이 3개니까 값을 3으로 주면 되나?" 싶을 수도 있는데, 정확히는 각 row의 "크기값"을 입력해야 합니다.

    아이템의 사이즈가 150px*150px이라고 생각하고 아래와 같이 작성하면 됩니다.

     

    .container {
    	display: grid;
    	grid-template-columns: 150px 150px 150px;
    	grid-template-rows: 150px 150px;
    }

     

    그러면 위 이미지처럼 아이템들이 격자 형태로 가지런히 놓인 걸 볼 수 있습니다. 뭔가 테이블 같군요!

     

     

     

     

    이번엔 속성을 다르게 줘봅시다.

    아래 속성을 줬을 때, 어떤 모습으로 보여질지 상상이 되시나요?

     

    .container {
    	display: grid;
    	grid-template-columns: 150px 150px;
    	grid-template-rows: 300px 100px;
    }

     

     

    왜 그런지 하나하나 살펴보면 이렇습니다.

     

    우선 column👇은 150px 150px이란 값을 줬습니다.

    따라서 두 개의 column이 뿅뿅 생기겠죠. 그리고 첫 번째도 두 번째도 동일하게 150px이란 너비를 갖습니다.

     

     

    한편 row👉의 경우 300px 100px이란 값을 줬었죠.

    그래서 첫 번째 row는 300만큼의 높이를, 두 번째 row는 100만큼의 높이를 갖습니다.

    그 이후의 row는 지정된 높이가 없으니 자식 요소만큼의 높이(=auto)를 가졌고요.

     

     

     

    참 신기하네요 😎

    그럼 아래의 레이아웃은 어떤 속성을 줬는지 짐작해 보실 수 있을 거에요.

     

     

    일단 column이 총 3개네요. 첫 번째는 넓고, 두 번째는 좁고, 세 번째는 보통이네요. 그럼 300, 50, 100 정도 주면 될 것 같아요.

    row는 2개입니다. 첫 번째는 길고, 두 번째는 짧아요. 그럼 200, 50 정도면 되지 않을까요?

    답은 이렇습니다!

     

    .container {
    	display: grid;
    	grid-template-columns: 300px 50px 100px;
    	grid-template-rows: 200px 50px;
    }
    

     

    See the Pen CSS Grid (1) by nanalike (@nykim_) on CodePen.

     

     

     

     

     

     

     

     

     

    한편, 작성의 편의를 위해 각 라인에 이름을 지어줄 수도 있습니다.

     

    .container {
    	display: grid;
    	grid-template-columns: [first] 100px [second] 200px;
    }

     

     

    뭔가 flexbox와는 비슷하면서도 다른 느낌이네요. 더 유연해진 테이블 같은 느낌이기도 하고요.

    어쨌든 뭔가 감이 와요! 이 자신감을 갖고 계속 진행해 봅시다.

     

     

     

     

    repeat() 함수와 fr 단위

     

    자, 여기 900px 너비의 컨테이너가 있습니다. 이걸 9 column으로 만들 거에요.

    그럼 grid-template-column: 100px 100px 100px 100px 100px 100px 100px 100px 100px; 라고 써주면 되겠네요.

    ........어... 좀 많이 불편한데요.

     

    이럴 때 쓰윽 꺼내 쓰는 게 repeat() 함수입니다.

     

    .container {
    	width: 900px;
    	display: grid;
    	grid-template-columns: repeat(9, 100px);
    }

     

     

    한편, 컨테이너의 크기가 고정되어 있지 않은 경우라면 아이템 크기를 비율로 지정하고 싶을 때가 있을 텐데요.

    이때 %를 사용해도 되지만, 유지보수 등을 고려해 좀 더 유연한 단위를 지정하고 싶을 때가 있습니다.

    이 경우에는 fr 단위를 사용합니다.

     

    fraction(분수)라는 이름에 맞춰, 이 단위는 사용 가능한 공간의 일정 비율을 나타냅니다.

    아이템이 6개 있는 상태에서 1fr 1fr 1fr을 지정하면...

     

    .container {
    	display: grid;
    	grid-template-columns: 1fr 1fr 1fr;
    }

     

    각 아이템이 1/3만큼의 column을 차지한 걸 볼 수 있습니다. 3의 fr 중에서 1만큼 차지한다-고 보면 되겠네요.

    그럼 이 경우엔 어떨까요?

     

    .container {
    	display: grid;
    	grid-template-columns: 2fr 1fr 1fr;
    }

     

    그럼 공간은 4개로 나뉘게 되고 (2+1+1=4), 첫 번째 column은 2/4만큼 가집니다. 그런 다음 남은 1/2를 두 번째와 세 번째 column이 하나씩 차지합니다.

    만약 컨테이너 너비가 1000px이라고 한다면, 각각 500px, 250px, 250px이 되겠죠? 컨테이너 너비가 유동적이라면 브라우저가 그에 맞춰 아이템 크기를 조절해줄 것입니다.

     

     

     

    한편, 이런 식으로 단위를 복합적으로 쓸 수도 있습니다.

    윈도 너비를 조절하면서 각 아이템이 어떻게 변하는지 확인해 보세요.

     

    .container {
    	display: grid;
    	grid-template-columns: 120px repeat(3, 1fr) 2fr 10%;
    }

    See the Pen CSS Grid (2) by nanalike (@nykim_) on CodePen.

     

     

     

     

     

     

     

     

     

    그리드 내 아이템 배치하기

     

     

    grid-line

    저런 네모네모 블록쌓기 말고, 좀 더 다양한 형태의 레이아웃을 짜고 싶을 땐 어떻게 하면 좋을까요?

    그럴 땐 각 아이템의 위치와 크기를 조정하는 속성을 사용합니다.

     

    우선 아이템이 4개 있는 컨테이너에게 column과 row를 지정해 줬습니다.

     

    .container {
    	display: grid;
    	grid-template-columns: 150px 150px 150px;
    	grid-template-rows: 150px 150px;
    }

     

    그런 다음 첫 번째 아이템에게 아래와 같은 속성을 추가합니다.

     

    .item1 {
        grid-column-start: 1;
        grid-column-end: 4;
    }

     

    오!! 첫번째 아이템이 치즈처럼 쭈우욱 늘어났네요. 왜냐면 1에서 시작해서 4에서 끝나도록 설정했으니까요.

    으으음?? column은 세 개 아니였나요? 4가 왜 거기서 나와....?? 🌸

    다소 혼란스럽겠지만, 여기서의 숫자는 정확히는 그리드 라인(Grid Line)을 가리키기 때문입니다.

     

     

     

    이렇게 라인이 4개가 있다고 보면 됩니다.

    item1이 1에서 시작해 4에서 끝나도록 설정했다는 게 눈에 확 들어오죠!

    그리고 같은 row에 있던 item2와 item3은 다음 row로 밀려난 것도 볼 수 있습니다.

     

     

    끝 지점을 지정하는 게 귀찮다고 한다면, span을 이용해 column 넓이를 지정할 수도 있습니다.

     

    .container {
    	display: grid;
    	grid-template-columns: repeat(3, 1fr);
    }
    
    .item4 {
      grid-column-end: span 2;
    }
    
    .item6 {
      grid-column-end: span 3;
    }

     

     

    위 레이아웃에서 item4는 2만큼, item6은 3만큼 늘어난 걸 눈으로 볼 수 있죠!

     

     

    row 역시 마찬가지로 grid-row-start와 grid-row-end를 지정할 수 있습니다.

     

    .container {
    	display: grid;
    	grid-template-columns: repeat(4, 1fr);
    	grid-template-rows: repeat(2, 100px);
    }
    
    
    .item4 {
    	grid-row-start: 2;
    	grid-column-end: span 3;
    }

     

    grid-row-start를 2로 지정했더니 item4가 두 번째 row로 슈슈슉 이동했네요.

     

     

     

     

    grid-column, grid-row

    난 입력하는 것마저 귀찮다! 그럴 때는 그냥 grid-column 속성 하나에 다 때려써도(?) 됩니다.

    예를 들어, grid-column: 2/ 5; 는 start가 2고 end가 5입니다.

    grid-column: 3 / span 3; 이면 라인 3에서 시작해서 3칸을 차지하겠죠?

     

    .container {
    	display: grid;
    	grid-template-columns: repeat(4, 1fr);
    }
    
    .item2 {
    	grid-column: 2 / 5;
    }

     

     

    grid-row도 마찬가지로 start와 end 속성을 한 번에 입력할 때 사용합니다.

     

     

    지금까지 배운 걸 응용한다면 이런 레이아웃도 만들 수 있어요!

    스크롤을 다 내리기 전에 어떤 grid-column, grid-row를 줬을지 생각해 보세요 ;)

     

     

    하나하나 봅시다.

    그림을 봤을 때 column은 총 3개이고, row는 4개네요.

    따라서 아래처럼 템플릿을 정해주면 되겠습니다.

     

    .container {
    	display: grid;
    	grid-template-columns: repeat(3, 130px);
    	grid-template-rows: repeat(4, 130px);
    }

     

    이제 개별 아이템을 지정할 차례입니다.

     

    item1과 item3, item6은 column을 늘리고, item2는 row를 늘리면 되겠군요.

    end 지점을 콕 지정해줘도 되고 span 2와 같이 지정할 수도 있겠네요!

     

    .item1 {
    	grid-column: 1 / 4;
    }
    
    .item2 {
    	grid-row: 2 / 4;
    }
    
    .item3 {
    	grid-column : 2 / span 2;
    }
    
    .item6 {
    	grid-column : 1 / span 3;
    }

     

     

     

    See the Pen CSS Grid (3) by nanalike (@nykim_) on CodePen.

     

     

     

     

     

     

    grid-area

    한편, grid-area를 써서 column과 row 모두 한 번에 지정하는 것도 가능합니다.

    총 4개의 값이 들어가며, 순서대로 grid-row-start, grid-column-start, grid-row-end, grid-column-end를 지정합니다.

     

    .item7 {
    	grid-area: 2 / 1 / 2 / 4;
    }

     

     

     

     

     

    grid-gap

    행과 행, 열과 열 사이에 간격을 지정해줄 수 있습니다.

    더 정확히는, Grid Line의 두께를 지정해준다고 할 수 있겠네요.

     

    이 값은 컨테이너에게 지정합니다.

    .container {
    	display: grid;
    	grid-template-columns: repeat(3, 130px);
    	grid-template-rows: repeat(2, 130px);
    	column-gap: 30px;
    	row-gap: 30px;
    }

     

     

    이 속성도 마찬가지로 줄여서 쓸 수 있어요.

    순서는 row-gap, column-gap 입니다.

     

    .container {
      gap: 30px 10px; //row-gap:30px; column-gap:10px;
    }

     

     

     

    align-content / justify-content

    어라? 어디서 본 속성 같은데요? 넵, flexbox에서 사용하던 것과 같습니다.

     

     

    세로축으로 정렬하는 align-content와 가로축으로 정렬하는 justify-content까지 기능이 같습니다.

    사용할 수 있는 값도 start, center, end, space-around, space-between, space-evenly, stretch로 똑같아요.

     

     

     

     

    minmax()

    column, row의 최소 / 최대 크기를 지정합니다.

    인자 두 개가 필요한데, 각각 min값 / max값에 해당합니다.

    이 값을 지정해 두면 해당 크기보다 작아지거나 커지지 않습니다. (min-width, max-width랑 비슷해요!)

     

     

     

    auto-fill

    column, row의 개수를 컨테이너에 맞게 자동적으로 조절해 줍니다. 따라서 쉽게 반응형을 만들 수 있습니다.

    repeat() 함수와 minmax() 함수랑 궁합이 잘 맞아요.

     

    .container {
    	display: grid;
    	grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    }

     

    아래 결과는 위 코드를 지정한 모습입니다. 화면 크기를 조절하면 컨테이너 너비에 따라 아이템이 자동 줄 바꿈 되는 걸 볼 수 있어요.

     

    See the Pen CSS Grid (4) by nanalike (@nykim_) on CodePen.

     

     

     

     

    자, 현재 컨테이너 너비가 200px이라고 합시다.

    그럼 최소 너비인 150px 이상이고, 1fr씩 늘어나게 했으니 각 아이템의 너비는 200px이 됩니다.

     

     

     

    이 상태에서 컨테이너 너비가 늘어나면 아이템 너비도 그에 맞춰 옆으로 쭈우욱 늘어납니다.

    그러다가 column이 2줄이 되는 순간이 오는데 바로, 컨테이너 너비가 300px이 되는 순간입니다.

     

     

     

    최소 사이즈인 150px 2개가 올라오려면 컨테이너 너비가 최소 300px은 되어야 한다는 뜻이니까요.

    이 상태에서 컨테이너 너비가 늘어나면 아이템도 그에 맞춰 쭈우욱 늘어나게 됩니다.

    자, 그럼 column이 4가 되는 순간은 언제일까요?

     

     

     

    컨테이너가 최소 150px짜리 아이템 4개를 수용할 수 있어야 하니, 600px일 때이겠죠.

    그리고 이때 아이템 너비는 다시 150px이 될 거고요.

     

    이걸 응용한다면 보다 손쉽게 반응형 작업이 가능할 거 같네요!

     

     

     

     

     

    응용하기 (예제)

    지금까지 배운 내용을 활용해 간단한 레이아웃을 만들어봤습니다 🤟

    전체 레이아웃과, 메인 영역 레이아웃을 grid로 설정했습니다. 기존과는 전혀 다른 스타일링이라 신선하고 새롭네요.

     

    See the Pen Web Layout Example with CSS Grid by nanalike (@nykim_) on CodePen.

     

     

     

    에필로그

    짧게나마 다뤄본 소감으로는 "역시 신기술!"이란 느낌이네요.

    플박은 세부적으로 다루는 느낌이라면, 그리드는 전체를 보고 다루는 느낌이라고 해야 할까요.

    하지만 아직까지는 플렉스가 조금 더 활용면에서 우위일 것 같아요. 좀 더 연구해보고 다방면으로 활용해보려고요 :^)

     

    아, 그리고 여기서 다룬 내용은 빙산의 일각, 아니 0.5각...? 정도에요.

    제가 적지 않은 속성도 많으니, 필요하신 경우 아래 참고글을 보시면 되겠습니다.

    긴 글 읽느라 고생하셨어요! (하이파이브 🙌)

     

     

     

    참고글

    5분 안에 css grid 배우기

    CSS Grid Layout Guidebook

    CSS Grid 완벽 가이드

    Basic concepts of grid layout

     

     

     

    728x90

    댓글