Flexbox toàn tập

Bài viết này sẽ hướng dẫn cho bạn mọi thứ về flexbox, bao gồm tất cả các thuộc tính cho phần tử cha (flex container) và phần tử con (flex items).
Flexbox toàn tập
Flexbox toàn tập

Thuật ngữ

  • Flex Layout: Flexible Box - vùng linh hoạt
  • Flex container / Container: phần tử cha
  • Flex items: phần tử con
  • Components: các thành phần nhỏ của ứng dụng

 

Giới thiệu

Flex Layout (bắt đầu được đề xuất sử dụng bởi W3C từ tháng 10 năm 2017) nhằm cung cấp một phương thức dàn trang hiệu quả hơn cho việc bố trí, căn chỉnh và phân phối không gian giữa các flex items trong một container, ngay cả khi kích thước của chúng là động hoặc không xác định.

Ý tưởng chính phía sau của flex layout là cung cấp cho container khả năng thay đổi chiều rộng / chiều cao (và thứ tự) của các flex items nhằm lấp đầy không gian có sẵn một cách tốt nhất (chủ yếu là để phù hợp với tất cả các loại thiết bị và kích thước màn hình). Flex layout mở rộng các flex items để lấp đầy không gian trống có sẵn hoặc thu nhỏ chúng để chống tràn (overflow).

Quan trọng nhất, Flex layout được thực thi theo cách trái ngược với kiểu dàn trang truyền thống (theo từng block theo chiều dọc và inline theo chiều ngang). Mặc dù những thứ đó hoạt động tốt cho các trang, nhưng chúng thiếu tính linh hoạt để hỗ trợ các ứng dụng lớn hoặc phức tạp (đặc biệt khi nói đến thay đổi hướng, thay đổi kích thước, kéo dài, thu nhỏ, v.v.).

Lưu ý: Flex layout thích hợp nhất cho các components của ứng dụng hoặc các bố cục quy mô nhỏ (small-scale layouts), trong khi Grid layout dành cho bố cục quy mô lớn hơn (large-scale layouts).

 

Khái niệm cơ bản

Bởi flexbox là một bộ module chứ không phải một thuộc tính riêng lẻ, cho nên nó liên quan đến rất nhiều thứ bao gồm các bộ thuộc tính của nó. Một số thuộc tính được định nghĩa cho container (phần tử cha - parent element, hay vùng linh hoạt - flex container), trong khi một số thuộc tính khác được định nghĩa cho các phần tử con - flex items.

Nếu cách thức dàn trang thông thường đều dựa trên hướng block và inline thì flex layout được thiết kế dựa trên flex-flow direction. 

Flex Flow Directions

Các thành phần sẽ được sắp xếp theo trục chính - main axis (từ main-start tới main-end) hoặc theo trục chéo - cross axis (từ cross-start tới cross-end).

  • main-axis: trục chính của một flex container là nơi mà các flex items được bố trí dọc theo đó. Hãy nhớ, nó không nhất thiết phải nằm ngang hay nằm dọc, nó hoàn toàn phụ thuộc vào thuộc tính flex-direction của container.
  • main-start | main-end: các flex items đặt bên trong container được sắp xếp theo chiều ngang, bắt đầu từ main-start cho đến main-end.
  • main-size: kích thước chính của flex items. Nó có thể là width - chiều rộng hoặc height - chiều cao, tùy thuộc vào trục chính - main axis của container.
  • cross-axis: trục chéo của một container. Nó nằm vuông góc với trục main-axis. Hướng của nó phụ thuộc vào hướng của main-axis.
  • cross-start | cross-end: mang ý nghĩa tương tự với main-start và main-end, nhưng theo hướng vuông góc với chúng.
  • cross-size: kích thước của flex items. Nó có thể là width - chiều rộng hoặc height - chiều cao, tùy thuộc vào trục chéo - cross axis của container.

 

Các thuộc tính dành cho parent - Container

Flex Container

 

display

Thuộc tính này giúp chỉ định một flex container. Các phần tử con trực tiếp của flex container sẽ trở thành flex items.

.container {
  display: flex | inline-flex;
}

 

flex-direction

Thuộc tính này giúp chúng ta thiết lập main axis, từ đó xác định hướng hiển thị của các flex items bên trong containerFlexbox là một khái niệm bố cục đơn hướng (single-direction layout concept). Bạn hãy nhớ các flex items được bố trí chủ yếu theo hàng ngang hoặc dọc.

