Bố cục

Podcast CSS – 009: Bố cục

Giả sử bạn đóng vai trò là nhà phát triển, một đồng nghiệp nhà thiết kế giao cho bạn bản thiết kế cho một trang web hoàn toàn mới. Thiết kế này có tất cả các loại bố cục và bố cục thú vị: bố cục hai chiều có tính đến chiều rộng và chiều cao của khung nhìn, cũng như các bố cục cần linh hoạt và linh hoạt. Làm cách nào để xác định cách tốt nhất để tạo kiểu cho những quảng cáo này bằng CSS?

CSS cung cấp cho chúng tôi nhiều cách để giải quyết các vấn đề về bố cục, trên trục ngang, trục dọc hoặc thậm chí cả hai. Việc chọn phương thức bố cục phù hợp cho một ngữ cảnh có thể khó và thường thì bạn có thể cần nhiều phương thức bố cục để giải quyết vấn đề của mình. Để giúp giải quyết vấn đề này, trong những mô-đun sau đây, bạn sẽ tìm hiểu về các tính năng độc đáo của từng cơ chế bố cục CSS để đưa ra các quyết định đó.

Bố cục: lịch sử ngắn gọn

Ở thời kỳ đầu của web, các phần tử <table> có thiết kế phức tạp hơn so với một tài liệu đơn giản. Việc tách HTML khỏi các kiểu hình ảnh trở nên dễ dàng hơn khi CSS được các trình duyệt áp dụng rộng rãi vào cuối những năm 90. CSS mang đến cho các nhà phát triển khả năng thay đổi hoàn toàn giao diện của trang web mà không cần đụng đến HTML. Chức năng mới này đã truyền cảm hứng cho các dự án như The CSS Zen Garden (Vườn Zen của CSS). Công cụ này được tạo ra để thể hiện sức mạnh của CSS nhằm khuyến khích thêm nhiều nhà phát triển tìm hiểu về CSS.

CSS đã phát triển khi nhu cầu thiết kế web và công nghệ trình duyệt của chúng tôi cũng thay đổi. Bạn có thể đọc cách chúng tôi phát triển bố cục CSS và cách chúng tôi phát triển theo thời gian đối với bố cục CSS trong bài viết này của Rachel Andrew.

Tiến trình cho biết sự phát triển của CSS trong những năm qua, bắt đầu từ năm 1996 đến năm 2021

Bố cục: hiện tại và tương lai

CSS hiện đại có công cụ bố cục cực kỳ mạnh mẽ. Chúng tôi có các hệ thống chuyên biệt về bố cục và sẽ có thông tin tổng quan về các tính năng hiện có, trước khi tìm hiểu chi tiết hơn về Flexbox và Grid trong những học phần tiếp theo.

Tìm hiểu về thuộc tính display

Thuộc tính display có hai chức năng. Điều đầu tiên cần làm là xác định xem hộp được áp dụng để hoạt động cùng dòng hay chặn.

.my-element {
  display: inline;
}

Các thành phần cùng dòng hoạt động như các từ trong một câu. Chúng nằm cạnh nhau theo hướng cùng dòng. Các phần tử như <span><strong>, thường dùng để tạo kiểu cho các đoạn văn bản trong chứa các phần tử như <p> (đoạn), sẽ nằm cùng dòng theo mặc định. Các thuộc tính này cũng giữ nguyên các khoảng trắng xung quanh.

Sơ đồ thể hiện tất cả các kích thước của một hộp và vị trí bắt đầu và kết thúc của từng phần kích thước

Bạn không thể đặt chiều rộng và chiều cao rõ ràng đối với các phần tử cùng dòng. Các phần tử xung quanh sẽ bỏ qua khoảng đệm và lề của cấp khối.

.my-element {
    display: block;
}

Các thành phần khối không được đặt cạnh nhau. Họ tự tạo ra một dòng giới thiệu mới. Trừ phi được mã CSS khác thay đổi, phần tử khối sẽ mở rộng bằng kích thước của kích thước cùng dòng, do đó trải rộng trên toàn bộ chiều rộng ở chế độ ghi theo chiều ngang. Lề ở tất cả các bên của một phần tử khối sẽ được áp dụng.

