< Lập trình tân binh | 3.2. Mô hình khối hộp

3.2. Mô hình khối hộp

1 trang web có thể được chia thành các khối hộp xếp cạnh nhau hoặc lồng vào nhau. Chúng ta thường gọi chúng là các “khối”. Phần lớn các thành phần mà chúng ta từng cùng thảo luận ở bài trước đếu là các khối : <header>, <article>, <nav>, vv… Ngoài ra còn nhiều thành phần khối khác cũng khá quen thuộc như khổ văn bản <p>, tiêu đề <h1>, vv...

Trong bài học này, chúng ta sẽ học cách thao tác với các mảng khối này như với những chiếc hộp thực sự : chúng ta có thể đưa ra cho chúng các kích thước, vui vẻ với việc căn chỉnh các lề, thao tác với nội dung, vv… để cho nội dung không bị hiển thị vượt quá kích thước của hộp.

Đây chính là các khái niệm căn bản nhất mà chúng ta cần sử dụng để lên trang cho trang web của chúng ta. Vậy nên đừng nháy mắt nhé, nếu không các bạn có thể bỏ lỡ điều gì đó.

Các thẻ kiểu khối và kiểu inline

Như đã từng nhắc đến trong phần trước của giáo trình, trong HTML, phần lớn các thẻ có thể chia thành 2 loại :

  • Các thẻ khối : ví dụ như thẻ khổ văn bản <p>
  • Các thẻ inline, hay thẻ nội dòng : ví dụ như thẻ đường dẫn liên kết <a>

! Ngoài ra vẫn còn 1 vài loại thẻ đặc biết khác như loại thẻ dùng cho các ô trong bảng (table-cell) hay loại thẻ dành cho thành viên trong 1 danh sách (list-item). Chúng ta sẽ tạm thời không để ý đến chúng bởi vì đấy chỉ là thiểu số giữa hàng tá thẻ HTML5.

? Làm sao tôi phân biệt được 1 thẻ inline với 1 thẻ khổi đây ?

Khá đơn giản :

  • Thẻ loại thẻ khối sẽ tự động tạo ra hiệu ứng xuống dòng ở trước và sau nó. Thật dễ để hình dung nó thành 1 khối phải không ? 1 trang web là tật hợp các khối như thể được sắp đặt cạnh nhau. Tiếp đó nữa, các bạn sẽ phát hiện ra là chúng ta thậm chí có thể lồng các khối hộp này vào với nhau nữa. Bằng cách đó, chúng ta có thêm rất nhiều khả năng có thể dùng để thiết kế trang web của chúng ta.
  • Các thẻ loại inline bắt buộc phải nằm bên trong 1 thẻ khối. Thẻ loại này không tạo ra hiệu ứng xuống dòng như các thẻ khối. Vậy nên nội dung trong thẻ này có thể nằm ngay cạnh nội dung bên ngoài thẻ, trên cùng 1 dòng. Đây là lý do tại sao chúng ta gọi chúng là thẻ nội dòng.

Để hiểu rõ hơn các khái niệm này, hãy quan sát hình minh họa sau.

  • Nền xanh là tất cả các thẻ khối.
  • Nền vàng chính là thẻ inline nằm bên trong thẻ khối.

Như các bạn có thể thấy, các khối hộp nằm cạnh nhau. Chúng ta đã nói chúng cũng có thể lồng vào nhau. Ví dụ điển hình nhất là việc khối <aside> nằm bên trong khổi <section> mà chúng ta đã nói đến trong bài trước. Thẻ inline <a></a> thì chèn nội dung của nó vào giữa dòng chữ nội dung của thẻ khối.

Vài ba ví dụ

Dưới đây là vài ba ví dụ các thẻ của mỗi loại để giúp các bạn có thể ghi nhớ phần nào.

Thẻ khối Thẻ inline
<p> <em>
<footer> <strong>
<h1> <mark>
<h2> <a>
<article> <img />

Bảng trên đây còn xa mới liệt kê hoàn chỉnh toàn bộ các thẻ chúng ta có trong HTML5. Nhưng không sao, các bạn có thể từ từ ghi nhớ từng chút một, không ai hối thúc chúng ta cả.