.container { 
  flex-direction: row | column | row-reverse | column-reverse; 
}
  • row (được thiết lập mặc định): chuyển trục main axis theo chiều ngang. Các flex items được hiển thị từ trái qua phải (ở chế độ ltr), và phải qua trái (ở chế độ rtl).
  • row-reverse: tương tự như row, nhưng đảo ngược thứ tự các flex items.
  • column: chuyển trục main axis theo chiều dọc. Các flex items được hiển thị từ trên xuống dưới (ở chế độ ltr), và từ dưới lên trên (ở chế độ rtl).
  • column-reverse: tương tự như column, nhưng đảo ngược thứ tự các flex items.

 

flex-wrap

Theo mặc định, trình duyệt sẽ cố gắng sắp xếp tất cả flex items trên cùng một hàng. Bạn có thể thay đổi nó và cho phép các flex items xuống dòng khi cần thiết với thuộc tính này.

.container { 
  flex-wrap: nowrap | wrap | wrap-reverse; 
}
  • nowrap (mặc định): tất cả flex items sẽ được xếp trên cùng một hàng.
  • wrap: các flex items sẽ được bọc trên nhiều dòng, từ trên xuống dưới.
  • wrap-reverse: tương tự với wrap, nhưng theo thứ tự từ dưới lên trên.

Bạn có thể tham khảo một số ví dụ trực quan về flex-wrap ở https://css-tricks.com/almanac/properties/f/flex-wrap/.

 

flex-flow

Đây là một cách viết tắt, giúp chúng ta chỉ định cả 2 thuộc tính flex-direction và flex-wrap. Giá trị mặc định của flex-flow là row nowrap.

.container { 
  flex-flow: column wrap; 
}

 

justify-content

Justify Content

Thuộc tính này giúp xác định sự liên kết giữa các flex items dọc theo main axis. Nó giúp phân phối thêm không gian trống giữa các flex items trên cùng một hàng (flex line). Ngoài ra thuộc tính này còn thực hiện một số kiểm soát cho việc căn chỉnh các mục khi chúng tràn hàng (overflow).

.container { 
  justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly | start | end | left | right ... + safe | unsafe; 
}
  • flex-start (được thiết lập mặc định): các flex items được sắp xếp về phía bắt đầu của flex-direction.
  • flex-end: các flex items được sắp xếp về nơi kết thúc của flex-direction.
  • start: các flex items được sắp xếp về phía bắt đầu của hướng ghi (writing-mode direction).
  • end: các flex items được sắp xếp về nơi kết thúc của hướng ghi (writing-mode direction).
  • left: các flex items được sắp xếp về phía bên trái của container, trừ khi nó không hợp lý với flex-direction thì nó sẽ hoạt động như start.
  • right: các flex items được sắp xếp về phía bên phải của container, trừ khi nó không hợp lý với flex-direction thì nó sẽ hoạt động như end.
  • center: các flex items được căn giữa theo flex lines.
  • space-between: các mục được sắp xếp đều bên trong flex lines, các mục đầu tiên được xếp ở phần đầu của flex lines, các mục cuối cùng được sắp xếp tại phần cuối của flex lines.
  • space-around: các flex items được sắp xếp đều trên hàng với không gian bằng nhau giữa chúng. Cần lưu ý rằng, về mặt trực quan, trông có vẻ không gian giữa các mục là không đều nhau, điều này là do các flex items đều có cùng không gian trống ở hai bên.
  • space-evenly: các mục được phân phối khoảng trống là như nhau, kể cả khoảng cách giữa hai mục đầu và cuối so với container.

Bạn cũng cần lưu ý rằng, các trình duyệt khác nhau đều có một vài khác biệt nhất định cho các giá trị này. Ví dụ như space-between hầu như chưa được hỗ trợ từ Edge, cũng như các giá trị left | right | start | end vẫn chưa có ở Chrome. Các giá trị an toàn nhất là flex-start | flex-end | center.

Bạn có thể tham khảo liên kết sau để biết thêm chi tiết https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content.

Ngoài ra chúng ta còn có thêm một tham số bổ sung: safe | unsafe. Việc sử dụng safe đảm bảo rằng cho dù bạn tùy chỉnh position như thế nào, bạn cũng không thể đẩy một phần tử ra bên ngoài màn hình theo cách nội dung đó không cuộn được (hay còn gọi là mất dữ liệu - data loss).

 

align-items

Align items

Giá trị này chỉ định behaviour mặc định của các flex items theo trục chéo trên flex line hiện tại. Bạn có thể nghĩ về nó như là một phiên bản justify-content theo trục chéo cross axis.

.container { 
  align-items: stretch | flex-start | flex-end | center | baseline | first baseline | last baseline | start | end | self-start | self-end + ... safe | unsafe; 
}
  • stretch: kéo dài chiều cao để lấp đầy container (tuy nhiên vẫn tuân theo min-width/max-width).
  • flex-start / start: các flex items được sắp xếp về phía đầu trục chéo. Giá trị flex-start áp dụng cho flex-direction trong khi start áp dụng cho hướng ghi (writing-mode direction).
  • flex-end / end: các flex items được sắp xếp về phía cuối trục chéo. Giá trị flex-end áp dụng cho flex-direction trong khi end áp dụng cho hướng ghi (writing-mode direction).
  • center: các flex items được căn giữa theo trục chéo.
  • baseline: các mục được căn chỉnh theo đường cơ sở.

