Можете ли вы сделать этот макет HTML без использования таблиц?

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

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

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

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

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

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

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

<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 ответов

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Я думаю, что для этого требуется специальный 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, чтобы увидеть).

Я бы порекомендовал не использовать таблицу в этом случае, потому что это не табличные данные; это просто презентация, чтобы кнопка находилась в крайнем правом положении. Вот что я хотел бы сделать, чтобы продублировать структуру вашей таблицы (перейдите на другой 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 вести себя так, как будто у него есть clearfix в IE (другие браузеры выбирают фактическое clearfix). Вам также не понадобятся все эти посторонние классы, если вы нацеливаетесь на вещи более конкретно, хотя вам может понадобиться обертка div или span для кнопки, чтобы упростить позиционирование.

Сделайте двойной 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>
<div class="group-header">
    <input type="button" name="Button" value="Button" style="float:right" />
    <span>Title</span>
</div>

Я решил использовать гибкую коробку, потому что она сделала все намного проще.
В основном вам нужно перейти к родителю дочерних элементов, которые вы хотите выровнять, и добавить 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
    }

Посмотреть демо

Я согласен, что на самом деле следует использовать таблицы только для табличных данных, по той простой причине, что таблицы не отображаются, пока они не закончили загрузку (независимо от того, насколько быстро это происходит, медленнее, чем метод 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>

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

Другие вопросы по тегам