Các thẻ phổ thông

Lại thêm 1 chút kiến thức được nhắc lại để các bạn có thể ghi nhớ rõ ràng hơn. Ở đây, chúng ta đang bàn về các thẻ mà bản thân chúng không mang theo ý nghĩa đặc biệt nào (kiểu như <p> dùng cho các khổ văn bản hay <strong> dành cho các cụm quan trọng).

Lợi ích chính của các thẻ này đó là chúng ta có thể thêm các thuộc tính class hay id để sử dụng vào các mục đích riêng tùy từng trường hợp. Chúng ta có tổng cộng là 2 thẻ trong nhóm này, thật hay là chúng lại phân đều thuộc về 2 loại mà chúng ta vừa nhắc đến ở trên.

  • <span></span> là thẻ kiểu inline
  • <div></div> là thẻ kiểu khối
Tôn trọng ý nghĩa các thẻ

2 thẻ phổ thông mà chúng ta vừa nhắc đến ở trên vô cùng hữu dụng, thế nhưng không nên lạm dụng chúng 1 cách quá đáng. Tôi đã thấy rất nhiều lập trình viên web quá sa đà vào sử dụng các thẻ <span><div> mà quên đi rằng bên cạnh chúng vẫn còn các thẻ khác áp dụng hợp lý hơn trong các trường hợp cụ thể. Hãy xem vài ví dụ dưới đây.

  • Thẻ <span> vô dụng : mã <span class="quanTrong"> là cách sử dụng thẻ <span> hoàn toàn vô dụng. Mã này hoàn toàn không nên xuất hiện trong mã nguồn của chúng ta do thẻ <strong> hoàn toàn có thể đáp ứng được nhu cầu sử dụng trong trường hợp này.
  • Thẻ <div> vô dụng : <div class="tieuDe"> cũng vô dụng không kém khi mà chúng ta có cả đống thẻ tiêu đề từ lớn đến nhỏ <h1>, <h2>, vv…

Đồng ý với các bạn là kết quả cuối cùng mà chúng ta nhận được có thể như nhau. Thế nhưng các thẻ phổ thông hoàn toàn không mang theo ý nghĩa đặc trưng nào, và dưới góc nhìn của máy tính, chúng hoàn toàn vô dụng vì không mang theo thông tin nào cả. Vì thế, hãy sử dụng các thẻ phù hợp mục đích bất cứ khi nào có thể. Lời khuyên này thậm chí được Google đưa ra để giúp trang web của chúng ta có thể được nâng cao thứ hạng trong kết quả tìm kiếm của bộ máy này.

Các kích thước của hộp

Trong phần này thì chúng ta sẽ chỉ làm việc với các thẻ thuộc loại khối hộp.

Trước tiên, hãy chú ý đến kích thước của chúng. Khác với các thẻ inline, các thẻ khối có chiều rộng và chiều cao xác định. Chúng được thể hiện bới 2 thuộc tính CSS.

  • width : chiều rộng hay chiều ngang của khối, có thể được tính theo % hoặc đơn vị điểm ảnh px.
  • height : chiều dọc hay chiều cao của khối hộp, tương tự cũng được tính thao % hay px.

! Nói chính xác hơn thì width và height là các thuộc tính thuộc về nội dung bên trong khối hộp. Nếu có tồn tại các khoảng cách lề (chúng ta sẽ thảo luận đến sau) bên trong hộp thì chúng sẽ khiến kích thước hộp tăng lên.

Mặc định thì khối hộp chiếm 100% chiều rộng không gian có sẵn. Chúng ta có thể dễ dàng kiểm chứng điều này khi áp dụng 1 màu nền hoặc màu viền cho hộp.

Bây giờ, hãy thêm 1 chút mã CSS để có thể thay đổi chiều rộng của khối hộp nhé.

p {
    width: 50%;
}

Đoạn mã này mang ý nghĩa là chiều rộng khối chỉ chiếm 50% chiều rộng không gian có sẵn.

Chúng ta sử dụng đơn vị phần trăm khi muốn kích thước khối hộp tự động điều chỉnh theo kích thước phân giải của máy người dùng.