.my-element {
    display: flex;
}

Thuộc tính display cũng xác định hành vi của các phần tử con của phần tử. Ví dụ: việc đặt thuộc tính display thành display: flex sẽ biến hộp đó thành hộp cấp khối, đồng thời chuyển đổi các phần tử con của nó thành các mục linh hoạt. Điều này cho phép các thuộc tính linh hoạt kiểm soát việc căn chỉnh, sắp xếp thứ tự và luồng.

Hộp linh hoạt và lưới

Có 2 cơ chế bố cục chính để tạo quy tắc bố cục cho nhiều phần tử, đó là flexboxgrid. Các API này có những điểm tương đồng nhưng được thiết kế để giải quyết những vấn đề về bố cục khác nhau.

Hộp linh hoạt

.my-element {
    display: flex;
}

Hộp linh hoạt là cơ chế bố cục cho bố cục một chiều. Bố cục trên một trục, theo chiều ngang hoặc chiều dọc. Theo mặc định, flexbox sẽ căn chỉnh các phần tử con của phần tử cạnh nhau, theo hướng cùng dòng và kéo dài theo hướng khối, để tất cả các phần tử con đều có cùng chiều cao.

Các mục sẽ ở trên cùng một trục và không xuống dòng khi hết dung lượng. Thay vào đó, chúng sẽ cố gắng xếp vào cùng một dòng với nhau. Bạn có thể thay đổi hành vi này bằng cách sử dụng các thuộc tính align-items, justify-contentflex-wrap.

Flexbox cũng chuyển đổi các phần tử con thành mục linh hoạt, nghĩa là bạn có thể viết các quy tắc về cách chúng hoạt động bên trong vùng chứa linh hoạt. Bạn có thể thay đổi cách căn chỉnh, thứ tự và căn chỉnh trên từng mục. Bạn cũng có thể thay đổi cách thu nhỏ hoặc phát triển bằng thuộc tính flex.

.my-element div {
    flex: 1 0 auto;
}

Thuộc tính flex là viết tắt của flex-grow, flex-shrinkflex-basis. Bạn có thể mở rộng ví dụ trên như sau:

.my-element div {
 flex-grow: 1;
 flex-shrink: 0;
 flex-basis: auto;
}

Nhà phát triển cung cấp các quy tắc cấp thấp này để gợi ý cho trình duyệt về cách hoạt động của bố cục khi bị thách thức bởi kích thước nội dung và khung nhìn. Điều này khiến đây trở thành một cơ chế rất hữu ích để thiết kế web thích ứng.

Lưới

.my-element {
    display: grid;
}

Lưới tương tự như nhiều cách để flexbox, nhưng được thiết kế để kiểm soát bố cục nhiều trục thay vì bố cục một trục (không gian dọc hoặc ngang).

Lưới cho phép bạn ghi các quy tắc bố cục trên một phần tử có display: grid, đồng thời giới thiệu một số dữ liệu nguyên gốc mới để định kiểu bố cục, chẳng hạn như các hàm repeat()minmax(). Một đơn vị lưới hữu ích là đơn vị fr (chỉ là một phần không gian còn lại) mà bạn có thể xây dựng các lưới truyền thống gồm 12 cột, với khoảng cách giữa mỗi mục, bằng 3 thuộc tính CSS:

.my-element {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 1rem;
}

Ví dụ ở trên cho thấy bố cục trục đơn. Trong trường hợp flexbox chủ yếu coi các mục là một nhóm, lưới cho phép bạn kiểm soát chính xác vị trí của các mục đó theo hai chiều. Chúng ta có thể xác định rằng mục đầu tiên trong lưới này chiếm 2 hàng và 3 cột:

.my-element :first-child {
  grid-row: 1/3;
  grid-column: 1/4;
}

Các thuộc tính grid-rowgrid-column hướng dẫn phần tử đầu tiên trong lưới trải rộng đến đầu cột thứ tư, từ cột đầu tiên, sau đó kéo dài đến hàng thứ ba, từ hàng đầu tiên.

