Можете ли вы сделать этот макет HTML без использования таблиц? - PullRequest
99 голосов
/ 07 февраля 2009

Хорошо, у меня была простая проблема макета неделю или две назад. А именно разделам страницы нужен заголовок:

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

Довольно простые вещи. Дело в том, что ненависть к таблицам, похоже, перешла в мир Интернета, о чем мне напомнили, когда я спросил Зачем использовать теги списков определений (DL, DD, DT) для форм HTML вместо таблиц? Теперь общее тема таблиц против divs / CSS ранее обсуждалась, например:

Так что это не предназначено для общего обсуждения CSS и таблиц для разметки. Это просто решение одной проблемы. Я пробовал различные решения с использованием CSS, в том числе:

  • Float вправо для кнопки или div, содержащего кнопку;
  • Положение относительно кнопки; и
  • Положение относительное + абсолютное.

Ни одно из этих решений не было удовлетворительным по разным причинам. Например, относительное расположение привело к проблеме с z-индексом, когда мое раскрывающееся меню появилось под содержимым.

Итак, я вернулся к:

<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>

И это прекрасно работает. Это просто, с обратной совместимостью (это будет работать, вероятно, даже на IE5), и это просто работает. Никаких проблем с позиционированием или плаванием.

Так может ли кто-нибудь сделать эквивалент без таблиц?

Требования:

  • Обратная совместимость: с FF2 и IE6;
  • Разумно согласовано: в разных браузерах;
  • Вертикально по центру: кнопка и заголовок имеют разную высоту; и
  • Гибкость: позволяет достаточно точно контролировать позиционирование (отступы и / или поля) и стиль.

Кстати, сегодня я наткнулся на пару интересных статей:

РЕДАКТИРОВАТЬ: Позвольте мне подробнее остановиться на проблеме с плавающей точкой. Такого рода работы:

<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>

Спасибо Ant P за часть overflow: hidden (все же, не знаю почему). Вот в чем проблема. Скажем, я хочу, чтобы заголовок и кнопка располагались вертикально по центру. Это проблематично, потому что элементы имеют разную высоту. Сравните это с:

<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>

, который отлично работает.

Ответы [ 10 ]

49 голосов
/ 07 февраля 2009

Нет ничего плохого в том, чтобы использовать инструменты, доступные вам, чтобы выполнять работу быстро и правильно.

В этом случае таблица работала отлично.

Я бы лично использовал для этого таблицу.

Я думаю, что вложенных таблиц следует избегать, все может запутаться.

27 голосов
/ 07 февраля 2009

Просто плавайте влево и вправо и установите, чтобы очистить оба, и все готово. Нет необходимости в таблицах.

Редактировать: Я знаю, что получил много голосов за это, и я верил, что был прав. Но есть случаи, когда вам просто нужно иметь таблицы. Вы можете попробовать сделать все с помощью CSS, и это будет работать в современных браузерах, но если вы хотите поддерживать более старые ... Не повторюсь, здесь связанный поток переполнения стека и rant на моем блог .

Edit2: Поскольку старые браузеры уже не так интересны, я использую загрузчик Twitter для новых проектов. Он отлично подходит для большинства задач макета и использует CSS.

17 голосов
/ 07 февраля 2009

Это вопрос с подвохом: он выглядит ужасно простым, пока вы не доберетесь до

Скажем, я хочу, чтобы заголовок и кнопка располагались вертикально по центру.

Я хочу заявить, что да, вертикальное центрирование сложно в CSS. Когда люди пишут, и это кажется бесконечным на SO, «можете ли вы сделать X в CSS», ответ почти всегда «да», и их порыв кажется необоснованным. В этом случае, да, эта конкретная вещь трудна.

Кто-то должен просто отредактировать весь вопрос так: «Неужели вертикальное центрирование проблематично в CSS?».

16 голосов
/ 07 февраля 2009

Название с плавающей точкой слева, кнопка с плавающей точкой справа и (вот та часть, которую я никогда не знал до недавнего времени) - сделайте контейнер из них обоих {overflow:hidden}.

В любом случае, это должно избежать проблемы z-index. Если это не работает, и вам действительно нужна поддержка IE5, продолжайте и используйте таблицу.

7 голосов
/ 09 февраля 2009

В чистом CSS рабочим ответом однажды будет просто использовать "display:table-cell". К сожалению, это не работает в современных браузерах А-класса, так что для всего этого вы могли бы также использовать таблицу, если вы все равно хотите добиться того же результата. По крайней мере, вы будете уверены, что это работает достаточно далеко в прошлом.

Честно говоря, просто используйте стол, если это проще. Это не повредит.

Если семантика и доступность элемента таблицы действительно имеют для вас значение, существует рабочий черновик для того, чтобы сделать вашу таблицу несемантической:

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

Я думаю, что для этого требуется специальный DTD помимо XHTML 1.1, который бы просто вызвал все споры text/html против application/xml, поэтому давайте не будем идти туда.

Итак, к вашей нерешенной проблеме CSS ...

Вертикально выровнять два элемента по их центру: это можно сделать несколькими различными способами, с помощью некоторой тупой хакерской CSS.