Ngoài ra, tham số safe | unsafe có thể được sử dụng kèm theo để ngăn chặn việc căn chỉnh các phần tử khiến nội dung không truy cập được.

 

align-content

Align content

Thuộc tính này căn chỉnh các flex lines của container khi có khoảng trống bên trong trục chéo (cross axis), tương tự với cách mà justify-content căn chỉnh các flex items theo trục chính (main axis).

Lưu ý: thuộc tính này sẽ vô hiệu khi container của bạn chỉ có duy nhất 1 flex line.

.container { 
  align-content: flex-start | flex-end | center | space-between | space-around | space-evenly | stretch | start | end | baseline | first baseline | last baseline + ... safe | unsafe; 
}
  • flex-start / start: các flex items được sắp xếp về phía đầu của container. Giá trị flex-start áp dụng cho flex-direction trong khi start áp dụng cho hướng ghi (writing-mode direction).
  • flex-end / end: các flex items được sắp xếp về phía cuối của container. Giá trị flex-end áp dụng cho flex-direction trong khi end áp dụng cho hướng ghi (writing-mode direction).
  • center: các flex items được phân phối vào chính giữa container.
  • space-between: các flex items được sắp xếp đồng đều, dòng đầu tiên ở sát phía đầu, dòng cuối cùng ở sát phía cuối.
  • space-around: các flex items được sắp xếp đồng đều với khoảng cách bằng nhau giữa mỗi flex line.
  • space-evenly: các flex items được phân phối đồng đều với khoảng cách bằng nhau giữa chúng.
  • stretch (default): các dòng được kéo dài độ cao nhằm chiếm hết không gian giữa chúng.

 

 

Các thuộc tính dành cho children - Flex Items

Flex Items

order

Flex order

Theo mặc định, thứ tự các flex items trùng khớp với thứ tự của chúng trong mã HTML. Tuy nhiên, bạn có thể hoàn toàn tùy chỉnh thứ tự sắp xếp của chúng qua thuộc tính này.

.item { 
  order: 3; /* giá trị mặc định là 0 */ 
}

 

flex-grow

Flex grow

Thuộc tính này giúp xác định khả năng thay đổi kích thước của flex items khi cần thiết. Giá trị hợp lệ ở đây là một số nguyên đóng vai trò như tỉ lệ. Nó sẽ chỉ định lượng không gian mà các flex items có thể đạt đến bên trong container.

Khi tất cả các flex ỉtems được đặt flex-grow là 1, không gian bên trong container sẽ được chia đều cho toàn bộ chúng. Nếu một vài flex item có giá trị bằng 2, thì kích thước của chúng sẽ gấp đôi so với các flex items còn lại (điều này không hoàn toàn đúng nhưng ít nhất hệ thống sẽ cố gắng để đạt được điều đó).

flex-grow được sử dụng khi tổng kích thước các flex items bên trong container của bạn nhỏ hơn kích thước của container, và bạn muốn nội dung bên trong container được lấp đầy.

.item { 
  flex-grow: 1; /* giá trị mặc định là 0 */ 
}

Giá trị nhỏ hơn 0 là không hợp lệ.

 

flex-shrink

Thuộc tính này chỉ định khả năng thu nhỏ kích thước của flex items khi cần thiết.

Ngược lại so với flex-growflex-shrink được sử dụng khi tổng kích thước các flex items lớn hơn kích thước của container, và bạn muốn các flex items co lại cho phù hợp với container.

.item { 
  flex-shrink: 2; /* giá trị mặc định là 0 */ 
}

Giá trị nhỏ hơn 0 là không hợp lệ.

 

flex-basis

Thuộc tính này xác định kích thước mặc định của một phần tử trước khi không gian còn lại được phân phối. Các giá trị hợp lệ bao gồm:

  • number: một đơn vị đo lường xác định (20%5rem100px...).
  • auto: mang ý nghĩa hệ thống sẽ tự động xem xét kích thước (width/height) của flex items (điều này được thực hiện tạm thời cho tới khi không cần nữa).
.item { 
  flex-basis: 100px | 20% | 100rem | ... | auto; /* giá trị mặc định là auto */ 
}

Nếu giá trị được thiết lập về 0, không gian thừa xung quanh nội dung sẽ không được tính vào. Nếu giá trị được thiết lập thành auto, không gian thừa sẽ được phân phối dựa trên giá trị flex-grow của chúng.

 

