Bạn có thể làm bố cục HTML này mà không cần sử dụng bảng không?


102

Ok, tôi đã gặp sự cố đơn giản về bố cục một hoặc hai tuần trước. Cụ thể là các phần của trang cần có tiêu đề:

+---------------------------------------------------------+
| Title                                            Button |
+---------------------------------------------------------+

Công cụ khá đơn giản. Điều đó là sự căm ghét bảng dường như đã chiếm lĩnh thế giới Web, điều mà tôi đã được nhắc đến khi tôi hỏi Tại sao lại sử dụng thẻ danh sách định nghĩa (DL, DD, DT) cho các biểu mẫu HTML thay vì bảng? Bây giờ chủ đề chung của bảng so với divs / CSS trước đây đã được thảo luận, ví dụ:

Vì vậy, đây không phải là một cuộc thảo luận chung về CSS và bảng để bố trí. Đây chỉ đơn giản là giải pháp cho một vấn đề. Tôi đã thử các giải pháp khác nhau cho vấn đề trên bằng cách sử dụng CSS bao gồm:

  • Phao bên phải cho nút hoặc một div chứa nút;
  • Định vị tương đối cho nút; và
  • Vị trí tương đối + tuyệt đối.

Không có giải pháp nào trong số này là thỏa đáng vì các lý do khác nhau. Ví dụ: vị trí tương đối dẫn đến sự cố chỉ mục z trong đó menu thả xuống của tôi xuất hiện bên dưới nội dung.

Vì vậy, tôi đã kết thúc việc quay lại:

<style type="text/css">
.group-header { background-color: yellow; width: 100%; }
.group-header td { padding: 8px; }
.group-title { text-align: left; font-weight: bold; }
.group-buttons { text-align: right; }
</style>
<table class="group-header">
<tr>
  <td class="group-title">Title</td>
  <td class="group-buttons"><input type="button" name="Button"></td>
</tr>
</table>

Và nó hoạt động hoàn hảo. Nó đơn giản, như khả năng tương thích ngược (có thể sẽ hoạt động ngay cả trên IE5) và nó chỉ hoạt động. Không gây rối với định vị hoặc phao.

Vì vậy, bất cứ ai có thể làm tương đương mà không có bảng?

Các yêu cầu là:

  • Tương thích ngược: tới FF2 và IE6;
  • Nhất quán hợp lý: trên các trình duyệt khác nhau;
  • Căn giữa theo chiều dọc: nút và tiêu đề có độ cao khác nhau; và
  • Linh hoạt: cho phép kiểm soát chính xác một cách hợp lý đối với vị trí (đệm và / hoặc lề) và kiểu dáng.

Ngoài ra, tôi đã xem qua một số bài viết thú vị ngày hôm nay:

CHỈNH SỬA: Hãy để tôi nói rõ hơn về vấn đề float. Loại công trình này:

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; overflow: hidden; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-title { float: left; padding: 8px; }
      .group-buttons { float: right; padding: 8px; }
    </style>
  </head>
  <body>
    <div class="group-header">
      <div class="group-title">This is my title</div>
      <div class="group-buttons"><input type="button" value="Collapse"></div>
    </div>
    <div class="group-content">
      <p>And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.</p>
      <p>So can anyone do the equivalent without tables that is backwards compatible to at least FF2 and IE6?</p>
      <p>On a side note, I came across a couple of interesting articles today:</p>
    </div>
  </body>
</html>

Cảm ơn Ant P về overflow: hiddenmột phần (mặc dù vẫn không hiểu tại sao). Đây là nơi mà vấn đề xuất hiện. Giả sử tôi muốn tiêu đề và nút được căn giữa theo chiều dọc. Đây là vấn đề vì các phần tử có chiều cao khác nhau. So sánh cái này với:

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; overflow: hidden; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-header td { vertical-align: middle; }
      .group-title { padding: 8px; }
      .group-buttons { text-align: right; }
    </style>
  </head>
  <body>
    <table class="group-header">
    <tr>
      <td class="group-title">This is my title</td>
      <td class="group-buttons"><input type="button" value="Collapse"></td>
    </tr>
    </table>
    <div class="group-content">
      <p>And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.</p>
      <p>So can anyone do the equivalent without tables that is backwards compatible to at least FF2 and IE6?</p>
      <p>On a side note, I came across a couple of interesting articles today:</p>
    </div>
  </body>
</html>

hoạt động hoàn hảo.


11
Ok điều đó có ý nghĩa "Tôi nên sử dụng màu gì cho vim?" được ủng hộ, vấn đề bố cục CSS cụ thể của tôi bị phản đối.
cletus