Đôi khi chúng ta lại cần thiết kế các khối với kích thước chính xác, khi đó chúng ta sẽ cần dùng tới đơn vị điểm ảnh.

p {
    width: 250px;
}
Cực tiểu và cực đại

Chúng ta có thể tùy chỉnh để thiết lập kích thước tối thiểu cũng như tối đa của 1 khối hộp. Việc này rất có ích do nó cho phép chúng ta định ra các giới hạn trong việc hiển thị các mảng khổi, giúp trang web của chúng ta có thể thích ứng với độ phân giải khác nhau của màn hình người dùng.

  • min-width : chiều rộng tối thiếu
  • max-width : chiều rộng tối đa
  • min-height : chiều cao tối thiểu
  • max-height : chiều cao tối đa

Ví dụ, chúng ta có thể yêu cầu 1 khổ văn bản chiếm 50% chiều rộng nhưng với điều kiện là kích thước này không thể nhỏ hơn 400 đơn vị điểm ảnh (pixel).

p {
    width: 50%;
    min-width: 400px;
}

Hãy thử nghiệm phóng to thu nhỏ cửa sổ. Kể cả khi cửa sổ trình duyệt quá nhỏ, khổ văn bản cũng nhất định chiếm ít nhất 400 pixel.

Mép lề

Chúng ta cần biết rằng, tất cả các khối đều có mép lề về các phía. Chúng thậm chí có đến 2 loại lề :

  • Lề trong
  • Lề ngoài

Trong hình vẽ bên trên, tôi đã thêm đường viền của hộp vào cho mọi người dễ hình dung.

  • Khoảng trống giữa nội dung và đường viền chính là lề trong (màu xanh)
  • Khoảng trống giữa đường viền với khối hộp bên cạnh là lề ngoài (màu đỏ)

Với CSS chúng ta có thể điều chỉnh kích thước các lề này nhờ 2 thuộc tính :

  • padding : kích thước của lề trong, thường tính theo đơn vị pixel
  • margin : kích thước của lề ngoài, cũng thường được tính theo pixel

! Các thẻ loại inline cũng sở hữu các thuộc tính này. Vậy nên các bạn cũng có thể thử điều chỉnh chúng trên các thẻ thuộc loại này.

Để quan sát rõ ràng các lề này, hãy thử sử dụng 1 khổ văn bản với đường viền đơn giản.

p {
    width: 350px;
    border: 1px solid black;
    text-align: justify;
}

Như có thể thấy, mặc định thì chúng ta sẽ không có lề trong (padding), tuy nhiên lại có sẵn lề ngoài (margin). Chính lề này làm chúng ta có cảm giác 2 khối văn bản không dính vào nhau mà giống như có 1 dòng ngăn cách ở giữa.

! Các kích thước lề mặc định không giống nhau, thay đổi tùy theo loại thẻ khối chúng ta sử dụng. Điều này có thể được kiểm chứng dễ dàng bằng cách sử dụng thẻ <div> để chứa văn bản thay vì <p>. Chúng ta sẽ nhận thấy là khối hộp này không có cả lề trong lẫn lề ngoài.

Chúng ta sẽ thử thêm khoảng cách lề trong 12 pixel vào cho khổ văn bản.

p {
    width: 350px;
    border: 1px solid black;
    text-align: justify;
    padding: 12px; /* Le trong 12px */
}

Thêm vào đó, tôi muốn khoảng cách giữa các hộp cạnh nhau tăng thêm. Chúng ta sẽ thêm vào 50px cho kích thước lề ngoài của các khối hộp.

p {
   width: 350px;
   border: 1px solid black;
   text-align: justify;
   padding: 12px;
   margin: 50px; /* Le ngoai 50px */
}

? Kích thước lề thêm vào cả  bên trái nữa à ?

Đúng vậy, margin hay padding đều áp dụng lên cả 4 phía của khối hộp. Nếu chúng ta chỉ muốn thay đổi lề của 1 phía cụ thể nào đó, chúng ta sẽ cần sử dụng các thuộc tính chính cụ thể hơn. Nguyên lý ở đây giống với những gì chúng ta đã biết với thuộc tính border.

Trái phải trên dưới...