Если вы можете вписаться в следующие ограничения, то есть относительно простой способ:

  • Высота двух элементов фиксирована.
  • Фиксированная высота контейнера.
  • Элементы будут достаточно узкими, чтобы не перекрываться (или могут быть установлены на фиксированную ширину).

Тогда вы можете использовать абсолютное позиционирование с отрицательными полями:

.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; }

Но в большинстве ситуаций это бессмысленно ... Если вы уже знаете высоту элементов, то вы можете просто использовать поплавки и добавить достаточное поле для их размещения.

Вот еще один метод, использующий текстовую базовую линию для вертикального выравнивания двух столбцов в виде встроенных блоков. Недостатком здесь является то, что вам нужно установить фиксированную ширину для столбцов, чтобы заполнить ширину от левого края. Поскольку нам нужно сохранить элементы привязанными к базовой строке текста, мы не можем просто использовать float: right для второго столбца. (Вместо этого мы должны сделать первый столбец достаточно широким, чтобы перевернуть его.)

<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: Мы добавляем обертки .valign вокруг каждого столбца. (Дайте им более «семантическое» имя, если это сделает вас счастливее.) Их нужно хранить без пробелов между ними, иначе текстовые пробелы будут их раздвигать. (Я знаю, что это отстой, но это то, что вы получаете за то, что вы «чисты» с разметкой и отделяете ее от слоя представления ... Ха!)

CSS: Мы используем vertical-align:middle, чтобы выровнять блоки по текстовой базовой линии элемента заголовка группы. Различные высоты каждого блока будут оставаться вертикально центрированными и выталкивать высоту их контейнера. Ширина элементов должна быть рассчитана, чтобы соответствовать ширине. Здесь их 400 и 100 минус горизонтальное заполнение.

В IE исправлено: Internet Explorer отображает только встроенный блок для встроенных элементов (например, span, а не div). Но если мы передадим div hasLayout, а затем отобразим его как встроенный, он будет вести себя как встроенный блок. Корректировка поля должна исправить зазор в 1 пиксель сверху (попробуйте добавить цвета фона в заголовок .group, чтобы увидеть).

3 голосов
/ 07 февраля 2009

Я бы рекомендовал не использовать таблицу в этом случае, потому что это не табличные данные; Это просто презентация, чтобы кнопка находилась в крайнем правом положении. Вот что я бы сделал, чтобы продублировать структуру вашей таблицы (измените на H # в соответствии с тем, где вы находитесь в иерархии вашего сайта):

<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>

Если вы хотите истинное вертикальное выравнивание по центру (т. Е. Если текст оборачивает кнопку по-прежнему по центру относительно обеих строк текста), то вам нужно либо составить таблицу, либо что-то поработать с position: absolute и поля. Вы можете добавить position: relative в раскрывающееся меню (или, скорее, его родителя), чтобы перетащить его на тот же уровень упорядочения, что и кнопки, что позволит вам поднять его над ними с помощью z-index, если это произойдет .

Обратите внимание, что вам не нужно width: 100% в div, потому что это элемент уровня блока, а zoom: 1 заставляет div вести себя так, как будто в IE есть исправление (другие браузеры выбирают фактическое исправление). Вам также не понадобятся все эти посторонние классы, если вы нацеливаетесь на вещи более конкретно, хотя вам может понадобиться div или span для оболочки, чтобы упростить позиционирование.

2 голосов
/ 07 февраля 2009
<div class="group-header">
    <input type="button" name="Button" value="Button" style="float:right" />
    <span>Title</span>
</div>
2 голосов
/ 07 февраля 2009

Сделайте двойной float в div и используйте clearfix. http://www.webtoolkit.info/css-clearfix.html Есть ли у вас какие-либо ограничения на отступы / поля?

<div class="clearfix">
   <div style="float:left">Title</div>
   <input type="button" value="Button" style="float:right" />
</div>
1 голос
/ 11 октября 2014

Я решил использовать гибкую коробку, потому что она намного упростила ситуацию.
В основном вам нужно перейти к родителю дочерних элементов, которые вы хотите выровнять, и добавить display: box (с префиксом, конечно). чтобы заставить их сидеть по сторонам, используйте justify-content . пробел между ними является правильным, когда у вас есть элементы, которые нужно выровнять до конца, как в этом случае (см. ссылку) ...
тогда вопрос выравнивания. Поскольку я создал родительский элемент для двух элементов, которые вы хотите выровнять по гибкому блоку, теперь легко использовать align-items: center. затем я добавил нужные вам стили, удалил плавающий элемент из заголовка и кнопки в заголовке и добавил отступ.

   .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
    }

См. Демонстрацию

1 голос
/ 24 октября 2010

Я согласен, что на самом деле следует использовать таблицы только для табличных данных, по той простой причине, что таблицы не отображаются, пока они не закончили загрузку (независимо от того, насколько быстро это происходит, медленнее, чем метод CSS). Однако я чувствую, что это самое простое и элегантное решение:

<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>

Функция кнопки и любая дополнительная деталь могут быть стилизованы из этой базовой формы. Извиняюсь за плохие теги.

...