bạn có thể làm bất cứ điều gì bạn muốn mà không cần bàn trong mọi trường hợp. Ngoài ra, tại sao @SamB lại đụng phải câu hỏi 2 tuổi này? DOH +
năng động

3
@ yes123: chà, tô sáng cú pháp sai ...
SamB

Câu trả lời:


50

Không có gì sai khi sử dụng các công cụ có sẵn cho bạn để thực hiện công việc một cách nhanh chóng và chính xác.

Trong trường hợp này, một bảng hoạt động hoàn hảo.

Cá nhân tôi đã sử dụng một cái bàn cho việc này.

Tôi nghĩ nên tránh các bảng lồng nhau, mọi thứ có thể trở nên lộn xộn.


21
Ngoại trừ khi bạn đang sử dụng một bảng cho bố cục trình bày thay vì dữ liệu dạng bảng chỉ vì lúc đầu nó dễ nhợt nhạt hơn, trong trường hợp đó, bạn đang đi xuống một con đường tối và nguy hiểm.
One Crayon

9
Ngay cả Amazon cũng sử dụng bảng trong một số trường hợp nhất định. Và stackoverflow.com cũng vậy. Tôi là tất cả cho các giải pháp css khi chúng thực sự hoạt động tốt.
Nosredna

11
Cả amazon, stackoverflow đều không phải là đỉnh cao của thiết kế web.
Bobby Jack

31
Chúng có thể không phải vậy, nhưng chúng là những giải pháp đang hoạt động phục vụ hàng chục nghìn người dùng.
17 ngày 26

22
Meme chống bàn này chỉ đơn giản là ngu ngốc. Trình quản lý bố cục 2 chiều duy nhất cho laout dựa trên ràng buộc linh hoạt là bảng; và cho dù đó chỉ là một cái phức tạp (với vô số col / rowspans) hay những cái lồng nhau tạo ra rất ít sự khác biệt. Nhưng thực tế và sự thật không phải lúc nào cũng là vũ khí đủ tốt để chống lại sự sốt sắng.
StaxMan

28

Chỉ cần thả nổi trái và phải và đặt để xóa cả hai và bạn đã hoàn tất. Không cần bàn.

Chỉnh sửa: Tôi biết rằng tôi đã nhận được rất nhiều phiếu tán thành cho việc này và tôi tin rằng mình đã đúng. Nhưng có những trường hợp bạn chỉ cần có bảng. Bạn có thể thử làm mọi thứ với CSS và nó sẽ hoạt động trong các trình duyệt hiện đại, nhưng nếu bạn muốn hỗ trợ các trình duyệt cũ hơn ... Không phải nhắc lại bản thân tôi, đây là chủ đề tràn ngăn xếp liên quanrant trên blog của tôi .

Edit2: Kể từ khi trình duyệt cũ không phải là thú vị nữa, tôi đang sử dụng Twitter bootstrap cho các dự án mới. Nó tuyệt vời cho hầu hết các nhu cầu về bố cục và sử dụng CSS.


2
Không xử lý căn giữa theo chiều dọc, vì vậy -1.
SamB

1
Tôi đã gặp sự cố sự cố tương tự trong đó tôi có một biểu trưng ở bên trái và một số menu văn bản ở bên phải. Các menu phải được căn chỉnh trên đường cơ sở của logo. Sử dụng float: right cho các menu không hoạt động. Nó đưa chúng đến góc trên cùng bên phải và chúng không được căn chỉnh theo chiều dọc với đường cơ sở của logo nữa.
Jean-François Beauchamp

1
Tôi nghĩ rằng bạn có thể giải quyết căn giữa theo chiều dọc bằng cách đặt chiều cao dòng của Tiêu đề giống với chiều cao của Nút.
igors

1
@igors, +1, bạn nói đúng. Xin lưu ý rằng câu hỏi này là từ năm 2009.;)
Milan Babuškov

17

Đây là một dạng câu hỏi mẹo: nó trông rất đơn giản cho đến khi bạn

Giả sử tôi muốn tiêu đề và nút được căn giữa theo chiều dọc.

Tôi muốn tuyên bố rằng có, căn giữa theo chiều dọc rất khó trong CSS. Khi mọi người đăng bài và dường như vô tận trên SO, "bạn có thể làm X trong CSS", câu trả lời hầu như luôn luôn là "có" và sự thay đổi của họ dường như không hợp lý. Trong trường hợp này, vâng, một điều cụ thể là khó.

Ai đó chỉ nên chỉnh sửa toàn bộ câu hỏi thành "căn giữa theo chiều dọc có vấn đề trong CSS không?".