Điểm qua 1 chút kiến thức tiếng anh cơ bản.

  • top : trên
  • bottom : dưới
  • left: trái
  • right : phải

Chỉ cần vậy là chúng ta có thể suy ra được tất cả các thuộc tính mà chúng ta có thể sử dụng. Tôi vẫn sẽ ghi ra đấy các thuộc tính marginpadding để các bạn có thể dễ dàng ghi nhớ và hiểu rõ hơn.

  • margin-top: lề ngoài trên
  • margin-bottom : lề ngoài dưới
  • margin-left : lề ngoài trái
  • margin-right : lề ngoài phải

  • padding-top: lề trong trên
  • padding-bottom : lề trong dưới
  • padding-left : lề trong trái
  • padding-right : lề trong phải

! Chúng ta cũng có 1 cách khác để thiết lập lề các phía chỉ dùng thuộc tính margin và padding. Ví dụ margin: 1px 2px 3px 4px; có nghĩa là “1px lề ngoài trên, 2px lề phải, 3px lề dưới và 4px lề trái”. Ngoài ra cũng có 1 cú pháp tắt nữa là margin: 2px 4px; nghĩa là “lề trên dưới là 2px và lề trái phải là 4px”.

Căn giữa

Chúng ta hoàn toàn có thể căn giữa cho khối hộp, nghĩa là yêu cầu khối hộp tự động nằm trên trục giữa trang. Lợi ích lớn của tính năng này là chúng ta có thể thiết kế trang web cân giữa, rất thích hợp khi không biết trước độ phân giải của màn hình người dùng.

Để căn giữa, chúng ta cần đáp ứng những điều kiện sau :

  • Đưa ra kích thước chiều rộng cho khối hộp nhờ width
  • Thiết lập sử dụng kích thước lề ngoài tự động với margin: auto;
p {
    width: 350px; /* Chieu rong bat buoc 350px */
    margin: auto; /* Tu dong can giua */
    border: 1px solid black;
    text-align: justify;
    padding: 12px;
    margin-bottom: 20px;
}

Vậy là chúng ta đã có các khổ văn bản lơ lửng ở giữa trang.

! Kỹ thuật này chỉ cho phép các khối được căn giữa theo chiều ngang chứ không thể căn theo chiều dọc.

Khi kích thức nội dung đi quá xa giới hạn…

Có 1 sự thật đáng buồn là khi chúng ta điều chỉnh kích thước cụ thể cho mảng khối của chúng ta, đôi khi chúng trở nên quá nhỏ để chứa hết được nội dung cần chứa bên trong nó.

Vừa may, những thuộc tính CSS mà chúng ta sẽ thảo luận dưới đây dùng để kiểm soát tình hình trong trường hợp vấn đề bên trên xảy ra.

overflow : ngắt khối

Hãy tưởng tượng chúng ta có 1 đoạn văn dài như 1 quyển tiểu thuyết nhưng lại chỉ có chỗ kích thước 250px chiều rộng và 110px chiều cao để hiển thị nó. Hãy xem chuyện gì xảy ra khi chúng ta cố gắng thực hiện việc hiển thị này.

p {
    width: 250px;
    height: 110px;
    text-align: justify;
    border: 1px solid black;
}

? Trời ơi, tại sao nội dung lại chạy hết ra khỏi khung thế kia ?

Không có gì ngạc nhiên cả. Chúng ta yêu cầu khối hộp mang các kích thước nhất định và chúng ta đã có điều chúng ta muốn. Thế nhưng không gỉ đảm bảo là toàn bộ nội dung có thể được chứa trong 1 diện tích bé như thế.