flex

Đây là cách viết tắt để thiết lập cả 3 thuộc tính flex-growflex-shrink, và flex-basis. Tham số thứ hai (flex-shrink) và thứ ba (flex-basis) là không bắt buộc.

.item { 
  flex: 1; /* flex-grow = 1, flex-shrink = 1, flex-basis = 0 */ 
  flex: 1 1 0; 
}

Giá trị mặc định của thuộc tính này là 0 1 auto.

Thuộc tính này được khuyên dùng hơn là việc thiết lập các thuộc tính con một cách riêng lẻ.

 

align-self

Align self

Bạn có thể hiểu thuộc tính này giống như align-items, nhưng chỉ tác dụng cho một số flex items riêng lẻ.

.item { 
  align-self: auto | flex-start | flex-end | center | baseline | stretch; 
}

Lưu ý rằng các thuộc tính như floatclearvertical-align sẽ không có tác dụng đối với các flex items.

 

Kết luận

Bài viết tới đây là kết thúc rồi. Cá nhân mình cảm nhận flexbox cực kỳ hay và hiệu quả cho việc dàn trang, nhất là với các trang có hỗ trợ mobile view.

Hi vọng thông qua bài viết này, các bạn sẽ nắm vững kiến thức về flexbox hơn. Nếu có câu hỏi gì thì các bạn cứ liên hệ với mình nhé.

 

Liên kết tham khảo

Comments

Bài viết nổi bật

PHP là ngôn ngữ được sử dụng rộng rãi nhất trên thế giới trong lập trình web. Nó cũng bị ghét nhất. Nhưng tại sao nhiều developer lại ghét nó đến vậy? Hôm nay chúng ta hãy cùng tìm hiểu lý do xem chúng có thuyết phục không nhé ^_^
Dạo gần đây đi đâu cũng nghe nói về microservices, người người nhà nhà rục rịch chuyển dịch hệ thống sang microservices. Trước khi đưa ra sự so sánh, mình sẽ khái quát một chút về Monolith Application và MicroServices một chút cho các bạn chưa biết nắm rõ hơn nhé.
Lúc trước mình hay sử dụng cách này trên laptop phụ của mình, giờ mua license luôn rồi. Hôm nay mình xin chia sẻ cho bạn nào cần nhé.
JWT Tokens là một cách thức lưu trữ thông tin xác thực hiệu quả, nhưng làm cách nào để chúng ta có thể giúp chúng an toàn hơn? Có 2 cách thường dùng để lưu trữ JWT Tokens là LocalStorage và Cookies. Bây giờ chúng ta sẽ bắt đầu "mổ xẻ" các ưu - nhược điểm của mỗi loại nhé.
Có khá nhiều bạn đã yêu cầu mình một bài viết về Repository Design Pattern. Vậy mục đích của nó là gì? Nó có thực sự cần thiết cho ứng dụng của bạn hay không? Những điểm mạnh, điểm yếu của nó là gì? Chúng ta cùng đi sâu tìm hiểu qua bài viết này nhé.

Mục lục

Related posts

Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Phân trang - một thành phần không thể thiếu trong các ứng dụng có lượng dữ liệu lớn. Tuy nhiên, bạn hiểu được bao nhiêu về nó?
Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
Dạo gần đây đi đâu cũng nghe nói về microservices, người người nhà nhà rục rịch chuyển dịch hệ thống sang microservices. Trước khi đưa ra sự so sánh, mình sẽ khái quát một chút về Monolith Application và MicroServices một chút cho các bạn chưa biết nắm rõ hơn nhé.
Cách bỏ qua câu lệnh --set-upstream quen thuộc cho các con lười
Mình sẽ giới thiệu 2 cách để xóa một property trong Javascript Object. Một cách sử dụng mutable - toán tử delete, một cách còn lại là immutable - tính năng Object Restructuring.

Tin mới nhất

Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Trong phần này, chúng ta sẽ tìm hiểu một số khái niệm cơ bản nhất về AWS là gì và một số lợi ích khi sử dụng AWS.
Trở thành một software developer hiệu suất cao không phải là điều dễ dàng. Điều này đòi hỏi bạn phải có kỹ năng và kiến thức về lập trình, cũng như cách tiếp cận và giải quyết các vấn đề phức tạp. Tuy nhiên, nếu bạn có chút kiên nhẫn và sự nỗ lực, bạn hoàn toàn có thể trở thành một developer tài năng và thành công.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Thông tin được định nghĩa dưới dạng dữ liệu, kiến thức về thông tin, và trí tuệ về tri thức.
Phân trang - một thành phần không thể thiếu trong các ứng dụng có lượng dữ liệu lớn. Tuy nhiên, bạn hiểu được bao nhiêu về nó?
Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.