11
Đó là vấn đề của tôi với đối số "table haters": CSS có thể làm mọi thứ mà bảng có thể làm ... ngoại trừ một số trường hợp khá đơn giản, phổ biến và hợp lý (như căn giữa theo chiều dọc). CSS giống như một lời hứa bầu cử đã trở nên tồi tệ.
cletus

4
Quan điểm của tôi là căn giữa theo chiều dọc chỉ là điều DUY NHẤT thực sự khó.
AmbroseChapel

3
CSS không dùng để thay thế các bảng; nó chỉ nhằm cho phép bạn giải quyết hầu hết các vấn đề về bố cục phổ biến mà không cần bảng. Nếu một cái bàn hoạt động, hãy sử dụng một cái bàn, giống như bạn dùng bút để vẽ thay vì dùng búa tạ.
Aaron Digulla

16

Tiêu đề nổi bên trái, nút nổi bên phải và (đây là phần mà tôi chưa từng biết cho đến gần đây) - tạo vùng chứa của cả hai {overflow:hidden}.

Điều đó sẽ tránh được vấn đề z-index. Nếu nó không hoạt động và bạn thực sự cần hỗ trợ IE5, hãy tiếp tục và sử dụng bảng.


+1 Whoa, điều gì xảy ra với phần tràn bị ẩn? Nó làm cho một sự khác biệt. Không biết tại sao mặc dù.
cletus

Thành thật mà nói, tôi cũng không hiểu và không thể tìm thấy bất kỳ đề cập nào về nó trong thông số kỹ thuật. Tuy nhiên, ai đó đã nói với tôi đó là cách "đúng đắn", sau khi tôi trả lời một câu hỏi khác gợi ý rằng họ sử dụng một phần tử đã xóa để làm điều đó. Có vẻ đó là ý tưởng hay cho tôi.

Các phần tử nổi vẫn cần được xóa để nội dung theo sau chúng trôi chảy đúng cách. tràn: ẩn; chỉ giải quyết chiều cao của vùng chứa.
Zack The Human

2
"tràn: ẩn" là một cuộc tấn công để đạt được cả hai chiều cao 'mở rộng' và xóa. Các phần tử sau SẼ xóa hộp đó (ít nhất là trong các trình duyệt triển khai chính xác phần đó của thông số kỹ thuật).
Bobby Jack

1
-1 cho không xử lý căn giữa theo chiều dọc, nhưng +2 cho overflow:hidden.
SamB

7

Trong CSS thuần túy, một ngày nào đó câu trả lời có hiệu quả sẽ là chỉ sử dụng "display:table-cell". Thật không may, điều đó không hoạt động trên các trình duyệt hạng A hiện tại, vì vậy, đối với tất cả những điều đó, bạn cũng có thể sử dụng bảng nếu bạn muốn đạt được cùng một kết quả. Ít nhất bạn sẽ chắc chắn rằng nó hoạt động đủ xa trong quá khứ.

Thành thật mà nói, chỉ sử dụng một cái bàn nếu nó dễ dàng hơn. Nó sẽ không đau đâu.

Nếu ngữ nghĩa và khả năng truy cập của phần tử bảng thực sự quan trọng đối với bạn, thì có một bản nháp làm việc để làm cho bảng của bạn không có ngữ nghĩa:

http://www.w3.org/TR/wai-aria/#presentation

Tôi nghĩ rằng điều này yêu cầu một DTD đặc biệt ngoài XHTML 1.1, điều này sẽ chỉ khuấy động toàn bộ cuộc tranh luận text/htmlvs application/xml, vì vậy chúng ta đừng đi đến đó.

Vì vậy, đối với vấn đề CSS chưa được giải quyết của bạn ...

Để căn chỉnh theo chiều dọc hai phần tử ở trung tâm của chúng: có thể được thực hiện theo một số cách khác nhau, với một số phương pháp hack CSS khó hiểu.

Nếu bạn có thể phù hợp với các ràng buộc sau, thì có một cách tương đối đơn giản:

  • Chiều cao của hai phần tử là cố định.
  • Chiều cao của thùng chứa là cố định.
  • Các phần tử sẽ đủ hẹp để không chồng lên nhau (hoặc có thể được đặt thành chiều rộng cố định).

Sau đó, bạn có thể sử dụng định vị tuyệt đối với biên âm:

.group-header { height: 50px; position: relative; }
.group-title, .group-buttons { position: absolute; top: 50%; }
# Assuming the height of .group-title is a known 34px
.group-title { left: 0; margin-top: -17px; }
# Assuming the height of .group-buttons is a known 38px
.group-buttons { right: 0; margin-top: -19px; }

