Bố cục

Podcast CSS - 009: Bố cục

Hãy tưởng tượng bạn đang là một nhà phát triển và một đồng nghiệp của nhóm thiết kế trao 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 kiểu bố cục và bố cục thú vị: bố cục hai chiều có quan tâm đến chiều rộng và chiều cao của khung nhìn, cũng như bố cục cần linh hoạt và linh hoạt. Làm cách nào để quyết định cách tốt nhất để tạo kiểu cho các đối tượng này bằng CSS?

CSS cung cấp cho chúng ta nhiều cách để giải quyết các vấn đề về bố cục, trên trục hoành, trục tung hay thậm chí cả hai. Chọn phương thức bố cục phù hợp cho ngữ cảnh có thể khó khăn, và thường 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 các mô-đun sau, bạn sẽ tìm hiểu về các tính năng độc đáo của mỗi cơ chế bố cục CSS để cung cấp thông tin cho các quyết định đó.

Bố cục: một lịch sử ngắn

Trong những ngày đầu của web, các thiết kế phức tạp hơn một tài liệu đơn giản được bố trí bằng các phần tử <table>. 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 sử dụng rộng rãi vào cuối thập niên 90. CSS đã mở ra cánh cửa cho các nhà phát triển có thể thay đổi hoàn toàn giao diện của trang web mà không cần chạm đến HTML. Chức năng mới này đã truyền cảm hứng cho các dự án như CSS Zen Garden, được tạo ra để thể hiện sức mạnh của CSS, qua đó khuyến khích nhiều nhà phát triển hơn tìm hiểu 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 thay đổi. Bạn có thể đọc về sự phát triển của bố cục CSS và phương pháp bố cục của chúng tôi theo thời gian tại bài viết này của Rachel Andrew.

Tiến trình cho thấy quá trình 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 biệt mạnh mẽ. Chúng tôi có các hệ thống bố cục chuyên biệt và chúng tôi sẽ xem xét ở cấp độ cao về những gì chúng tôi có thể sử dụng, trước khi tìm hiểu chi tiết hơn về Flexbox và Grid trong các mô-đun tiếp theo.

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

Thuộc tính display thực hiện 2 việc. Việc đầu tiên là xác định xem hộp được áp dụng để hoạt động như cùng dòng hay chặn.

.my-element {
  display: inline;
}

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

Sơ đồ cho thấy tất cả các kích thước của một hộp, cũng như vị trí bắt đầu và kết thúc của mỗi phần kích thước

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

.my-element {
    display: block;
}

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

.my-element {
    display: flex;
}

Thuộc tính display cũng xác định cách hoạt động của phần tử con của một phần tử. Ví dụ: việc đặt thuộc tính display thành display: flex sẽ khiến hộp này trở thành hộp cấp khối, và cũng chuyển đổi các phần tử con thành các mục linh hoạt. Việc 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 và luồng.

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

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

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, hộp linh hoạt 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 chúng theo hướng khối sao cho chúng có cùng chiều cao.

Các mục sẽ ở trên cùng một trục và không được gói khi hết không gian. Thay vào đó, các em sẽ cố gắng ép vào cùng một dòng. 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.

Hộp linh hoạt cũng chuyển đổi các phần tử con thành các mục linh hoạt, tức 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ăn chỉnh, thứ tự và lý do cho 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;
}

Các 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 phương diện nội dung và khung nhìn không xác định. Đ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 có nhiều điểm tương đồng với flexbox, nhưng nó được thiết kế để điều khiển 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 viết quy tắc bố cục trên một phần tử có display: grid, và giới thiệu một vài dữ liệu gốc mới để tạo kiểu bố cục, chẳng hạn như hàm repeat()minmax(). Một đơn vị lưới hữu ích là đơn vị fr, chiếm một phần không gian còn lại. Bạn có thể xây dựng các lưới gồm 12 cột truyền thống, với một khoảng cách giữa từng mục, với 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 một bố cục một trục. Trong trường hợp này, 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í đặt quảng cáo theo hai chiều. Chúng ta có thể xác định rằng mục đầu tiên trong lưới này có 2 hàng và 3 cột:

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

Thuộc tính grid-rowgrid-column hướng dẫn phần tử đầu tiên trong lưới kéo dài đế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 hộp linh hoạt hoặc lưới, các phần tử của bạn hiển thị trong luồng bình thường. Có một số phương thức bố cục mà bạn có thể sử dụng để điều chỉnh hành vi và vị trí của các mục khi ở luồng thông thường.

Khối cùng dòng