Bố cục luồng

Nếu không sử dụng lưới hoặc hộp linh hoạt, các phần tử sẽ xuất hiện theo luồng bình thường. Có một số phương thức bố cục mà bạn có thể dùng để điều chỉnh hành vi và vị trí của các mục khi trong luồng thông thường.

Khối cùng dòng

Bạn có nhớ các phần tử xung quanh không tuân theo lề khối và khoảng đệm trên phần tử cùng dòng không? Với inline-block, bạn có thể tạo ra điều đó xảy ra.

p span {
    display: inline-block;
}

Việc sử dụng inline-block sẽ cung cấp cho bạn một hộp có một số đặc điểm của phần tử cấp khối, nhưng vẫn lưu chuyển cùng dòng với văn bản.

p span {
    margin-top: 0.5rem;
}

Nổi

Nếu bạn có hình ảnh nằm trong một đoạn văn bản, thì văn bản đó có thuận tiện để bao bọc quanh hình ảnh đó như bạn thấy trên báo không? Bạn có thể thực hiện việc này với số thực có độ chính xác đơn.

img {
    float: left;
    margin-right: 1em;
}

Thuộc tính float hướng dẫn một phần tử "nổi" theo hướng đã chỉ định. Hình ảnh trong ví dụ này được hướng dẫn ở dạng nổi sang trái, sau đó cho phép các thành phần đồng cấp "gói" xung quanh hình ảnh đó. Bạn có thể hướng dẫn một phần tử làm nổi left, right hoặc inherit.

Bố cục nhiều cột

Nếu bạn có một danh sách thực sự dài các phần tử, chẳng hạn như danh sách tất cả các quốc gia trên thế giới, thì việc này có thể khiến người dùng phải cuộn nhiều và lãng phí thời gian. Việc này cũng có thể tạo ra khoảng trắng thừa trên trang. Với nhiều cột CSS, bạn có thể chia cột này thành nhiều cột để giải quyết cả hai vấn đề này.

<h1>All countries</h1>
<ul class="countries">
  <li>Argentina</li>
  <li>Aland Islands</li>
  <li>Albania</li>
  <li>Algeria</li>
  <li>American Samoa</li>
  <li>Andorra</li>
  …
</ul>
.countries {
    column-count: 2;
    column-gap: 1em;
}

Thao tác này sẽ tự động chia danh sách dài đó thành hai cột và thêm một khoảng trống giữa hai cột.

.countries {
    width: 100%;
    column-width: 260px;
    column-gap: 1em;
}

Thay vì đặt số cột mà nội dung được chia tách, bạn cũng có thể xác định chiều rộng tối thiểu mong muốn, bằng cách sử dụng column-width. Khi có thêm không gian trong khung nhìn, nhiều cột hơn sẽ được tạo tự động và khi không gian giảm xuống, các cột cũng sẽ giảm xuống. Điều này rất hữu ích trong ngữ cảnh thiết kế web thích ứng.

Khẳng định vị thế

Bài viết cuối cùng trên trang tổng quan về cơ chế bố cục là vị trí. Thuộc tính position thay đổi hành vi của một phần tử trong luồng thông thường của tài liệu và mối quan hệ giữa phần tử đó với các phần tử khác. Các tuỳ chọn hiện có là relative, absolute, fixedsticky với giá trị mặc định là static.

.my-element {
  position: relative;
  top: 10px;
}

Phần tử này được dịch chuyển xuống 10 px dựa trên vị trí hiện tại trong tài liệu, vì phần tử này được đặt tương ứng với chính nó. Việc thêm position: relative vào một phần tử cũng khiến phần tử này trở thành khối chứa của mọi phần tử con có position: absolute. Điều này có nghĩa là phần tử con giờ đây sẽ được định vị lại cho phần tử cụ thể này, thay vì phần tử mẹ tương đối trên cùng, khi phần tử này có vị trí tuyệt đối.

