Trong lập trình front-end, chúng ta sẽ thường xuyên phải làm việc với yêu cầu cần chia thành các hàng cột để hiện thị được nhiều dữ phần tử dữ liệu, ngoài flex box thì grid cũng là một lựa chọn.

Kiến thức cơ bản

Ví dụ chúng ta muốn hiển thị 3 hàng 3 cột cho các dữ liệu chúng ta có thể tạo mã nguồn như sau:

<!DOCTYPE html>
<html>
<head>
<style>
.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 10px;
}

.container div {
  padding: 40px;
  text-align: center;
  font-size: 20px;
  color: white;
  border-radius: 8px;
}

.container div:nth-child(1) { background: #e74c3c; }
.container div:nth-child(2) { background: #9b59b6; }
.container div:nth-child(3) { background: #3498db; }
.container div:nth-child(4) { background: #1abc9c; } 
.container div:nth-child(5) { background: #f1c40f; }
.container div:nth-child(6) { background: #e67e22; }
.container div:nth-child(7) { background: #2ecc71; }
.container div:nth-child(8) { background: #16a085; }
.container div:nth-child(9) { background: #34495e; }
</style>
</head>
<body>

<div class="container">
  <div>1</div><div>2</div><div>3</div>
  <div>4</div><div>5</div><div>6</div>
  <div>7</div><div>8</div><div>9</div>
</div>

</body>
</html>

Ở đây chúng ta sử dụng:

  • Thuộc tính: display: grid; để chỉ định rằng các phần tử trong .container sẽ được chia theo hàng và cột.
  • Thuộc tính grid-template-columns: 1fr 1fr 1fr;: Với fr là viết tắt của fractional unit là tỉ lệ chi không gian cho 3 cột, ở đây chúng ta chia 3 cột bằng nhau. Bạn cũng có thể sử dụng grid-template-columns: repeat(3, 1fr); nó cũng tương đương và ngắn gọn hơn. Ngoài ra bạn cũng có thể sử dụng kích thước cụ thể thay vì fr ví dụ 200px, 300px.
  • Thuộc tính gap: 10px;: Chỉ định khoảng cách giữa các hàng và cột là 10px.

Và kết quả chúng ta nhận được sẽ là:

Grid inline

Đôi khi bạn muốn hiện thị grid trên cùng dòng với văn bản, bạn có thể sử dụng thuộc tính display: inline-grid;. Ví dụ đoạn mã sau:

<!DOCTYPE html>
<html>
<head>
<style>
.grid-inline {
  display: inline-grid;
  grid-template-columns: 1fr 1fr;
  background: pink;
}
.grid-inline div {
  border: 1px solid #555;
  padding: 10px;
}
</style>
</head>
<body>
<p>Grid dạng inline:</p>
<span class="grid-inline">
  <div>C</div><div>D</div>
</span>
<span>➡️ Văn bản này nằm cùng dòng với grid!</span>
​
</body>
</html>

Sẽ cho kết quả 2 ô CD nằm cùng dòng với văn bản.

Các nhóm thuộc tính cơ bản của grid

Nó bao gồm các nhóm.

Nhóm xác định hàng và cột

Thuộc tínhMô tảVí dụ
grid-template-columnsĐịnh nghĩa số và kích thước các cộtgrid-template-columns: 200px 1fr 2fr;
grid-template-rowsĐịnh nghĩa số và kích thước các hànggrid-template-rows: 100px auto 100px;
grid-template-areasĐặt layout theo tên vùnggrid-template-areas: "header header" "sidebar main" "footer footer";

Với grid-template-areas bạn có thể đặt tên cho các vùng từ đó dễ theo dõi hơn, ví dụ bạn có thể dàn một trang có phần đầu ở trên, phần menu bên trái, phần nội dung bên phải và phân chân trang ở cuối với mã nguồn như sau:

<!DOCTYPE html>
<html>
<head>
<style>
.container {
  display: grid;
  grid-template-areas:
    "header header"
    "menu content"
    "footer footer";
  grid-template-columns: 1fr 3fr;
  gap: 3px;
  background-color: #abcdff;
  padding: 5px;
}
.container div {
  background-color: white;
  padding: 10px;
}
.container div.header {
  grid-area: header;
  text-align: center;
}
.container div.menu {
  grid-area: menu;
}
.container div.content {
  grid-area: content;
}
.container div.footer {
  grid-area: footer;
  text-align: center;  
}
</style>
</head>
<body>

<div class="container">
  <div class="header"><h2>Đầu trang</h2></div>
  <div class="menu"><a href="#">Đường dẫn 1</a><br><a href="#">Đường dẫn 2</a><br><a href="#">Đường dẫn 3</a></div>
  <div class="content"><h3>Thân trang</h3><p>Lorem ipsum odor amet, consectetuer adipiscing elit. Ridiculus sit nisl laoreet facilisis aliquet. Potenti dignissim litora eget montes rhoncus sapien neque urna. Cursus libero sapien integer magnis ligula lobortis quam ut.</p></div>
  <div class="footer"><h4>Chân trang</h4></div>
</div>

</body>
</html>

Ở đây bạn chỉ định phần đầu sẽ chiếm 2 cột, phần menu chiếm 1 cột, phần thân trang chiếm 1 cột và phần chân trang chiếm 2 cột, kết quả bạn nhận được là:

Nhóm khoảng cách và tự động lặp

Thuộc tínhMô tảVí dụ
gap (hoặc grid-gap)Khoảng cách giữa các ô (cả hàng và cột)gap: 10px;
row-gapKhoảng cách giữa các hàngrow-gap: 20px;
column-gapKhoảng cách giữa các cộtcolumn-gap: 15px;
repeat()Hàm giúp lặp kích thước nhiều lầngrid-template-columns: repeat(3, 1fr);
minmax()Giới hạn kích thước min/maxgrid-template-columns: repeat(3, minmax(100px, 1fr));
auto-fit / auto-fillTự động lấp đầy hoặc co giãn ôgrid-template-columns: repeat(auto-fit, minmax(150px, 1fr));

Các thuộc tính auto-fillauto-fit hơi khó hiểu, vậy chúng ta sẽ giải thích kỹ hơn. Ví dụ chúng ta có mã nguồn như sau:

<!DOCTYPE html>
<html>
<head>
<style>
.grid {
  display: grid;
  gap: 10px;
  background: #f0f0f0;
  padding: 10px;
  border: 1px solid #ccc;
}
.grid div {
  background: #3498db;
  color: #fff;
  text-align: center;
  padding: 20px;
  border-radius: 5px;
}
.fill {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.fit {
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
</style>
</head>
<body>
<div class="wrapper">
  <div class="grid fill">
    <div>1</div><div>2</div><div>3</div><div>4</div>
  </div>
  <div class="grid fit">
    <div>1</div><div>2</div><div>3</div><div>4</div>
  </div>
</div>
</body>
</html>

Kết quả chúng ta nhận được là:

Như bạn có thể thấy với auto-fill nó sẽ tạo ra các cột vừa với độ rộng được quy định tối thiểu là 150px và tối đa là một cột (minmax(150px, 1fr)) và nếu độ rộng của màn hình lớn thì hàng vẫn còn dư khoảng trống.

Nhưng với auto-fit thì nó sẽ tạo ra các cột với kích thước được tuỳ chỉnh để sao cho lấp đầy toàn bộ độ rộng của màn hình nhưng vẫn đảm bảo tối thiểu độ rộng một cột là 150px.

Nhóm căn chỉnh toàn bộ grid

Thuộc tínhMô tảVí dụ
justify-itemsCăn nội dung trong cột (theo chiều ngang)justify-items: center;
align-itemsCăn nội dung trong hàng (theo chiều dọc)align-items: start;
place-itemsGộp align-itemsjustify-itemsplace-items: center;
justify-contentCăn toàn bộ grid theo chiều ngangjustify-content: space-between;
align-contentCăn toàn bộ grid theo chiều dọcalign-content: center;
place-contentGộp align-contentjustify-contentplace-content: center;

Để dễ hiểu hơn chúng ta sẽ có ví dụ sau:

<!DOCTYPE html>
<html>
<head>
<style>
.container {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(2, 100px);
  gap: 10px;
  width: 330px;
  height: 220px;
  border: 2px dashed #aaa;
  background: #f8f8f8;
  justify-content: center;
  align-content: start;
  justify-items: start;
  align-items: center;

  background-image:
    linear-gradient(to right, rgba(128,0,255,0.4) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(128,0,255,0.4) 1px, transparent 1px);
  background-size: 110px 110px;
  background-position: 0 0;
  box-shadow: 0 0 0 2px rgba(128,0,255,0.6);
}

.container div {
  background: #3498db;
  color: white;
  font-size: 20px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
</style>
</head>
<body>
<div class="container">
  <div>1</div><div>2</div><div>3</div>
  <div>4</div><div>5</div><div>6</div>
</div>
</body>
</html>

Và kết quả chúng ta nhận được là:

Như bạn có thể thấy justify-content: center; làm cho container của chúng ta được căn giữa theo chiều ngang, align-content: start; làm cho container của chúng ta căn trái theo chiều dọc. justify-items: start; làm cho nội dung trong ô được căn trái theo chiều dọc và align-items: center; làm cho nội dung trong ô được căn giữa theo chiều ngang.

Nhóm thuộc tính của Grid Item

Thuộc tínhMô tảVí dụ
grid-column-start / grid-column-endVị trí bắt đầu / kết thúc theo cộtgrid-column: 1 / 3;
grid-row-start / grid-row-endVị trí bắt đầu / kết thúc theo hànggrid-row: 2 / 4;
grid-column / grid-rowViết gộpgrid-column: 1 / span 2;
grid-areaDùng tên vùng hoặc chỉ định vùng trực tiếpgrid-area: header; hoặc grid-area: 1 / 1 / 2 / 3;
justify-selfCăn chỉnh phần tử riêng theo chiều ngangjustify-self: center;
align-selfCăn chỉnh phần tử riêng theo chiều dọcalign-self: end;
place-selfGộp align-selfjustify-selfplace-self: center;

Để hiểu rõ hơn, chúng ta sẽ có ví dụ như sau:

<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<style>
.container {
  display: grid;
  grid-template-columns: repeat(4, 100px);
  grid-template-rows: repeat(3, 100px);
  background: #f0f0f0;
  border: 2px dashed #aaa;
  
  background-image:
    linear-gradient(to right, rgba(128,0,255,0.4) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(128,0,255,0.4) 1px, transparent 1px);
  background-size: 100px 100px;
  background-position: 0 0;
  box-shadow: 0 0 0 2px rgba(128,0,255,0.6);
}

.container div {
  color: white;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
}

.item1 {
  background: #e74c3c;
  grid-column: 1 / 3;
  grid-row: 1 / 2
}

.item2 {
  background: #aabbcc;
  grid-area: 2 / 1 / 3 / 3;
}

.item3 {
  background: #2ecc71;
  justify-self: end; 
}

.item4 {
  background: #9b59b6;
  align-self: end;
}

.item5 {
  background: #1abc9c;
  place-self: center start;
}

.item6 {
  background: #e67e22;
}
</style>
</head>
<body>

<div class="container">
  <div class="item1">grid-column + grid-row</div>
  <div class="item2">grid-area</div>
  <div class="item3">justify-self</div>
  <div class="item4">align-self</div>
  <div class="item5">place-self</div>
  <div class="item6">mặc định</div>
</div>

</body>
</html>

Và kết quả nhận được là:

Như bạn có thể thấy:

.item1 {
  grid-column: 1 / 3;
  grid-row: 1 / 2
}

Làm cho cho ô item1 sẽ bắt đầu từ đường cột số 1 đến đường cột số 3 nghĩa là chiếm 2 cột đầu tiên và bắt đầu từ đường hàng số 1 đến đường hàng số 2 tức là chiếm một hàng đầu tiên.

.item2 {
  grid-area: 2 / 1 / 3 / 3;
}

Sẽ làm cho ô item2 bắt đầu tại hàng 2, bắt đầu tại cột một, kết thúc trước hàng 3 và kết thúc trước cột 3 tức là chiếm 2 ô đầu tiên tại hàng thứ 2.

Tổng kết

Ngoài flex thì grid cũng là một trong những lựa chọn cho chia hàng cột cho trang web đặc biệt trong nghiệp vụ phân trang. Nó có rất nhiều thuộc tính nhưng chủ yếu chúng ta sẽ sử dụng các thuộc tính trong Nhóm khoảng cách và tự động lặp.