Bạn có nhớ rằng các phần tử xung quanh không tuân theo lề và khoảng đệm của khối trên một phần tử cùng dòng không? Với inline-block, bạn có thể khiến đ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 chạy 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, việc văn bản đó bọc quanh hình ảnh như bạn có thể thấy trên báo như vậy có tiện cho mình không? Bạn có thể thực hiện việc này bằng số thực.

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

Thuộc tính float yêu cầu 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 ở bên trái, sau đó cho phép các phần tử đồng cấp "gói" xung quanh. Bạn có thể hướng dẫn một phần tử thực dấu phẩy động left, right hoặc inherit.

Bố cục nhiều cột

Nếu có một danh sách dài gồm các phần tử, chẳng hạn như danh sách tất cả quốc gia trên thế giới có thể khiến người dùng phải cuộn rất nhiều và lãng phí thời gian. Thao tá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 phần 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ố lượng cột để phân chia nội dung, 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ó nhiều không gian hơn trong khung nhìn, nhiều cột hơn sẽ tự động được tạo và khi không gian giảm, sẽ giảm xuống. Điều này rất hữu ích trong ngữ cảnh thiết kế web đáp ứng.

Xác lập vị thế

Cuối cùng, trong phần tổng quan này về cơ chế bố cục là vị trí. Thuộc tính position thay đổi cách hoạt động của một phần tử trong luồng thông thường của tài liệu, và mối liên hệ với các thành phần khác. Hiện có các lựa chọn là relative, absolute, fixedsticky với giá trị mặc định là static.

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

Phần tử này bị dịch chuyển xuống 10 px dựa trên vị trí hiện tại của nó trong tài liệu, khi đượ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 của nó giờ đây sẽ được đặt lại vị trí thành phần tử cụ thể này, thay vì thành phần mẹ tương đối trên cùng, khi phương thức này được áp dụng 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 đặt position thành absolute, nó phá vỡ phần tử đó ra khỏi luồng 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 đều chỉnh lại luồng để lấp đầy không gian còn lại mà phần tử đó còn lại.

Một 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ể có được nền tảng cố định, các khía cạnh cố định của fixed và các khía cạnh dễ dự đoán hơn để tôn vinh luồng tài liệu của relative bằng cách dùng sticky. Với giá trị này, khi khung nhìn cuộn qua phần tử, nó vẫn được liên kết với các giá trị top, right, bottomleft mà bạn đã đặt.

Tổng kết

Có rất nhiều lựa chọn và tính linh hoạt với bố cục CSS. Để tìm hiểu sâu hơn về sức mạnh của CSS FlexboxGrid, hãy tiếp tục chuyển đến một số mô-đun tiếp theo.

Kiểm tra kiến thức

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

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

Xác định inline hoặc block hoặc none.
Layout Engine cần biết hộp này có chiều rộng tối đa hay không và nó 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ể đặt chế độ hiển thị thành lưới nhưng không liên quan gì đến khung bố cục.
Xác định hành vi của trẻ.
Hộp linh hoạt và lưới có ý kiến và tính năng mới cho con họ.
Xác định xem hộp có nên cuộn hay không.
Đó là thuộc tính overflow.

Để chuyển nhiều đoạn vào các cột, thuộc tính CSS nào phù hợp nhất việc cần làm này là gì?

display: grid
Mặc dù lưới có thể đặt nhiều đoạn vào cột, nhưng các cột đó sẽ là các cột riêng và không liên tục nối từ cột này sang cột khác.
column-count
Các đoạn sẽ đi từ cuối một cột đến đầu cột tiếp theo, giống như một tạp chí hoặc báo.
display: flex
Mặc dù 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 liên kết với nhau từ các đoạn tương tự.
float
Hãy thử lại!

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

Nó bị mắc kẹt ở bên bờ sông.
Bối cảnh ở đây là CSS chứ không phải địa lý.
Thuộc tính này đã được gán giá trị vị trí top hoặc left.
Việc chỉ có những thuộc tính này sẽ không kéo ra khỏi luồng.
Thuộc tính này không còn được định vị dựa trên vị trí của các thành phần cùng cấp.
Ví dụ: một hộp có position: absolute, hiện được định vị bằng toạ độ x và y dựa trên khối chứa chứ không phải thứ tự của hộp đó với các phần tử đồng cấp 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 sử dụng flex-wrap: wrap hoặc repeat(auto-fit, 30ch) cho dịch vụ này.
Sai
Hộp linh hoạt và Lưới có các tính năng gói đặc biệt cần có kiểu bổ sung để áp dụng.