Bài 2.4: Thực hành tạo layout với CSS

Bài 2.4: Thực hành tạo layout với CSS
Chào mừng bạn trở lại với chuỗi bài học về Lập trình Web Front-end! Nếu HTML là bộ xương định hình cấu trúc trang web, thì CSS chính là linh hồn thổi sức sống và vẻ đẹp vào bộ xương ấy. Và một trong những vai trò quan trọng nhất của CSS chính là tạo layout – sắp xếp, bố cục các thành phần trên trang sao cho khoa học, dễ nhìn và thu hút người dùng.
Việc tạo layout hiệu quả không chỉ làm cho trang web của bạn trông chuyên nghiệp hơn mà còn ảnh hưởng trực tiếp đến trải nghiệm người dùng (UX) và khả năng phản hồi (responsive) trên các thiết bị khác nhau. Trong bài thực hành này, chúng ta sẽ cùng nhau khám phá các kỹ thuật tạo layout kinh điển và hiện đại nhất trong CSS.
Hãy cùng bắt tay vào thực hành ngay thôi!
1. Nắm Vững Các Thuộc Tính display
Cơ Bản
Trước khi nhảy vào các kỹ thuật phức tạp hơn, chúng ta cần hiểu rõ cách các phần tử HTML hiển thị mặc định và cách CSS thay đổi điều đó bằng thuộc tính display
. Đây là nền tảng của mọi layout.
display: block;
: Đây là cách hiển thị mặc định của các phần tử nhưdiv
,p
,h1
,section
, v.v. Một phần tử block sẽ chiếm toàn bộ chiều rộng có thể có và luôn bắt đầu trên một dòng mới. Bạn có thể dễ dàng đặtwidth
,height
,margin
,padding
cho chúng.display: inline;
: Các phần tử nhưspan
,a
,strong
,em
thường có kiểu hiển thị này. Phần tử inline chỉ chiếm đúng không gian cần thiết cho nội dung của nó và không bắt đầu trên một dòng mới. Bạn không thể đặtwidth
vàheight
trực tiếp cho phần tử inline, vàmargin-top
,margin-bottom
cũng không có tác dụng.display: inline-block;
: Đây là sự kết hợp đáng giá. Một phần tửinline-block
sẽ hiển thị trên cùng một dòng giống nhưinline
, nhưng bạn có thể đặtwidth
,height
,margin
,padding
cho nó giống nhưblock
. Kỹ thuật này từng được sử dụng nhiều để tạo các menu ngang hoặc các khối nội dung nằm cạnh nhau trước khi Flexbox và Grid ra đời.
Ví dụ cơ bản:
<div class="box box-block">Block</div>
<div class="box box-block">Block</div>
<span class="box box-inline">Inline</span>
<span class="box box-inline">Inline</span>
<div class="box box-inline-block">Inline-Block</div>
<div class="box box-inline-block">Inline-Block</div>
.box {
padding: 10px;
margin: 5px;
background-color: lightblue;
border: 1px solid blue;
color: blue;
font-weight: bold;
}
.box-block {
display: block; /* Mặc định của div */
width: 100px; /* Chiếm toàn bộ chiều rộng nếu không đặt */
}
.box-inline {
display: inline; /* Mặc định của span */
/* width, height, margin-top, margin-bottom SẼ KHÔNG CÓ TÁC DỤNG */
}
.box-inline-block {
display: inline-block;
width: 100px; /* CÓ TÁC DỤNG */
height: 50px; /* CÓ TÁC DỤNG */
}
Giải thích code:
- Chúng ta định nghĩa một style
.box
chung để dễ nhìn. .box-block
minh họa lại hành vi mặc định củadiv
(chiếm dòng mới, có thể đặt kích thước)..box-inline
minh họa hành vi mặc định củaspan
(trên cùng dòng, không nhận kích thước dọc)..box-inline-block
cho thấy cách hai phần tử này nằm trên cùng một dòng nhưng vẫn có thể đặtwidth
vàheight
.
Hiểu rõ sự khác biệt này là cực kỳ quan trọng khi làm việc với các kỹ thuật layout khác!
2. Vị Trí Của Các Phần Tử Với Thuộc Tính position
Thuộc tính position
cho phép bạn kiểm soát chính xác vị trí của một phần tử trên trang. Nó thường đi kèm với các thuộc tính top
, right
, bottom
, left
và z-index
(kiểm soát thứ tự lớp xếp chồng).
position: static;
: Đây là giá trị mặc định. Phần tử hiển thị theo luồng bình thường của tài liệu. Các thuộc tínhtop
,right
,bottom
,left
,z-index
sẽ không có tác dụng.position: relative;
: Phần tử được định vị tương đối so với vị trí ban đầu của nó trong luồng tài liệu bình thường. Khi bạn sử dụngtop
,right
,bottom
,left
, phần tử sẽ dịch chuyển khỏi vị trí ban đầu, nhưng khoảng trống ban đầu của nó vẫn được giữ lại.position: absolute;
: Đây là một kỹ thuật mạnh mẽ nhưng cần cẩn thận. Phần tử được định vị tuyệt đối so với phần tử cha được định vị gần nhất (phần tử cha cóposition
khácstatic
). Nếu không có phần tử cha nào được định vị, nó sẽ định vị tương đối so với<html>
hoặc<body>
. Quan trọng: Phần tửabsolute
bị loại bỏ khỏi luồng tài liệu bình thường, nghĩa là các phần tử khác sẽ hiển thị như thể nó không tồn tại.position: fixed;
: Phần tử được định vị tuyệt đối so với viewport (cửa sổ trình duyệt). Nó sẽ luôn ở yên tại vị trí đó ngay cả khi người dùng cuộn trang. Thường dùng cho header, footer hoặc nút cuộn lên đầu trang.position: sticky;
: Là sự kết hợp giữarelative
vàfixed
. Phần tử được định vị tương đối trong luồng tài liệu bình thường cho đến khi nó đạt đến một ngưỡng cuộn nhất định (được xác định bởitop
,right
,bottom
,left
), lúc đó nó trở thànhfixed
và dính vào vị trí đó trong viewport. Thường dùng cho các thanh sidebar hoặc tiêu đề bài viết "dính".
Ví dụ về relative
và absolute
:
<div class="container-relative">
<div class="box box1">Relative Parent</div>
<div class="box box2">Absolute Child</div>
</div>
<div class="box box3">Another Block</div>
.container-relative {
position: relative; /* Đặt position khác static cho cha */
width: 300px;
height: 150px;
border: 2px dashed green;
margin-bottom: 20px;
padding: 10px;
}
.box {
padding: 10px;
border: 1px solid;
}
.box1 {
background-color: lightcoral;
position: relative; /* Tương đối với vị trí ban đầu của nó */
top: 10px;
left: 10px;
/* Vị trí ban đầu của box1 vẫn để lại khoảng trống */
}
.box2 {
background-color: lightgoldenrodyellow;
position: absolute; /* Tuyệt đối so với .container-relative */
top: 20px;
right: 20px;
/* box2 bị loại bỏ khỏi luồng, không ảnh hưởng đến box3 */
}
.box3 {
background-color: lightgray;
/* box3 hiển thị như thể box2 không tồn tại ở vị trí ban đầu của nó */
}
Giải thích code:
.container-relative
được đặtposition: relative;
. Điều này biến nó thành "phần tử cha được định vị" cho bất kỳ phần tửabsolute
nào bên trong nó..box1
được đặtposition: relative;
và dịch chuyển 10px xuống và 10px sang phải so với vị trí đáng lẽ của nó. Chú ý là phần tử.box3
bên dưới vẫn được đẩy xuống như thể.box1
đang ở vị trí ban đầu của nó..box2
được đặtposition: absolute;
. Vì nó nằm trong.container-relative
(đã được định vị), nó sẽ được đặt cách cạnh trên 20px và cạnh phải 20px của.container-relative
. Quan sát sẽ thấy.box2
nằm "trên" các phần tử khác và.box3
nằm ngay dưới.container-relative
, bỏ qua không gian mà.box2
đáng lẽ chiếm giữ.
Kỹ thuật position: absolute
bên trong position: relative
là cực kỳ phổ biến để định vị các phần tử con (như icon, label, thông báo nhỏ) chính xác bên trong một phần tử cha.
3. Sức Mạnh Của Flexbox Cho Layout Một Chiều
Flexbox (Flexible Box Module) là một mô hình layout được thiết kế để giúp bạn dễ dàng căn chỉnh, phân phối không gian và sắp xếp các phần tử trong một chiều (ngang hoặc dọc). Nó tuyệt vời cho các thanh điều hướng, các nhóm nút, các card nằm cùng hàng hoặc cùng cột.
Bạn bắt đầu bằng cách đặt display: flex;
cho phần tử cha (gọi là flex container). Các phần tử con trực tiếp bên trong nó sẽ trở thành flex items.
Các thuộc tính chính trên Flex Container:
display: flex;
: Biến container thành flex container.flex-direction
: Xác định hướng của main axis (trục chính) -row
(mặc định, theo hàng ngang),column
(theo cột dọc),row-reverse
,column-reverse
.justify-content
: Căn chỉnh các flex items dọc theo main axis. Các giá trị phổ biến:flex-start
,flex-end
,center
,space-between
,space-around
,space-evenly
.align-items
: Căn chỉnh các flex items dọc theo cross axis (trục vuông góc với main axis). Các giá trị phổ biến:stretch
(mặc định),flex-start
,flex-end
,center
,baseline
.flex-wrap
: Kiểm soát xem các flex items có xuống dòng khi không đủ không gian không (nowrap
- mặc định,wrap
,wrap-reverse
).
Các thuộc tính chính trên Flex Items:
flex-grow
: Xác định khả năng của item mở rộng để lấp đầy không gian trống còn lại trong container.flex-shrink
: Xác định khả năng của item co lại nếu không đủ không gian.flex-basis
: Xác định kích thước ban đầu của item trước khi phân bổ không gian.flex
: Viết tắt củaflex-grow
,flex-shrink
,flex-basis
. Ví dụ:flex: 1;
(tương đương1 1 0%
).align-self
: Ghi đè thuộc tínhalign-items
của container cho một item cụ thể.
Ví dụ về Flexbox:
<div class="flex-container">
<div class="flex-item">Item 1</div>
<div class="flex-item">Item 2</div>
<div class="flex-item">Item 3</div>
</div>
<div class="flex-container column-layout">
<div class="flex-item">Item A</div>
<div class="flex-item">Item B</div>
<div class="flex-item">Item C</div>
</div>
.flex-container {
display: flex; /* Biến thành flex container */
border: 2px dashed purple;
padding: 10px;
margin-bottom: 20px;
height: 100px; /* Chỉ định chiều cao để thấy align-items rõ hơn */
justify-content: space-around; /* Phân bổ không gian quanh các items */
align-items: center; /* Căn giữa các items theo chiều dọc */
}
.column-layout {
flex-direction: column; /* Sắp xếp items theo cột */
height: 200px; /* Tăng chiều cao cho cột */
justify-content: center; /* Căn giữa items theo chiều dọc (trục chính) */
align-items: flex-start; /* Căn items theo lề trái (trục phụ) */
}
.flex-item {
background-color: lightgreen;
border: 1px solid green;
padding: 15px;
margin: 5px;
}
Giải thích code:
.flex-container
đầu tiên:display: flex;
tạo ra một hàng ngang mặc định.justify-content: space-around;
đặt khoảng trống đều nhau quanh các items.align-items: center;
căn giữa các items theo chiều dọc của container..column-layout
: Thừa hưởngdisplay: flex;
nhưng đặtflex-direction: column;
để sắp xếp items theo cột.justify-content: center;
bây giờ căn giữa items theo chiều dọc (vìflex-direction
làcolumn
).align-items: flex-start;
căn các items về lề trái (vì trục phụ bây giờ là chiều ngang).
Flexbox cực kỳ linh hoạt và mạnh mẽ cho việc căn chỉnh và phân phối không gian một chiều. Bạn sẽ sử dụng nó rất nhiều trong các dự án thực tế!
4. Xây Dựng Layout Hai Chiều Với CSS Grid
Nếu Flexbox là vua của layout một chiều, thì CSS Grid Layout chính là hoàng đế của layout hai chiều (hàng và cột cùng lúc). Grid cho phép bạn tạo ra các cấu trúc lưới phức tạp, hoàn hảo cho layout tổng thể của một trang web (header, sidebar, content, footer) hoặc các layout dạng lưới phức tạp hơn như thư viện ảnh, danh sách sản phẩm.
Bạn bắt đầu bằng cách đặt display: grid;
cho phần tử cha (gọi là grid container). Các phần tử con trực tiếp sẽ trở thành grid items.
Các thuộc tính chính trên Grid Container:
display: grid;
: Biến container thành grid container.grid-template-columns
: Xác định số lượng và kích thước của các cột. Có thể dùng các đơn vị nhưpx
,%
,em
,rem
, và đặc biệt là đơn vịfr
(fraction) - đơn vị phân bổ không gian trống còn lại. Ví dụ:grid-template-columns: 1fr 1fr 1fr;
(tạo 3 cột có chiều rộng bằng nhau),grid-template-columns: 100px auto 1fr;
(cột 1 100px, cột 2 tự động co giãn theo nội dung, cột 3 chiếm hết không gian còn lại).grid-template-rows
: Xác định số lượng và kích thước của các hàng.gap
(hoặcgrid-gap
): Tạo khoảng cách giữa các hàng và cột. Viết tắt củarow-gap
vàcolumn-gap
.justify-items
: Căn chỉnh nội dung bên trong các item dọc theo trục ngang trong ô lưới của chúng.align-items
: Căn chỉnh nội dung bên trong các item dọc theo trục dọc trong ô lưới của chúng.justify-content
: Căn chỉnh toàn bộ lưới bên trong container dọc theo trục ngang.align-content
: Căn chỉnh toàn bộ lưới bên trong container dọc theo trục dọc.
Các thuộc tính chính trên Grid Items:
grid-column-start
,grid-column-end
: Xác định cột bắt đầu và kết thúc của item.grid-row-start
,grid-row-end
: Xác định hàng bắt đầu và kết thúc của item.grid-column
: Viết tắt củagrid-column-start / grid-column-end
. Ví dụ:grid-column: 1 / 3;
(chiếm từ cột 1 đến cột 3, tức là 2 cột).grid-row
: Viết tắt củagrid-row-start / grid-row-end
.grid-area
: Viết tắt củagrid-row-start / grid-column-start / grid-row-end / grid-column-end
. Hoặc có thể đặt tên cho area trong container và dùng thuộc tính này để đặt item vào area đó.
Ví dụ về CSS Grid:
<div class="grid-container">
<header class="grid-item header">Header</header>
<nav class="grid-item sidebar">Sidebar</nav>
<main class="grid-item content">Content</main>
<footer class="grid-item footer">Footer</footer>
</div>
.grid-container {
display: grid; /* Biến thành grid container */
grid-template-columns: 1fr 3fr; /* Cột 1 chiếm 1 phần, cột 2 chiếm 3 phần */
grid-template-rows: auto 1fr auto; /* Hàng 1 tự động, hàng 2 chiếm hết còn lại, hàng 3 tự động */
gap: 15px; /* Khoảng cách 15px giữa các hàng và cột */
height: 400px; /* Chiều cao container để thấy hàng 2 chiếm hết */
border: 2px dashed orange;
padding: 10px;
}
.grid-item {
background-color: lightyellow;
border: 1px solid orange;
padding: 15px;
text-align: center;
}
/* Định vị các item vào vị trí mong muốn trong lưới */
.header {
grid-column: 1 / 3; /* Chiếm từ cột 1 đến cột 3 (tức 2 cột) */
grid-row: 1; /* Ở hàng 1 */
}
.sidebar {
grid-column: 1; /* Ở cột 1 */
grid-row: 2; /* Ở hàng 2 */
}
.content {
grid-column: 2; /* Ở cột 2 */
grid-row: 2; /* Ở hàng 2 */
}
.footer {
grid-column: 1 / 3; /* Chiếm từ cột 1 đến cột 3 (tức 2 cột) */
grid-row: 3; /* Ở hàng 3 */
}
Giải thích code:
.grid-container
được đặtdisplay: grid;
.grid-template-columns: 1fr 3fr;
định nghĩa hai cột. Cột đầu tiên có kích thước là 1 phần (1fr
) của không gian trống, cột thứ hai là 3 phần (3fr
). Tổng cộng có 4 phần, cột 1 chiếm 1/4, cột 2 chiếm 3/4 không gian trống sau khi trừ đigap
và kích thước cố định nếu có.grid-template-rows: auto 1fr auto;
định nghĩa ba hàng. Hàng đầu và hàng cuối có chiều cao tự động theo nội dung (auto
). Hàng ở giữa (1fr
) sẽ chiếm hết chiều cao còn lại của container.gap: 15px;
tạo khoảng cách 15px giữa các ô lưới.- Các class
.header
,.sidebar
,.content
,.footer
sử dụnggrid-column
vàgrid-row
để xác định vị trí và kích thước của từng item trong lưới đã định nghĩa. Ví dụ,.header
chiếm từ đường kẻ cột 1 đến đường kẻ cột 3 (bao phủ cả hai cột 1fr và 3fr) và nằm ở hàng 1.
CSS Grid là công cụ tối ưu cho việc xây dựng layout trang web phức tạp và phản hồi. Việc kết hợp Grid cho cấu trúc tổng thể và Flexbox cho các thành phần bên trong từng ô Grid là một kỹ thuật rất phổ biến và mạnh mẽ.
5. Lựa Chọn Kỹ Thuật Nào?
Với nhiều kỹ thuật layout như vậy, câu hỏi đặt ra là khi nào nên dùng cái nào?
display: block
,inline
,inline-block
: Sử dụng cho các phần tử đơn lẻ hoặc các bố cục rất đơn giản, khi bạn chỉ cần kiểm soát cách chúng hiển thị trên dòng.position
: Dùng để định vị chính xác một phần tử tương đối với vị trí ban đầu, cha mẹ được định vị hoặc viewport. Rất hữu ích cho các lớp phủ, popup, icon định vị chính xác, header/footer cố định. Không dùng để tạo layout chính của trang.float
: Nên hạn chế sử dụng cho layout chính. Chủ yếu còn được dùng cho mục đích ban đầu của nó là làm văn bản bao quanh hình ảnh. Flexbox và Grid đã thay thế Float trong hầu hết các trường hợp tạo cột.- Flexbox: Lý tưởng cho layout một chiều. Tuyệt vời để căn chỉnh items trong một hàng (menu, form inputs) hoặc một cột (danh sách). Sử dụng khi bạn chỉ quan tâm đến việc phân phối không gian và căn chỉnh trên một trục duy nhất.
- CSS Grid: Lý tưởng cho layout hai chiều. Hoàn hảo để xây dựng cấu trúc tổng thể của trang web (header, footer, sidebar, main content) hoặc các layout dạng lưới phức tạp hơn. Sử dụng khi bạn cần kiểm soát cả hàng và cột cùng lúc.
Thường thì, bạn sẽ kết hợp Flexbox và Grid. Ví dụ, sử dụng Grid để tạo layout chính của trang, sau đó sử dụng Flexbox bên trong một ô Grid để căn chỉnh các thành phần con của ô đó.
Comments