| 브라우저 | 지원 버전 |
|---|---|
| Chrome | 57+ ✅ |
| Firefox | 52+ ✅ |
| Safari | 10.1+ ✅ |
| Edge | 16+ ✅ |
| IE | ❌ (구 문법으로만 부분 지원) |
참고: caniuse.com에서 정확한 호환성 정보 확인 가능
CSS Grid는 격자(Grid) 기반 레이아웃 시스템으로, 복잡한 2차원 레이아웃을 쉽게 구현할 수 있습니다.
<div class="grid-container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr; /* 4개 컬럼 */
grid-template-rows: 100px 100px 100px; /* 3개 행 */
grid-gap: 10px; /* 간격 */
padding: 20px;
}
.item {
background: #007bff;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
}
.grid-example {
display: grid;
/* 다양한 단위 사용 */
grid-template-columns:
200px /* 고정 크기 */
1fr /* 비율 (1배) */
2fr /* 비율 (2배) */
minmax(100px, 300px) /* 최소/최대 크기 */
auto; /* 내용에 맞춤 */
/* repeat 함수 사용 */
grid-template-columns: repeat(4, 1fr); /* 1fr을 4번 반복 */
grid-template-columns: repeat(3, 200px); /* 200px을 3번 반복 */
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); /* 반응형 */
}
<div class="layout-container">
<div class="header">헤더</div>
<div class="sidebar">사이드바</div>
<div class="main">메인 컨텐츠</div>
<div class="footer">푸터</div>
</div>
.layout-container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: 80px 400px 80px;
grid-gap: 10px;
min-height: 100vh;
}
.header {
grid-column: 1 / 5; /* 컬럼 1번 라인부터 5번 라인까지 */
background: #333;
color: white;
}
.sidebar {
grid-column: 1 / 2; /* 컬럼 1번 라인부터 2번 라인까지 */
grid-row: 2 / 3; /* 행 2번 라인부터 3번 라인까지 */
background: #f8f9fa;
}
.main {
grid-column: 2 / 5; /* 컬럼 2번 라인부터 5번 라인까지 */
grid-row: 2 / 3;
background: white;
padding: 20px;
}
.footer {
grid-column: 1 / 5;
background: #6c757d;
color: white;
}
1 2 3 4 5 ← 세로 라인 번호
1 ┌───┬───┬───┬───┐
│ │ │ │ │
2 ├───┼───┼───┼───┤
│ │ │ │ │
3 ├───┼───┼───┼───┤
│ │ │ │ │
4 └───┴───┴───┴───┘
↑ 가로 라인 번호
.item {
/* 기본 방식 */
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 2;
/* 단축 속성 */
grid-column: 1 / 3;
grid-row: 1 / 2;
/* span 키워드 사용 */
grid-column: span 2; /* 2칸 차지 */
grid-row: span 1; /* 1칸 차지 */
}
<div class="page-layout">
<header class="page-header">헤더</header>
<aside class="page-sidebar">사이드바</aside>
<main class="page-main">메인 컨텐츠</main>
<footer class="page-footer">푸터</footer>
</div>
.page-layout {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: 80px 1fr 60px;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
min-height: 100vh;
grid-gap: 10px;
}
.page-header {
grid-area: header;
background: #007bff;
color: white;
}
.page-sidebar {
grid-area: sidebar;
background: #f8f9fa;
}
.page-main {
grid-area: main;
background: white;
padding: 20px;
}
.page-footer {
grid-area: footer;
background: #6c757d;
color: white;
}
.grid-with-gaps {
grid-template-areas:
"header header header header"
"sidebar main main ." /* . = 빈 공간 */
"sidebar main main ."
"footer footer footer footer";
}
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-gap: 20px;
padding: 20px;
}
/* 수동 반응형 */
@media (max-width: 768px) {
.page-layout {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
}
}
@media (min-width: 769px) and (max-width: 1024px) {
.page-layout {
grid-template-columns: 150px 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
}
<div class="gallery-grid">
<div class="gallery-item featured">
<img src="https://picsum.photos/600/400?random=1" alt="Featured Image">
</div>
<div class="gallery-item">
<img src="https://picsum.photos/300/300?random=2" alt="Image 2">
</div>
<div class="gallery-item">
<img src="https://picsum.photos/300/300?random=3" alt="Image 3">
</div>
<div class="gallery-item">
<img src="https://picsum.photos/300/300?random=4" alt="Image 4">
</div>
<div class="gallery-item">
<img src="https://picsum.photos/300/300?random=5" alt="Image 5">
</div>
<div class="gallery-item">
<img src="https://picsum.photos/300/300?random=6" alt="Image 6">
</div>
</div>
.gallery-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 200px;
grid-gap: 15px;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.gallery-item {
background: #f8f9fa;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.gallery-item:hover {
transform: translateY(-5px);
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* 첫 번째 이미지를 2x2로 확대 */
.gallery-item.featured {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
/* 반응형 */
@media (max-width: 768px) {
.gallery-grid {
grid-template-columns: 1fr;
grid-auto-rows: 250px;
}
.gallery-item.featured {
grid-column: 1 / 2;
grid-row: 1 / 2;
}
}
@media (min-width: 769px) and (max-width: 1024px) {
.gallery-grid {
grid-template-columns: repeat(2, 1fr);
}
.gallery-item.featured {
grid-column: 1 / 3;
grid-row: 1 / 2;
}
}
<div class="blog-layout">
<header class="blog-header">
<h1>My Blog</h1>
<nav>Navigation Menu</nav>
</header>
<aside class="blog-sidebar">
<h3>Sidebar</h3>
<ul>
<li>Recent Posts</li>
<li>Categories</li>
<li>Archives</li>
</ul>
</aside>
<main class="blog-content">
<article>
<h2>Blog Post Title</h2>
<p>Blog post content goes here...</p>
</article>
</main>
<footer class="blog-footer">
<p>© 2024 My Blog. All rights reserved.</p>
</footer>
</div>
.blog-layout {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
min-height: 100vh;
grid-gap: 20px;
padding: 20px;
}
.blog-header {
grid-area: header;
background: #343a40;
color: white;
padding: 20px;
border-radius: 8px;
}
.blog-sidebar {
grid-area: sidebar;
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
}
.blog-content {
grid-area: content;
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.blog-footer {
grid-area: footer;
background: #6c757d;
color: white;
padding: 15px;
border-radius: 8px;
text-align: center;
}
/* 태블릿 */
@media (max-width: 1024px) {
.blog-layout {
grid-template-columns: 200px 1fr;
}
}
/* 모바일 */
@media (max-width: 768px) {
.blog-layout {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"content"
"sidebar"
"footer";
}
}
position: sticky는 스크롤 기반 고정 요소를 만드는 속성입니다.
| 브라우저 | 지원 버전 |
|---|---|
| Chrome | 56+ ✅ |
| Firefox | 32+ ✅ |
| Safari | 6.1+ ✅ |
| Edge | 16+ ✅ |
| IE | ❌ |
<body style="height: 3000px; background: #f0f0f0;">
<div class="content-section">
<div class="sticky-sidebar">
<img src="product.jpg" alt="Product Image">
</div>
<div class="main-text">
<h2>Product Description</h2>
<p>Long product description that requires scrolling...</p>
<!-- 많은 텍스트 내용 -->
</div>
</div>
</body>
.content-section {
background: white;
max-width: 1200px;
margin: 100px auto;
padding: 40px;
display: flex;
gap: 40px;
min-height: 2000px; /* 스크롤 가능하도록 */
}
.sticky-sidebar {
flex: 0 0 400px;
position: sticky;
top: 20px; /* viewport 상단에서 20px 위치에 고정 */
height: fit-content;
}
.sticky-sidebar img {
width: 100%;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.main-text {
flex: 1;
line-height: 1.8;
}
top, bottom 등)에 도달하면 고정<header class="main-header">
<h1>Website Header</h1>
</header>
<nav class="sticky-nav">
<ul>
<li><a href="#home">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#services">Services</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
<main class="main-content">
<!-- 페이지 내용 -->
</main>
.main-header {
background: #343a40;
color: white;
padding: 60px 20px;
text-align: center;
}
.sticky-nav {
position: sticky;
top: 0;
background: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
z-index: 100;
}
.sticky-nav ul {
display: flex;
list-style: none;
margin: 0;
padding: 0;
max-width: 1200px;
margin: 0 auto;
}
.sticky-nav li {
flex: 1;
}
.sticky-nav a {
display: block;
padding: 20px;
text-decoration: none;
color: #333;
text-align: center;
transition: background 0.3s ease;
}
.sticky-nav a:hover {
background: #f8f9fa;
}
.main-content {
max-width: 1200px;
margin: 0 auto;
padding: 40px 20px;
min-height: 2000px;
}
<div class="article-layout">
<aside class="table-of-contents">
<h3>목차</h3>
<ul>
<li><a href="#section1">섹션 1</a></li>
<li><a href="#section2">섹션 2</a></li>
<li><a href="#section3">섹션 3</a></li>
<li><a href="#section4">섹션 4</a></li>
</ul>
</aside>
<article class="article-content">
<section id="section1">
<h2>섹션 1</h2>
<p>섹션 1의 내용...</p>
</section>
<!-- 더 많은 섹션들 -->
</article>
</div>
.article-layout {
display: grid;
grid-template-columns: 250px 1fr;
gap: 40px;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.table-of-contents {
position: sticky;
top: 20px;
height: fit-content;
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
border: 1px solid #e9ecef;
}
.table-of-contents h3 {
margin-top: 0;
color: #495057;
}
.table-of-contents ul {
list-style: none;
padding: 0;
}
.table-of-contents li {
margin-bottom: 8px;
}
.table-of-contents a {
color: #007bff;
text-decoration: none;
padding: 8px 0;
display: block;
border-radius: 4px;
padding-left: 12px;
transition: all 0.3s ease;
}
.table-of-contents a:hover {
background: #e9ecef;
color: #0056b3;
}
.article-content {
line-height: 1.8;
}
.article-content section {
margin-bottom: 60px;
min-height: 600px;
}
@media (max-width: 768px) {
.article-layout {
grid-template-columns: 1fr;
}
.table-of-contents {
position: static;
order: -1;
}
}
/* Grid가 적합한 경우 */
.grid-suitable {
/* 2차원 레이아웃 (행과 열 모두 제어) */
display: grid;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
}
/* Flexbox가 적합한 경우 */
.flex-suitable {
/* 1차원 레이아웃 (한 방향만 제어) */
display: flex;
justify-content: space-between;
align-items: center;
}
| 특징 | Grid | Flexbox |
|---|---|---|
| 차원 | 2차원 (행 + 열) | 1차원 (행 또는 열) |
| 용도 | 전체 레이아웃 | 컴포넌트 내부 정렬 |
| 복잡성 | 복잡한 레이아웃 | 간단한 정렬 |
| 반응형 | 강력한 반응형 기능 | 유연한 크기 조절 |
.layout-grid {
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}
/* 명확한 이름 사용 */
.page-header { grid-area: header; }
.page-nav { grid-area: nav; }
.page-main { grid-area: main; }
.page-aside { grid-area: aside; }
.page-footer { grid-area: footer; }
/* 불필요한 재계산 방지 */
.grid-container {
contain: layout style;
}
/* 이미지 최적화 */
.grid-item img {
object-fit: cover;
width: 100%;
height: 100%;
}
/* 스크린 리더를 위한 순서 유지 */
.accessible-grid {
display: grid;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
}
@media (min-width: 768px) {
.accessible-grid {
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
}
CSS Grid와 Position Sticky을 활용하여 반응형인 웹 레이아웃을 구현할 수 있습니다