.my-element {
  position: relative;
  width: 100px;
  height: 100px;
}

.another-element {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 50px;
    height: 50px;
}

Khi bạn thiết lập position thành absolute, thao tác này sẽ chia phần tử ra khỏi quy trình tài liệu hiện tại. Điều này có nghĩa là:

  1. Bạn có thể định vị phần tử này ở bất cứ nơi nào bạn muốn bằng cách sử dụng top, right, bottomleft trong phần tử mẹ tương đối gần nhất.
  2. Tất cả nội dung xung quanh một phần tử tuyệt đối sẽ chỉnh lại để lấp đầy khoảng trống còn lại mà phần tử đó còn lại.

Phần tử có giá trị positionfixed hoạt động theo cách tương tự như absolute, trong đó phần tử mẹ là phần tử <html> gốc. Các phần tử vị trí cố định vẫn được neo từ trên cùng bên trái dựa trên các giá trị top, right, bottomleft mà bạn đặt.

Bạn có thể sử dụng sticky để có được các khía cạnh cố định, cố định của fixed cũng như các khía cạnh dễ dự đoán hơn trong việc chỉnh sửa luồng tài liệu của relative. Với giá trị này, khi khung nhìn cuộn qua phần tử, khung nhìn sẽ vẫn liên kết với các giá trị top, right, bottomleft mà bạn đã đặt.

Tóm tắt

Có nhiều lựa chọn và tính linh hoạt với bố cục CSS. Để tìm hiểu thêm về sức mạnh của CSS FlexboxGrid, hãy tiếp tục tìm hiểu một số học phần tiếp theo.

Kiểm tra mức độ hiểu biết của bạn

Kiểm tra kiến thức của bạn về bố cục

Thuộc tính display có 2 chức năng gì?

Xác định inline, block hoặc none.
Công cụ bố cục cần biết liệu hộp này có chiều rộng đầy đủ hay không và có cần một dòng mới không.
Xác định khung bố cục lưới.
Thuộc tính hiển thị có thể thiết lập chế độ hiển thị thành lưới, nhưng không liên quan đến khung bố cục.
Xác định hành vi nên cư xử của trẻ.
Hộp linh hoạt và lưới có các ý kiến và tính năng mới dành cho các thành phần con cháu.
Xác định xem hộp có nên cuộn hay không.
Đó là thuộc tính overflow.

Để đưa nhiều đoạn văn vào cột, thuộc tính CSS nào là phù hợp nhất cho nhiệm vụ này?

display: grid
Mặc dù lưới có thể đặt nhiều đoạn văn vào cột, nhưng những cột đó sẽ là các cột riêng, không chạy cùng nhau từ đoạn này sang cột khác.
column-count
Các đoạn sẽ chạy từ cuối một cột sang đầu cột tiếp theo, như tạp chí hoặc báo sẽ làm.
display: flex
Mặc dù tính năng flex có thể đặt nhiều đoạn văn vào các cột, nhưng các cột đó sẽ là các cột riêng, không cần phải di chuyển cùng nhau từ đoạn này sang đoạn tiếp theo.
float
Hãy thử lại!

Một khối nằm ngoài luồng có nghĩa là gì?

Thiết bị bị kẹt ở bên bờ sông.
Bối cảnh là CSS chứ không phải vị trí địa lý.
Mô-đun này đã được cấp một giá trị vị trí top hoặc left.
Nếu chỉ có các thuộc tính này thì bạn sẽ không thể làm gì hết.
Giá trị này không còn được định vị dựa trên các vị trí cùng cấp.
Ví dụ: một hộp có position: absolute giờ đây có toạ độ x và y dựa trên khối chứa, chứ không dựa trên thứ tự của khối này với các phần tử phụ khác.

Hộp linh hoạt và Lưới bao bọc các phần tử con theo mặc định?

Đúng
Bạn phải chọn tham gia flex-wrap: wrap hoặc repeat(auto-fit, 30ch).
Sai
Hộp linh hoạt và Lưới có các tính năng xuống dòng đặc biệt cần có thêm kiểu để áp dụng.