Nhưng điều này là vô nghĩa trong hầu hết các tình huống ... Nếu bạn đã biết chiều cao của các phần tử, thì bạn chỉ cần sử dụng phao và thêm đủ lề để định vị chúng khi cần.

Đây là một phương pháp khác sử dụng đường cơ sở văn bản để căn chỉnh theo chiều dọc hai cột dưới dạng khối nội tuyến. Hạn chế ở đây là bạn cần đặt chiều rộng cố định cho các cột để lấp đầy chiều rộng từ cạnh trái. Bởi vì chúng ta cần giữ các phần tử bị khóa trong đường cơ sở văn bản, chúng ta không thể chỉ sử dụng float: right cho cột thứ hai. (Thay vào đó, chúng ta phải làm cho cột đầu tiên đủ rộng để đẩy nó qua.)

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; }
      .valign { display: inline-block; vertical-align: middle; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-title { padding: 8px; width: 384px; }
      .group-buttons { padding: 8px; width: 84px; text-align: right; }
    </style>
    <!--[if lt IE 8]>
    <style type="text/css">
      .valign { display: inline; margin-top: -2px; padding-top: 1px; }
    </style>
    <![endif]-->
  </head>
  <body>
    <div class="group-header">
      <div class="valign">
        <div class="group-title">This is my title.</div>
      </div><!-- avoid whitespace between these! --><div class="valign">
        <div class="group-buttons"><input type="button" value="Collapse"></div>
      </div>
    </div>
    <div class="group-content">
      <p>And it works perfectly, but mind the hacks.</p>
    </div>
  </body>
</html>

HTML: Chúng tôi thêm các trình bao bọc .valign xung quanh mỗi cột. (Đặt cho chúng một cái tên "ngữ nghĩa" hơn nếu nó làm bạn hạnh phúc hơn.) Những cái này cần được giữ không có khoảng trắng ở giữa nếu không các khoảng trắng văn bản sẽ đẩy chúng ra xa nhau. (Tôi biết điều đó thật tệ, nhưng đó là những gì bạn nhận được vì sự "thuần túy" với đánh dấu và tách nó khỏi lớp trình bày ... Ha!)

CSS: Chúng tôi sử dụng vertical-align:middleđể xếp các khối vào đường cơ sở văn bản của phần tử tiêu đề nhóm. Các chiều cao khác nhau của mỗi khối sẽ được căn giữa theo chiều dọc và đẩy ra chiều cao của thùng chứa của chúng. Chiều rộng của các phần tử cần được tính toán để phù hợp với chiều rộng. Ở đây, chúng là 400 và 100, trừ đi phần đệm ngang của chúng.

IE sửa lỗi: Internet Explorer chỉ hiển thị khối nội tuyến cho các phần tử nội tuyến nguyên bản (ví dụ: span, không phải div). Nhưng, nếu chúng ta cung cấp cho div hasLayout và sau đó hiển thị nó trong dòng, nó sẽ hoạt động giống như inline-block. Điều chỉnh lề là để sửa một khoảng trống 1px ở trên cùng (hãy thử thêm màu nền vào .group-title để xem).


1
Hmm màn hình hiển thị: thẻ table-X dường như có mục đích để bố trí bằng cách sử dụng bảng, chỉ mà không sử dụng thẻ bảng?
Danubian Sailor

3

Tôi khuyên bạn không nên sử dụng bảng trong trường hợp này, vì đó không phải là dữ liệu dạng bảng; nó hoàn toàn là thuyết trình để có nút nằm ở ngoài cùng bên phải. Đây là những gì tôi sẽ làm để sao chép cấu trúc bảng của bạn (thay đổi thành một H # khác để phù hợp với vị trí của bạn trong hệ thống phân cấp trang web của bạn):

<style>
  .group-header { background: yellow; zoom: 1; padding: 8px; }
  .group-header:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
  /* set width appropriately to allow room for button */
  .group-header h3 { float: left; width: 300px; }
  /* set line-height or margins to align with h3 baseline or middle */
  .group-header input { float: right; }
</style>

<div class="group-header">
  <h3>This is my title</h3>
  <input type="button" value="Collapse"/>
</div>

Nếu bạn muốn căn chỉnh dọc thực sự ở giữa (tức là nếu văn bản bao quanh nút vẫn được căn giữa đối với cả hai dòng văn bản), thì bạn cần phải thực hiện một bảng hoặc làm việc gì đó với position: absolutevà lề. Bạn có thể thêm position: relativevào menu thả xuống của mình (hoặc nhiều khả năng là cha của nó) để kéo nó vào cùng cấp độ sắp xếp với các nút, cho phép bạn đẩy nó lên trên chúng bằng chỉ mục z, nếu nói đến điều đó.

Lưu ý rằng bạn không cần width: 100%div vì nó là một phần tử cấp khối và zoom: 1làm cho div hoạt động giống như nó có một clearfix trong IE (các trình duyệt khác chọn clearfix thực tế). Bạn cũng không cần tất cả các lớp không liên quan đó nếu bạn đang nhắm mục tiêu những thứ cụ thể hơn một chút, mặc dù bạn có thể cần một div bao bọc hoặc khoảng trên nút để giúp định vị dễ dàng hơn.


Giải pháp của bạn không hoạt động trên IE6 mặc dù do: sau lớp giả.
Sebastian Hoitz, 09/02/09

1
Nó hoạt động trong IE 6, nhờ vào bên zoom: 1trong .group-header, kích hoạt hasLayout và khiến IE 6 hoạt động giống như khi nó có phần tử: after đang hoạt động.
One Crayon

2

Thực hiện float kép trong một div và sử dụng tiền tố rõ ràng. http://www.webtoolkit.info/css-clearfix.html Bạn có bất kỳ hạn chế về padding / margin nào không?

<div class="clearfix">
   <div style="float:left">Title</div>
   <input type="button" value="Button" style="float:right" />
</div>

Tôi có yêu cầu căn giữa theo chiều dọc (và thêm một chút đệm). Tôi nghĩ rằng tôi đã làm rõ điều đó sau khi bạn đăng.
cletus

2
<div class="group-header">
    <input type="button" name="Button" value="Button" style="float:right" />
    <span>Title</span>
</div>

1

Tôi đã chọn sử dụng Flexbox, vì nó giúp mọi thứ dễ dàng hơn rất nhiều.

Về cơ bản, bạn cần phải chuyển đến cha mẹ của những đứa trẻ mà bạn muốn căn chỉnh và thêm display:box(tất nhiên là có tiền tố). Để khiến họ ngồi ở hai bên, hãy sử dụng justify-content . Khoảng cách giữa là điều đúng đắn khi bạn có các phần tử cần được căn chỉnh đến cuối cùng, như trong trường hợp này (xem liên kết) ...

Sau đó là vấn đề căn chỉnh dọc. Vì tôi đã tạo thành phần gốc của hai phần tử, bạn muốn căn chỉnh một Flexbox. Bây giờ thật dễ dàng để sử dụng align-items: center.

Sau đó, tôi đã thêm các kiểu bạn muốn trước đó, xóa dấu nổi khỏi tiêu đề và nút trong tiêu đề và thêm một phần đệm:

.group-header, .group-content {
    width: 500px;
    margin: 0 auto;
}
.group-header{
    border: 1px solid red;
    background: yellow;
    overflow: hidden;
    display: -webkit-box;
    display: -moz-box;
    display: box;
    display: -webkit-flex;
    display: -moz-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-justify-content: space-between;
    -moz-justify-content: space-between;
    -ms-justify-content: space-between;
    -o-justify-content: space-between;
    justify-content: space-between;
    webkit-align-items: center;
    -moz-align-items: center;
    -ms-align-items: center;
    -o-align-items: center;
    align-items: center;
    padding: 8px 0;
}
.group-content{
    border: 1px solid black;
    background: #DDD;
}
.group-title {
    padding-left: 8px;
}
.group-buttons {
    padding-right: 8px
}

Xem Demo


1

Tôi đồng ý rằng người ta thực sự chỉ nên sử dụng các bảng cho dữ liệu dạng bảng, vì lý do đơn giản là các bảng không hiển thị cho đến khi chúng tải xong (bất kể tốc độ đó nhanh đến mức nào; phương pháp CSS sẽ chậm hơn). Tuy nhiên, tôi cảm thấy rằng đây là giải pháp đơn giản và thanh lịch nhất:

<html>
    <head>
        <title>stack header</title>
        <style type="text/css">
            #stackheader {
                background-color: #666;
                color: #FFF;
                width: 410px;
                height: 50px;
            }
            #title {
                color: #FFF;
                float: left;
                padding: 15px 0 0 15px;
            }
            #button {
                color: #FFF;
                float: right;
                padding: 15px 15px 0 0;
            }
        </style>
    </head>

    <body>
        <div id="stackheader">
        <div id="title">Title</div>
        <div id="button">Button</div>
        </div>
    </body>
</html>

Chức năng nút và bất kỳ chi tiết bổ sung nào có thể được tạo kiểu từ biểu mẫu cơ bản này. Xin lỗi vì các thẻ xấu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.