제목 : CSS grid 란 무엇이고, 어떻게 사용할까?
이 글을 작성하는 이유 :
아주 최근에 작성한 CSS 에 대한 글 몇 개와 연동하여
알아야 할 지식으로 생각하여 CSS grid 에 대해서 다루게 되었다.
이전 글은,
예제와 함께 알아보는 CSS flex 와 Flexbox
위의 3 글이며,
레이아웃의 핵심인 Flexbox 와 더불어, Grid 에 대해서도 알아보려고 한다.
혹시라도 CSS 에 대해서 잘 모르시는 분이 있다면,
위의 3 개의 글을 순차적으로 읽고 오시면 도움이 됩니다.
그리고, 질문은 환영이기 때문에,
으로 메일을 보내주시면 감사하겠습니다.
내가 예제를 블로그에 만드는 방법
나의 블로그 템플릿은 hELLO 라는 템플릿에서 나의 커스텀 CSS 를 덧붙인 형태이기 때문에,
현재 블로그 스타일 시트의 영향을 받는다면, 날 것의 형태를 볼 수 없다.
따라서, 내가 선택한 방식은 iframe 태그를 이용하여 현재 페이지에 종속되어 있는 StyleSheet
로부터 떼어놓는 방식이다.
혹시라도 블로그를 작성 할 생각이 있다면, 내가 사용하는 방식은 추후 많은 도움이 될 것이다.
예시 :
<iframe
style="width:70%; max-height:20rem;"
srcdoc='
<style>
body {
background : white;
}
</style>
<body>
기본 상태는 이러합니당
</body>
'
>
<p>이 문구가 보인다면, iframe 이 막혀 CSS 예시를 볼 수 없습니다.
</iframe>
이 사이트 자체에서 iframe 의 백그라운드는 투명에 속하기 때문에,
강제로 하얀색으로 초기화 시키고 시작한다.
<head> 에 메타데이터로 스타일을 넣지 않아도,
이러한 형식으로 분리된 HTML + CSS + JS 형식을 만들 수 있다.
Grid 란 무엇인가?
개별 컴포넌트는 외부(부모, 형제) 컴포넌트가 자신을 어떻게 인식할지,
내부에 포함된 컴포넌트는 "어떻게 정렬될지" 선택할 수 있다.
이러한 정렬은 display 라는 CSS 속성으로 결정된다.
HTML 태그는 정말 다양한데, 리스트, 테이블, 단순 영역 등등
고유의 HTML 태그들은 제 역할에 맡게 적당한 display Default 값을 가지고 있다.
우리가 다루는 display 속성은, 주로 여러 컴포넌트를 담게 되는 오브젝트에 선언하게 된다.
즉, 우리는 여러 컴포넌트를 담을 컨테이너가 하위 요소를 어떻게 정렬 할 지 선택 할 수 있다.
div, section, article, 과 같은 영역 태그들은 block 이라는 기본 값이 있으나,
개발자들의 무한한 스타일링 기법을 충족시키기 위해,
display : flexdisplay : grid
가 대표적으로 존재한다.
Flex 란, 컨테이너가 내부 컴포넌트를 1차원 나열 형식으로 표현하고자 할 때 사용되며,
flex-wrap : wrap 이라는 명시를 통해 다양한 너비의 디바이스에서
크기에 따른 자동 줄넘김을 유도 할 수 있다.
flex 에 대해서 더 자세한 것은,
예제와 함께 알아보는 CSS flex 와 Flexbox
여기서 배우고 오면 이해가 될 것이다.
그렇다면, Grid 란 무엇일까?
Grid 란, 내부 컴포넌트를 row 와 column 나열 형태로 표현하기 위해 존재한다.
즉, 2차원이라고 말할 수 있다.
row(행), column(열) 을 직접 선언하는 것이 언제 중요하냐고 할 수 있을 테지만,
헤더, 사이드바, 아티클 등등 여러 요소가 순서대로 항상 배치되어야 할 때
grid 를 사용하여 간단하게 해결 할 수 있다.
grid 에 추가되는 다양한 속성들
Grid 기본 속성 (Grid)
grid-template-columnsgrid-auto-columnsgrid-template-rowsgrid-auto-rows
Grid 영역 속성 (Grid Areas)
grid-areagrid-template-areas
Grid 영역의 새로운 단위
fr
Grid 에서 사용되는 함수
repeat()minmax()fit-content()
Grid 의 아이템 배치
grid-column-startgrid-column-endgrid-row-startgrid-row-end
Grid 의 여백
grid-column-gapgrid-row-gapgrid gap
Grid 의 단축어(짧은 표기) 속성
grid-columngrid-rowgrid-templategrid
위와 같이 Grid 디스플레이를 위해 다양하며 새로운 속성들이 기다리고 있다.
Grid 에서 알아야 할 용어에 대한 설명
그리드에서부터는 위에서 언급한 새로운 특화 속성들을 자유로이 다루기 위해서,
Term(사용될 용어) 를 간단하게 볼 필요가 있다.
그래서 따로 이미지를 만들어 봤다.
Grid Line
Grid Line 은 시작 지점을 나타내는 용도이다.
시작 인덱스는 0 이 아니라, 1 부터 시작한다.
추후 사용될 이 용어와 의미는 Column, Row 둘 다 동일하게 적용된다.
Grid Track
행을 의미하는 Row 로 작성되지 않고, 여기서는 Track 이라고 불린다.
왜 하나의 줄이라고 부르지 않고, 도대체 왜 "트랙" 이라고 부르는가? 해서 의미를 계속 살펴보았다.
여기서 위의 Grid Line 과 연관되어 나오는데,
"행 트랙" 이란, 두 행(row) Line 사이에 있으며,
"열 트랙" 이란, 두 열(column) Line 사이에 있다는 것이다.
여기서나는 Line 을 공간으로 바라보았는데,
그게 아니고, 위에 설명된 진짜 "그어진 Grid Line" 으로 바라보아야 한다.
사실상 이 라인까지도 포함된 개념을 Row 혹은 Column 으로 보고,
"그 사이의 공간" 을 Track 이라고 부르는 것이다.
Grid Cell
셀은 간단하다. 위에서 말한 영역, 즉, Grid Line 사이의 영역을 Track 이라고 말했다면,
이 Cell 은 이 자리의 "행 Track", "열 Track" 의 교차 영역을 의미한다.
이렇게 어렵게 설명하는 이유는, 간단히 말해 경계선을 포함시키지 않기 위함이다.
Grid Area
위의 용어는 특정 엘리먼트, 혹은 위치에 배치된 엘리먼트가
글 작성 시 줄넘김 하는 것 처럼 넘어가지 않고,
해당 위치에서 정해진 위치까지 포함하도록 만든다.
Grid Gap
내부에 채워질 각 엘리먼트들의 Margin 이라고도 볼 수 있다.
각 엘리먼트가 얼마나 떨어져 있을지 선언한다.
새로운 단위, fr
display : flex 환경에서는 굉장히 유용하게 사용되는 기능이 존재하는데,
바로 비율로 각 컴포넌트가 얼마나 이 컨테이너를 차지 할 것인지를 지정하는 것이다.
단축 키워드인 flex 를 이용할 수 있는데,
하위 엘리먼트에서 스스로 flex : 1, flex : 2 가 선언되었다면,
각 엘리먼트는 1/3, 2/3 의 공간을 차지 할 것이다.
이 fr 이라는 단위는 나중에 CSS 의 "함수" 와 직접적으로 연관되어 있다.
아직 현재는 fr 이라는 단위가, 선언된 위치에 따라 해당 Column, or Row 가
이 단위와 함께 비율적으로 커지거나 작아진다는 것이다.
예를 들어, grid-template-column : 1fr 1fr 1fr 2fr; 으로 선언 될 경우,
- 하나의 트랙에 들어가는 순서, column(열) 에 따라
1 : 1 : 1 : 2비율로 너비가 나뉜다. - 엘리먼트가 6 개 일 경우, 2 줄로 편성되며, 배치된 열에 따라 위와 같은 비율의 너비를 가진다.
- 엘리먼트가 그보다 작은 2 일경우,
1 : 1로 계산되지 않으며,
배치되지 않은1fr 2fr은 빈 칸으로 간주한다.
위의 설명을 본다면, fr 이라는 단위는 "비율" 에 해당한다는 것을 알 수 있다.
그리고, 이 단위는 px, em, .. 등등 정확한 절대 단위와 같이 사용될 수 있다.
fr 은 이 절대적인 값들과 Gap 을 뺀 나머지 영역에서 fr 비율로 나눈다.
Grid 를 사용 해 보자.
display : flex 를 통해 Flexbox 를 본격적으로 여는 것 처럼,
Grid 는 display : grid 를 통해 2차원 엘리먼트 배치를 본격적으로 구성하게 해 준다.
grid-template-xxx (행, 열)
grid 는 행, 그리고 열 을 선언하는 특수? 전용 속성이 존재한다.
바로,
grid-template-columns: 열 설정grid-template-rows: 행 설정
여기서 다른 css 속성과는 확실히 다른 점이 존재하는데,
바로 인자의 개수 제한이 없다시피 한다는 것이다.
인자의 개수 제한이 없다는 게 무슨 의미일까?
CSS 에서 Propertie : Value 선언 쌍을 이루는 것이 일반적이다.
그러나, 몇몇 속성에서는 다중 값 선언이 허용된다.
예를 들어,
display : inline flex;: 블록이 아닌 인라인 형식, 그리고 Flexbox.border-width : 0 0 10px 0;: 아래에 10px 의 경계선이 있으며, 나머지는 경계가 안보임flex : 2 0 auto: flex-item 에서 선언할 수 있는데, 이 아이템은 비율 수준 2 를 가져간다.
생각나는 다중 값 속성들은 일단, 이러하다.
그리고, grid-template-xxx 에 해당하는 이 2 가지 속성은,
grid-template-??? : 100px 1fr 100px 10px 10px 10px ...
이러한 식으로 거의 무한하게 뻗어나갈 수 있다.
그리고 위의 값이 선언된다면, 이러한 의미가 된다.
row or column 에서의 의미 (행이던 열이던 상관이 없음.)
1 번째 인자 : 절대적인 100px 확보
2 번째 인자 : 남는 공간에서 비율 1 을 가져간다.
3 번째 인자 : 절대적인 10px 확보
4 번째 인자 : 동일
... 10px 이 지속적으로 이어진다고 가정.
그렇다면, 행과 열 개수를 자유롭게 바꾸기 어렵지 않나?
라고 생각을 했었는데, 그렇지 않다. 바로, CSS 문법의 "함수" 가 존재하기 때문이다.
함수를 사용하기까지는 아직 내가 적응이 된 것은 아니라서, Grid 의 기초를 다루며 천천히 진입 할 것이다.
내가 만든 예제를 살펴보자.
.container {
/* grid 선언 */
display : grid;
/* 이 컨테이너는 20 rem 의 너비를 고정적으로 가진다 */
width : 20rem;
margin : 1rem;
border : 4px solid black;
/* grid 컨테이너 내부의 요소들이 서로 간격을 10px 로 떨어진다 */
gap : 10px;
/* 내가 선언하는 '열' 이 가질 요소 */
grid-template-columns : 50px 1fr 30%;
}
div {
text-align : center;
border : 2px solid gray;
border-radius : 3px;
box-shadow : 0 5px 5px 0 darkgray;
}
<body>
<button onclick="plusElem()">요소 추가하기</button>
<br/>
<section class="container" id="container">
<div>
1
</div>
</section>
<script>
const container = document.getElementById("container");
let currNum = 2;
function plusElem() {
const newElem = document.createElement("div");
newElem.textContent = currNum++;
container.appendChild(newElem);
}
</script>
</body>
Preview :
end
위의 예제에 아주 간단한 엘리먼트 추가 기능을 넣었는데,
이는 엘리먼트가 하나의 Track 에서 포함 기준치를 넘어가면,
어떻게 엘리먼트를 배치하는지 직관적으로 보여주기 위함이다.
위에서 내가 선언한 Grid Template 을 보자.
grid-template-columns : 50px 1fr 30%;
첫 번째 요소는 고정적으로 50px 을 얻으며,
세 번째 요소는 Grid Container 의 영역에 따라 30% 를 가진다.
그리고 남은 Free Area 는,
유일하게 이 단위를 사용하는 두 번째 요소에 남는 영역을 모두 몰아준다.
따라서 위의 예제를 보면, 2 번째 요소가 제일 큰 것이다.
만약에 위의 1fr 을 3fr 로 바꿔도, 같은 단위를 사용하는 "열" 이 없기 때문에,
동일하게 너비를 가진다.
만약에 50px 1fr 30% 1fr 이라면,
50px, 30% 에 해당하는 너비를 뺀 결과를,
1fr, 1fr 이 서로 비율로 1/2, 1/2 로 나눠 갖는다.
그렇다면, 반대로 grid-template-rows 만 선언되면 어떻게 될까?
.container {
/* grid 선언 */
display : grid;
/* 이 컨테이너는 20 rem 의 높이를 고정적으로 가진다 */
height : 20rem;
margin : 1rem;
border : 4px solid black;
/* grid 컨테이너 내부의 요소들이 서로 간격을 10px 로 떨어진다 */
gap : 10px;
/* 내가 선언하는 행 이 가질 요소 */
grid-template-rows : 50px 1fr 30%;
grid-auto-flow : column;
}
div {
text-align : center;
border : 2px solid gray;
border-radius : 3px;
box-shadow : 0 5px 5px 0 darkgray;
}
<!-- 위의 예제와 동일합니다. -->
<body>
<button onclick="plusElem()">요소 추가하기</button>
<br/>
<section class="container" id="container">
<div>
1
</div>
</section>
<script>
const container = document.getElementById("container");
let currNum = 2;
function plusElem() {
const newElem = document.createElement("div");
newElem.textContent = currNum++;
container.appendChild(newElem);
}
</script>
</body>
안타깝게도, grid-template-columns 를 단독으로 선언하여 다음 줄로 넘길 수 있었던 것에 비해,
grid-template-rows 만을 단독으로 선언해서는, 원하는 바를 만들 수가 없다.
나는 굳이 grid-template-columns 를 사용하고 싶지 않았다.
그 이유가, 컬럼을 선언하게 되면, 내부의 컨텐츠가 컬럼에 따라 "미리 분리" 가 되어있기 때문이다.
내가 원한 것은, "컨텐츠의 수에 따라 영역이 그때그때 나뉘는 것" 을 원했다.
이에 대한 답을 알기 위해 Gemini-2.5 를 사용했는데,
위의 예제에서 CSS 에 grid-auto-flow : column; 단 한 줄만 추가하면 되었다.
.container {
/* grid 선언 */
display : grid;
/* 이 컨테이너는 20 rem 의 높이를 고정적으로 가진다 */
height : 20rem;
margin : 1rem;
border : 4px solid black;
/* grid 컨테이너 내부의 요소들이 서로 간격을 10px 로 떨어진다 */
gap : 10px;
/* 내가 선언하는 행 이 가질 요소 */
grid-template-rows : 50px 1fr 30%;
grid-auto-flow : column;
}
div {
text-align : center;
border : 2px solid gray;
border-radius : 3px;
box-shadow : 0 5px 5px 0 darkgray;
}
HTML 은 그대로
Preview
end
위의 예제를 만들고 나서, 원하던 형식으로 표시되는 것을 확인 할 수 있었다.
Grid 컨테이너 트랙 고유 크기 조정 키워드
우리가 생각해 볼 수 있는 것은, 절대값 선언인 50px, 2rem, 30%
를 제외하고,
Grid 시스템에서 가장 많이 사용 되는 단위는 fr 이라는 단위다.
즉, 이는 free 의 약자로서, 남는 공간을 fr 끼리 비율로 분배하는 효율적인 단위이다.
여기서 생각 해 볼 수 있는 점은,
위의 단위들에서 "컨텐츠에 따른 크기" 는 고려 대상이 아니라는 것이다.
즉, 절대 값이나, Grid 컨테이너에서 유연한 비율을 선언할 수 있는 fr 단위 또한, 컨텐츠를 신경쓰지 않는다.
따라서 여기서 grid-template-columns or rows 에 선언할 수 있는 또 다른 키워드들이 존재하는데,
automin-contentmax-contentfit-content(..)
이다.
아직 본격적으로 CSS Function 을 다룰 때가 아닌 것 같아서 밑의 아주 간단한 예시를 들자면,
grid-template-columns : auto min-content max-content fit-content(3rem);
이러한 방식으로 선언이 가능하다.
만약에, 1 개의 트랙에 동일한 속성을 선언하고자 한다면,
grid-template-columns : repeat(4, 1fr); 와 같은 형식으로 선언이 가능하다.
위의 repeat 라는 함수는 동일한 인자를 결과적으로 펼쳐주는 역할을 하는데,
4: 4 번 동일하게 반복 선언한다.1fr: 1fr 을.
Result : grid-...-columns : 1fr 1fr 1fr 1fr; 이 된다.
다시 돌아와서, Grid Track 의 고유 크기 조정 키워드는
위와 같은 repeat 함수의 "인자" 로 건네주어 하위 컴포넌트의 크기를 다룰 수 있다.
예를 들어보자.
- 나는 총 7 개의 엘리먼트를 넣을 수 있게 만들 것이며,
- 하나의 줄에 총 3 개가 들어 갈 수 있다.
- 하위 컴포넌트들은 컨테이너의 선언에 따라 모두 같은 키워드로 조정된다.
- 그러나, 각각의 컴포넌트들은 다른 컨텐츠 길이를 가진다.
그리고, 각 단위의 정확한 의미를 알아보자.
auto: 컨텐츠의 크기에 따라 공간을 분배하며, 컴포넌트들이 하나의 트랙을 전부 차지한다.min-content: 내부 컴포넌트에서 "가장 긴 단어" 만큼 너비를 가진다.max-content: 내부 컴포넌트에서 줄넘김이 발생하지 않을 만큼 큰 너비를 가진다.
이 키워드는 오버플로우를 발생시킬 수 있다.fit-content(?):?에 선언된 크기만큼 커질 수 있으며, 그 이상은 늘어나지 않는다.
트랙의 끝에 도달하면 컨텐츠 내부를 자동으로 줄넘김하므로, 유용한 기능이다.
/* 전역 변수로서 트랙 키워드를 동적으로 변화시키기 위해서 선언 */
/* 또한, CSS 내부에서 함수를 통해 전역적으로 가져올 수 있음. */
:root {
--grid-track-keyword : auto;
}
.container {
display : grid;
/* 오버플로를 유발시키기 위한 적정한 길이로 판단 */
max-width : 20rem;
/* repeat, var 함수를 통해 앞으로 grid 를 구성하게 됨. */
grid-template-columns : repeat(3, var(--grid-track-keyword));
/* 1fr 이 아니라, auto 로 선언하여, 하얀 빈 칸이 생겨나지 않도록 조치. */
grid-template-rows : repeat(3, auto);
padding : 1rem;
margin : 1rem;
border : 2px solid dodgerblue;
}
div {
text-align : center;
padding : 1rem;
border : 2px solid gray;
border-radius : 3px;
box-shadow : 0 5px 5px 0 darkgray;
}
<body>
각 개체의 컬럼 사이즈를 골라보자 :
<br/>
<select id="grid-track-select">
<option value="auto">auto</option>
<option value="min-content">min-content</option>
<option value="max-content">max-content</option>
<option value="fit-content(7rem)">fit-content(7rem)</option>
</select>
<br/>
<section id="container" class="container">
<div>
컨테이너 1
</div>
<div>
컨테이너 2
</div>
<div>
컨테이너 3 인데, max-content 를 선택하면 오버플로가 납니다.
</div>
<div>
컨테이너 4
</div>
<div>
컨테이너 5
</div>
<div>
컨테이너 6
</div>
<div>
컨테이너 7
</div>
</section>
<script>
const select = document.getElementById("grid-track-select");
const container = document.getElementById("container");
const root = document.documentElement;
select.addEventListener("change", function () {
/* CSS 시트에서 :root 로 선언된 변수는 이와 같이 동적으로 변화시키거나 선언할 수 있음. */
root.style.setProperty("--grid-track-keyword", select.value);
});
</script>
</body>
Preview :
end
위에 만들어 놓은 예제를 통해 Grid 의 고유 크기 조정 keyword 들을 익히기를 바란다.
위의 키워드에서 중요한 것은, 일방적으로 컨테이너가 선언하는 크기만을 선언 할 수 있는 것이 아니라,
컨테이너 내부에 존재하는 컴포넌트들의 "컨텐츠 양" 에 따라 조절할 수 있다는 것이 핵심이다.
조금 더 직접적으로 알아보는 fr, 그리고 추가 함수들
이 글에서는 fr 이라는 단위에 대해서 먼저 설명하긴 했지만,
컨텐츠의 양에 따라 자동적으로 영역을 분배 해 주는 auto 가 먼저 배울 내용이라고 생각된다.
fr 단위에 대해서 본격적으로 들어가기 전에, 다시 정보를 짚고 넘어가자.
fr단위는 남는 grid 컨테이너에서 비율로 나눈다.- 컨테이너에 하나의 엘리먼트가 존재한다면,
1fr,3fr이던 동일한 크기를 가진다. fr단위가 여러번 선언된다면, 해당 트랙 전체 크기에서 비율로 나눈다.- 그리드 템플릿 행, 열은 여러 번 인자를 선언하거나 전달하는 방식으로 구성되므로,
repeat와 같은 함수를 자주 사용하게 된다.
먼저 예제로 하나의 예시를 보고 가자.
나는 예제를 이렇게 만들었다.
- row 방향이며, 총 3 개의 열을 가질 수 있다.
- 2 번째 열의 크기만을 바꾸고, 나머지는
1fr로 동결이다. - 크기를 선택 해 가며, 비율의 감각을 키우고 넘어가자.
물론, 나도 css 를 잘하는 사람이 절대 아니기 때문에, 예시를 만들면서 조금씩 감각을 키우고 있다.
:root {
--select-free : 1fr;
}
.container {
display : grid;
grid-template-columns : 1fr var(--select-free) 1fr;
width : 20rem;
border : 2px solid dodgerblue;
margin : 1rem;
padding : 1rem;
gap : 0.75rem;
}
div {
text-align : center;
border : 2px solid gray;
border-radius : 3px;
box-shadow : 0 5px 5px 0 darkgray;
}
<body>
두 번째 엘리먼트의 비율을 변화시켜봅시다.
<br/>
<select id="select-fr">
<option value="1fr">1fr</option>
<option value="2fr">2fr</option>
<option value="3fr">3fr</option>
<option value="4fr">4fr</option>
</select>
<br/>
<section class="container">
<div>
컨테이너 1
</div>
<div style="background: lightblue;">
컨테이너 2 - 변화
</div>
<div>
컨테이너 3
</div>
</section>
<script>
const select = document.getElementById("select-fr");
const rootStyle = document.documentElement;
select.addEventListener("change", function () {
rootStyle.style.setProperty("--select-free", select.value);
})
</script>
</body>
Preview :
end
하나의 트랙 안에서, 선택한 2 번째의 엘리먼트가
가지는 fr 단위에 따라서 어떤 변화를 보이는지 볼 수 있을 것이다.
fr 단위를 가지는 엘리먼트들은 남는 영역을 경쟁하므로,
1fr --> 3fr 했을 때, 1fr 에 비해 3 배 커진 것이 아니라,
(3/5)fr 의 크기를 가지게 되었다는 것이 중요하다.
만약 1fr 을 선택했다면, (1/3)fr 의 크기를 가지게 된다.
새로운 함수 minmax 와 함수의 조합
grid 템플릿 선언에서는 인자의 중복 선언으로 개별 열, 혹은 행을 생성 할 수 있게 해 준다.
그러나, 이러한 행동은 코드의 길이를 과도하게 늘릴 뿐만 아니라, 번거롭게 한다.
따라서, 위의 예제에서 repeat CSS Function 을 작성하며 간단하게 선언했다.
그리고 이번에는 새로운 함수, minmax 를 알아 볼 시간이다.
minmax 함수란 무엇인가?
이 함수는 우리가 여태까지
grid-template-columns or rows : 50px 1rem 30% auto min-content max-content fit..
이렇게 하나의 인자에 다양한 단위를 넣을 수 있던 것 처럼,
이 인자 중 하나에 넣을 수 있는 함수값에 해당한다.
minmax(1 번째 인자, 2 번째 인자) 의 형태를 띄게 되는데,
1 번째 인자는 이 "열" 의 "최소 크기" 를 의미하며,
2 번째 인자는 이 "열" 의 "최대 크기" 를 의미한다.
여기서 다양한 조합이 나올 수 있게 되는데,
단순한 50 ~ 100 px 로도 만들 수 있겠지만,
이러한 조합이 가능하다.
minmax(auto, 1fr): 최소 크기는 "컨텐츠에 따라" 맞추며, 최대 크기는 하나의 Grid Track 이다.minmax(0, 1fr): 최소 크기는 컨텐츠 여부에 상관없이 0 길이에 도달 가능하며,
최대 크기는 하나의 Grid Track 을 의미한다.repeat(12, minmax(0, 1fr)):
컨테이너의 요소 개수에 따라 분배하며, 트랙에 빈 공간은 없다.
요약하자면,
선언된 열, 혹은 행 은 인자에 따라 "최소" 혹은 "최대" 크기를 갖게 되는 함수라는 의미이다.
repeat 인자로 사용될 수 있는 새로운 단어, "auto-fill" "auto-fit"
기존에 repeat 라는 CSS 함수를 사용하기 위해서는,
repeat(반복 횟수, "들어갈 문장"); 형식으로 사용했다.
그런데, 위의 auto-fill, auto-fit 이라는 단어는 "반복 횟수" 인자에 들어 갈 수 있다.
직관적으로 이해되지 않았는데,
이 문장을 몇 번 인자로 넣을 것인지에 대한 대답이, auto-fill, auto-fit 이라는 것에
의문을 가졌다.
그리고 repeat 안에 들어가는 auto-??? 선언은 무조건 하나의 함수가 더 조합되어야 하는데,
바로 minmax 이다.
밑에서 예제로 minmax 를 사용하지 않고 절대단위로 사용했는데, 변화가 없었다.
즉, 이 두 속성, auto-fill, auto-fit 에 대한 이해가 부족했기 때문에
변화를 직접 만들 수가 없었다.
먼저, 설명과 예제를 보자.
이 2 개의 공통점
둘 다, Grid 를 반응형 디자인으로 만들어 준다.
즉, 명시적으로 "횟수" 를 선언하는 게 아니라,
자연스러운 줄넘김을 구사할 수 있는 것이다.
먼저 간단하게 짚고 넘어가자면,
auto-fill:repeat(auto-fill, minmax(200px, 1fr));auto-fit:repeat(auto-fit, minmax(200px, 1fr));
이러한 방식으로 사용한다.
auto-fill 은, 하나의 트랙이 오버플로 되지 않을 만큼, (padding, gap 더하면 오버플로 값이 나올 수 있으므로,)
채우되, 만약에 Grid Track 에 남는 공간이 있다면,(오른쪽 공간) 이를 냅둔다.
그러나,
auto-fit 은, 하나의 트랙이 오버플로 되지 않을 만큼 추가해 주는 기능을 동일하게 가지지만,
남는 공간을 분배하여 트랙이 꽉 차게 만든다.
왜 minmax 를 사용해야 하는가?
여기서 중요한 게, 두 선언 auto-??? 는 Grid Track 을 인식하고,
"컨테이너의 너비" 는 고려 대상이 아니라는 것이다.
아니 컨테이너의 너비가 결국 Grid Track 의 너비가 아닌가? 라고 생각했는데,
하위 컴포넌트에서 Grid Track 의 최종 길이 (padding 과 gap 등등을 뺀 결과)
를 인식하기 위해서는, 1fr 을 사용해야 한다는 것이다.
이러한 이유로 인해, auto-??? 두 속성은 minmax 함수와 결합되어 사용된다.
:root {
--auto-var : auto-fill;
}
.container {
display : grid;
width : 23rem;
grid-template-columns : repeat(var(--auto-var), minmax(5rem, 1fr));
margin : 1.5rem;
padding : 1.5rem;
gap : 1rem;
background-color : gray;
}
div {
text-align : center;
background : white;
box-shadow : 0 0 0.5rem darkgray;
border-radius : 0.25rem;
}
<body>
값을 바꿔가며 변화를 확인 해 보세요.
<br/>
<select id="auto-select">
<option value="auto-fill">auto-fill</option>
<option value="auto-fit">auto-fit</option>
</select>
<br/>
<section id="container" class="container">
<div>
엘리먼트 1
</div>
<div>
엘리먼트 2
</div>
</section>
<br/>
<button onclick="appending()">엘리먼트 추가</button>
<br/>
<button onclick="initial()">초기화</button>
<script>
const select = document.getElementById("auto-select");
const rootStyle = document.documentElement;
const container = document.getElementById("container");
select.addEventListener("change", function () {
rootStyle.style.setProperty("--auto-var", select.value);
})
// 예제를 위한 추가 함수이므로, 위에 집중하셔도 됩니다.
function appending() {
const newElem = document.createElement("div");
newElem.textContent = "새 엘리먼트";
container.appendChild(newElem);
}
function initial() {
container.innerHTML = "<div>엘리먼트 1</div><div>엘리먼트 2</div>";
}
</script>
</body>
Preview :
end :
auto-fit, auto-fill 은,
하나의 줄에 엘리먼트를 나열하는 상태에서, 아직 컬럼을 넣을 수 있는 상태에서 차이를 보인다.
즉, 이미 하나의 트랙이 채워진 상태에서는, auto-fit, auto-fill 은 동일하게 보인다.
자동 배치
지금까지 볼 수 있었던 배치는, 주로 왼쪽에서 오른쪽으로 향하는 배치 방식이었다.
그런데, Grid 레이아웃에서는, 위아래 작성 후 오른쪽으로 줄넘김하는 것이 가능하다.
row, column 두 개의 방향을 모두 만족하기 위해서는,
들어갈 수 있는 최대 엘리먼트를 인자를 통해 지정 해 주어야 한다.
grid-auto-flow
위의 기능을 가능하게 만들어 주는 것이 바로 이 속성이다.
여기에 row, column 2 개의 값이 들어 갈 수 있다.
row: 여태까지 봤던 것 처럼 엘리먼트가 순서대로 배치됨.column: 수직으로 먼저 작성되는데, 위아래로 향하며, 수직이 채워지면 그 다음 열에서 시작한다.
역시, 이러한 것도 예제를 통해 직접적으로 변화를 보는 것이 좋다고 생각한다.
:root {
--auto-flow : row;
}
.container {
display : grid;
width : 20rem;
grid-template-columns : repeat(3, 1fr);
grid-template-rows : repeat(3, 1fr);
grid-auto-flow : var(--auto-flow);
margin : 1.5rem;
padding : 1.5rem;
gap : 1rem;
background-color : gray;
}
div {
text-align : center;
background : white;
box-shadow : 0 0 0.5rem black;
border-radius : 0.25rem;
}
<body>
<select id="select-flow">
<option value="row">row</option>
<option value="column">column</option>
</select>
<br/>
<section class="container">
<div>
엘리먼트 1
</div>
<div>
엘리먼트 2
</div>
<div>
엘리먼트 3
</div>
<div>
엘리먼트 4
</div>
<div>
엘리먼트 5
</div>
</section>
<script>
const select = document.getElementById("select-flow");
const rootStyle = document.documentElement;
select.addEventListener("change", function() {
rootStyle.style.setProperty("--auto-flow", select.value);
})
</script>
</body>
Preview :
end
지정, 자동 배치 그리고 트랙 늘리기
이제까지 우리는 Grid Container 가 선언된 엘리먼트가
하위 엘리먼트를 어떻게 정렬하고, 조정하는지 보았다.
지금부터 작성되는 것은, Grid Container 바로 하위에 존재하는 grid-item 들이 선언하는 항목이다.
Flexbox 즉, display : flex 가 선언되었을 때도 flex-item 들이 존재했는데,
여기서도 display : grid 가 선언되었을 때, grid-item 에 선언하는 속성들이 존재했다.
컨테이너 하위에 존재하는 요소에 이러한 항목을 선언 할 수 있다.
먼저 보고 세부 내용을 보도록 하자.
grid-item 에서 선언 할 수 있는 속성들
grid-column-start: 이 엘리먼트의 Grid Column Line 시작 지점grid-column-end: 이 엘리먼트의 Grid Column Line 끝 지점grid-row-start: 이 엘리먼트의 Grid Row Line 시작 지점grid-row-end: 이 엘리먼트의 Grid Row Line 끝 지점grid-column: Grid Column Line 의 시작과 끝을 모두 선언하는 단축 속성grid-row: Grid Row Line 의 시작과 끝을 모두 선언하는 단축 속성
만약에 같은 열, 혹은 행 에 대해서 시작과 끝이 모두 선언되었을 때,
그 간격이 1 이상이라면, span(확장) 을 의미한다.
모든 속성에는 span 이 인자로 들어갈 수 있다.
EX - span 2 --> 선언된 속성에 따라 해당 방향으로 2 칸으로 확장.
그리고 꼭 기억해야 할 게, 단축 속성인 grid-column, grid-row 는,
시작과 끝을 / 로 나눈다. 이는 나눗셈으로 생각해서는 안되고,
시작과 끝을 나누는 델림(delim) 으로 해석해야 한다.
한번, 간단하게 이 예제가 적용된 예시를 보자.
:root {
--select-row : 1;
--select-col : 1;
}
.container {
display : grid;
width : 20rem;
grid-template-columns : repeat(5, 1fr);
grid-template-rows : repeat(5, 1fr);
margin : 1.5rem;
padding : 1.5rem;
gap : 1rem;
background-color : gray;
}
div {
text-align : center;
background : white;
box-shadow : 0 0 0.5rem black;
border-radius : 0.25rem;
}
div.span-row {
grid-column : auto / span var(--select-row);
}
div.span-col {
grid-row : auto / span var(--select-col);
}
<body>
grid-column 적용 엘리먼트의 크기를 조정 해 보세요.
<br/>
<select id="select-row-span">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<br/>
grid-row 적용 엘리먼트의 크기를 조정 해 보세요.
<br/>
<select id="select-col-span">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<section class="container">
<div>
기본 엘리먼트
</div>
<div class="span-row">
grid-column 적용 엘리먼트
</div>
<div class="span-col">
grid-row 적용 엘리먼트
</div>
</section>
<script>
const selectRow = document.getElementById("select-row-span");
const selectCol = document.getElementById("select-col-span");
const rootElem = document.documentElement;
function changeVal (event) {
const id = event.target.id;
if(id == "select-row-span") {
rootElem.style.setProperty("--select-row", event.target.value);
} else {
rootElem.style.setProperty("--select-col", event.target.value);
}
}
selectRow.addEventListener("change", changeVal);
selectCol.addEventListener("change", changeVal);
</script>
</body>
preview :
end
위에서 선언된 grid-column, grid-row 는, 복합 인자를 받는다.
여기서 첫 번째 인자로 auto 가 들어갔는데, 이 의미는
"원래 하던 대로 행동" 하겠다는 것이다. 유동적으로 들어가겠다는 의미이다.
그리고 나는 끝을 넣지 않고, span <숫자> 를 이용해서 엘리먼트를 넓히는 예제를 선택했다.
시작과 끝을 지정하는 것을 하기 전에, 늘리는 예제를 먼저 배우는 것이 나중을 위해서 더 쉽겠다는 생각이 들었다.
만약에 위의 예제를 단순한 끝과 마지막으로 표현했다면,
grid-column:1 / 3grid-row:2 / 4
이러한 형태로 나타 낼 수도 있었다.
즉, 위의 내용으로 알 수 있는 것은,
위에서 선언했던 grid-item 에서 사용 할 수 있는 속성들로,
Grid Track 들을 "걸쳐서" 보여 줄 수 있다는 것이다.
이는 Grid Area 이기도 하다.
각 방향에서의 시작과 끝을 마음대로 조정 해 보자
위에서는 단순한 열, 행 방향으로의 확장을 보았다.
이번에는 5 x 5 크기의 컨테이너에서, 하나의 엘리먼트가 어떻게 확장될 수 있는지,
그에 대해서 예제를 통해 알아보자.
내가 의도하는 것은,
- 시작 지점과 끝 지점을 직접 조정하면서 어떻게 늘려질 수 있는지 알아보기
- 시작과 끝은 같거나, 역으로 성립되면 기본 크기인 1 을 가진다. - css 문법에 어긋나는 행동
:root {
--select-row-start : 1;
--select-col-start : 1;
--select-row-end : 2;
--select-col-end : 2;
}
.container {
display : grid;
width : 20rem;
height : 20rem;
grid-template-columns : repeat(5, 1fr);
grid-template-rows : repeat(5, 1fr);
margin : 1.5rem;
padding : 1.5rem;
gap : 1rem;
background-color : gray;
}
div {
text-align : center;
background : white;
box-shadow : 0 0 0.5rem black;
border-radius : 0.25rem;
}
div.span-elem {
grid-column-start : var(--select-col-start);
grid-column-end : var(--select-col-end);
grid-row-start : var(--select-row-start);
grid-row-end : var(--select-row-end);
}
<body>
grid-column-start : <select id="select-col-start">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select><br/>
grid-column-end : <select id="select-col-end">
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select><br/>
<br/>
grid-row-start : <select id="select-row-start">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select><br/>
grid-row-end : <select id="select-row-end">
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select>
<section class="container">
<div class="span-elem">
엘리먼트 증감 해 보기
</div>
</section>
<script>
const selectColStart = document.getElementById("select-col-start");
const selectColEnd = document.getElementById("select-col-end");
const selectRowStart = document.getElementById("select-row-start");
const selectRowEnd = document.getElementById("select-row-end");
const rootElem = document.documentElement;
selectColStart.addEventListener("change", changeRange);
selectColEnd.addEventListener("change", changeRange);
selectRowStart.addEventListener("change", changeRange);
selectRowEnd.addEventListener("change", changeRange);
function changeRange(event) {
rootElem.style.setProperty(`--${event.target.id}`, event.target.value);
}
</script>
</body>
Preview :
end
위에서,
각 시작과 끝을 2, 5 로 설정하면,
정 중앙에 엘리먼트를 위치하게 만들 수도 있다.
위에서 사용한
grid-column-startgrid-column-endgrid-row-startgrid-row-end
이 4 개의 속성을 항상 같이 사용해야 하는 것은 아니다.
해당 Grid-Item 이 행, 열 이 2 개의 상황에서,
어떤 위치부터 시작해야 하는지, 필요한 속성을 빼서 사용하면 된다.
각각의 속성은 하나씩 선언될 수 있으며, span 이라는 키워드와 함께 사용이 가능하다.
예를 들어, column, row 던지,
EX - grid-column-end : span 2 라면,
시작 부분에서 2 개의 트랙을 가지며,
혹은 끝 부분에서 반대로 2 개의 트랙을 가진다는 의미가 된다.
grid-area 사용하기
바로 위의 방식, grid-xxx-start or end 키워드로 트랙을 걸쳐 생성되는 엘리먼트를 생성할 수 있지만,
헤더, 사이드바, 컨텐츠, 푸터 의 방식으로 직관적으로 나눌 수 있다.
단, 직접적으로 문자열로 선언 해 주어야 한다.
grid-area 는, grid-item 에 해당하는 엘리먼트에서 선언하는 속성이다.
grid-template-areas 사용하기
grid-area 라는 직관적인 속성을 grid-item 에서 사용하기 위해서는,
grid-template-areas 를 Grid Container 에서 선언 해 주어야 한다.
이게 어떻게 직관적으로 사용 가능한 grid container 가 되냐면,
.container {
display : grid;
width : 18rem;
grid-template-columns : repeat(1, 3fr);
grid-template-areas :
"header header header"
"sidebar content content"
"sidebar footer footer"
}
.header {
grid-area : header;
}
.sidebar {
grid-area : sidebar;
}
.content {
grid-area : content;
}
.footer {
grid-area : footer;
}
.container 의, grid-template-area 를 살펴보자.
보면, 문자열로 "직접" 영역을 지정해 놓은 것을 볼 수 있다.
여기서 grid-area : 위에서 선언한 나의 속성; 으로 쉽게 grid-area 를 만들 수 있다.
이 주제를 마무리하며
이번에는 Flexbox 에 이은, Grid 사용법을 알아보았다.
만약에 Grid 레이아웃이 존재하지 않는다고 해도, 이 표현이 불가능한 것은 아니다.
그러나, 2 차원 나열 레이아웃에서 엘리먼트의 영역 분할,
혹은 컨텐츠에 따른 영역 분할을 쉽고 동적으로 분할하도록 도와준다는 점에서 호감이 갔다.
Grid 에 대해서 더 이해하고 싶다면.
Grid 에 대한 깊은 이해를 하고 싶다면,
CSS-TRICKS - CSS Grid Layout Guide
위의 두 문서를 같이 본다면 추가적인 정보를 얻을 수 있다.
또한, Grid Layout 를 직접 작성하여 배우는 게임이 존재하는데,
Grid Garden 이라는 게임이다.
나는 예제를 전부 직접 작성하며 공식문서를 보고 익힌 것 보다 더 높을 수 밖에 없다.
이 링크를 통해 끝까지 풀어 Grid 레이아웃을 익히는 것을 추천한다.
참조 사이트
web.deb 사이트- 그리드
https://web.dev/learn/css/grid?hl=ko
MDN 문서 - Grid
https://developer.mozilla.org/ko/docs/Glossary/Grid
Grid Garden - 게임(직감을 발달시키기에 굉장히 유용함)
MDN 문서 - Grid Layout
https://developer.mozilla.org/ko/docs/Web/CSS/CSS_grid_layout
CSS-TRICS - CSS Grid Layout Guide
https://css-tricks.com/snippets/css/complete-guide-grid/
'Web-Server > 웹 지식' 카테고리의 다른 글
| 예제와 함께 알아보는 CSS flex 와 Flexbox (0) | 2025.10.26 |
|---|---|
| CSS 레이아웃, display 에 대해서 알아놓자 (0) | 2025.10.17 |
| 미리 알아두면 좋았을 CSS 기초 및 응용 예제 (0) | 2025.10.08 |
| HTML 문서 정식 태그 "전부" 공부하기 - 마무리 편 (코드 작성 및 구현까지) (0) | 2025.06.01 |
| HTML 문서 정식 태그 "전부" 공부하기 - 4편 (코드 작성 및 구현까지) (0) | 2025.05.30 |