Nếu các bạn không muốn nội dung tràn ra ngoài giới hạn của kích thước khổ văn bản, chúng ta cần sử dụng đến thuộc tính overflow. Dưới đây là những giá trị chúng ta có thể gán cho thuộc tính này :

  • visible : là giá trị mặc định. Khi kích thước nội dung vượt quá kích thước hộp, chúng ta vẫn nhìn thấy phần nội dung tràn ra ngoài.
  • hidden : khi kích thước nội dung vượt quá giới hạn, nó sẽ bị cắt và chúng ta không thể thấy phần nội dung này.
  • scroll : trong trường hợp này, nội dung cũng bị cắt tương tự. Khác biệt là trình duyệt sẽ tạo ra 1 thanh chạy bên trong khối hộp để cho phép chúng ta có thể đọc được toàn bộ nội dung văn bản. Chúng ta sẽ có cảm giác như 1 cửa sổ nằm trong 1 cửa sổ khác.
  • auto : chế độ tự động. Chúng ta để trình duyệt tự quyết định xem có nên thêm thanh chạy vào khối hộp không. Vậy nên thanh chạy chỉ được thêm vào khi cần thiết. Đây là giá trị được khuyến khích sử dụng.

Với lệnh overflow: hidden; văn bản của chúng ta sẽ bị cắt như dưới đây.

Bây giờ, hãy cùng thử overflow: auto; với đoạn mã dưới đây.

p {
    width: 250px;
    height: 110px;
    text-align: justify;
    border: 1px solid black;
    overflow: auto;
}

Tuyệt vời ! Thế là chúng ta đã có thanh chạy để sử dụng nếu muốn đọc hết nội dung văn bản.

! HTML có 1 thẻ là <iframe> thuộc về loại thẻ thế hệ cũ. Chức năng của nó là hiển thị nội dung của 1 trang HTML hoàn chỉnh bên trong 1 trang HTML khác. Thẻ này cho kết quả tương tự như kết quả chúng ta vừa nhận được. Tuy nhiên, ngày nay, chúng ta được khuyến khích là không nên sử dụng thẻ này.

word-wrap : ngắt đoạn văn bản dài

Nếu bên trong khối hộp chúng ta cần hiển thị 1 nội dung dài, vượt quá chiều ngang khối, chúng ta sẽ cần sử dụng thuộc tính word-wrap. Thuộc tính này cho phép cưỡng ép ngắt khi gặp các từ quá dài (thường là 1 địa chỉ đường dẫn quá dài).

Đây là trường hợp xảy ra khi 1 đường dẫn quá dài được hiển thị trong khối văn bản.

Trình duyệt không biết là cần ngắt ở đâu do trong đường dẫn thì không có dấu cách, dấu chấm, dấu phảy, vv… để chỉ định vị trí ngắt.

Với đoạn mã CSS dưới đây, máy tính sẽ cưỡng ép việc ngắt từ này.

p {
    word-wrap: break-word;
}

! Tôi đề nghị là nên sử dụng thuộc tính này cho những vùng nội dung chứa nội dung cung cấp bởi người dùng do chúng ta không làm chủ được kích thước của nó (ví dụ như bình luận diễn đàn, nội dung ghi chú riêng, tin nhắn riêng của người dùng, vv…). Hành động này sẽ hạn chế ảnh hưởng của những nội dung trên tới thiết kế trang web của chúng ta.

Tóm tắt bài học :
  • Chúng ta phân ra 2 loại thẻ HTML :
    • Thẻ khối như <p>, <h1> : là những thẻ tự động tạo ra hiệu ứng xuống dòng để phân cách với các thẻ khác. Mặc định thì chúng chiếm tất cả chiều rộng có sẵn. Chúng sẽ sắp xếp từ trên xuống dưới.
    • Thẻ nội dòng như <a>, <strong> : chứa nội dung nằm giữa dòng. Chúng sắp xếp từ trái qua phải.
  • Chúng ta có thể thay đổi kích thước của thẻ thuộc kiểu khối với các thuộc tính CSS width (chiều rộng) và height (chiều cao).
  • Chúng ta có thể định ra các kích thước tối thiểu và tối đa cho chiều rộng và chiều cao : min-height, max-height, min-width, max-width.
  • Mỗi đối tượng đều sở hữu các thuộc tính căn lề : lề trong (padding) và lề ngoài (margin).
  • Nếu kích thước nội dung vượt quá kích thước cố định của khổi hộp mà chúng ta đã định nghĩa, nội dung có nguy cơ hiển thị tràn ra ngoài. Trong trường hợp đó, chúng ta có thể thêm vào thanh chạy nhờ overflow hoặc cưỡng ép ngắt từ với word-wrap.