it-swarm.com.ru

Объединение таблицы и иерархического списка в HTML

Я работаю над редизайном устаревшего набора инструментов и смотрю, как лучше отобразить некоторую информацию как в презентационном, так и в семантическом виде.

Данные иерархически по своей природе, но имеют свойства, которые должны быть легко видны пользователям. Желаемый макет похож на ниже.

Seq     Item Name         Min  Max  - Anything under here isn't shown
 1      Identifier         1    1     (Required)
 2      Name               1    1
  2.1    First Name        1    1
  2.2    Middle Name       -    -     (Optional but unlimted)
  2.3    Last Name         1    1
 3      Age                -    1     (Optional)

На данный момент это целая таблица, и отступ для номера Sequence (Seq) достигается путем вставки дополнительных ячеек таблицы, чтобы как бы поднять все вправо.

Задача, которую я имею, состоит в том, чтобы выяснить, как эффективно отображать эту информацию.

Прежде всего это табличные данные? Я бы сказал нет, так как иерархия важна, а «столбцы» - это просто атрибуты элемента в каждой «строке».

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

Если это таблица, каков наилучший способ представить семантическое существование иерархии в таблице?

19
user764357

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

К сожалению, в HTML нет вложенного механизма группировки строк таблицы: tbody можно использовать для группировки строк, но вложение это недопустимо (за исключением промежуточного table внутри td, что довольно ужасно).

Это оставляет вам два варианта:

  1. Представлять информацию с помощью вложенных списков какого-либо рода и полагаться на CSS, чтобы результат выглядел как таблица.

  2. Представлять информацию в виде таблицы и полагаться на какие-либо атрибуты для представления ее иерархических отношений.

Вот несколько примеров того, как вы могли бы реализовать этот выбор:

Использование вложенных списков (наивный подход):

<ul>
  <li>
    <dl>
      <dt>Seq</dt> <dd>1</dd>
      <dt>Item Name</dt> <dd>Identifier</dd>
      <dt>Min</dt> <dd>1</dd>
      <dt>Max</dt> <dd>1</dd>
    </dl>
  </li>
  <li>
    <dl>
      <dt>Seq</dt> <dd>2</dd>
      <dt>Item Name</dt> <dd>Name</dd>
      <dt>Min</dt> <dd>1</dd>
      <dt>Max</dt> <dd>1</dd>
    </dl>
    <ul>
      <li>
        <dl>
          <dt>Seq</dt> <dd>2.1</dd>
          <dt>Item Name</dt> <dd>First Name</dd>
          <dt>Min</dt> <dd>1</dd>
          <dt>Max</dt> <dd>1</dd>
        </dl>
      </li>
      <li>
        <dl>
          <dt>Seq</dt> <dd>2.2</dd>
          <dt>Item Name</dt> <dd>Middle Name</dd>
          <dt>Min</dt> <dd>-</dd>
          <dt>Max</dt> <dd>-</dd>
        </dl>
      </li>
      <li>
        <dl>
          <dt>Seq</dt> <dd>2.3</dd>
          <dt>Item Name</dt> <dd>Last Name</dd>
          <dt>Min</dt> <dd>1</dd>
          <dt>Max</dt> <dd>1</dd>
        </dl>
      </li>
    </ul>
  </li>
  <li>
    <dl>
      <dt>Seq</dt> <dd>3</dd>
      <dt>Item Name</dt> <dd>Age</dd>
      <dt>Min</dt> <dd>-</dd>
      <dt>Max</dt> <dd>1</dd>
    </dl>
  </li>
<ul>

Это обрабатывает иерархический аспект информации, но в итоге вы многократно повторяете себя, и вам придется перепрыгивать через некоторые циклы в CSS, чтобы отобразить результат в табличной форме. Это, вероятно, выполнимо при разумном использовании :first-child, но конечный результат состоит в том, что вы старались изо всех сил пометить что-то, что вы хотите представить в виде таблицы не в табличной форме, и в результате дали себе больше работы потянув его обратно в форму.

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

Использование вложенных списков («умный» подход):

<dl>
  <dt>
    <ul> <li>Seq</li> <li>Item Name</li> <li>Min</li> <li>Max</li> </ul>
  </dt>
  <dd>
    <ul> <li>1</li> <li>Identifier</li> <li>1</li> <li>1</li> </ul>
  </dd>
  <dd>
    <dl>
      <dt>
        <ul> <li>2</li> <li>Name</li> <li>1</li> <li>1</li> </ul>
      </dt>
      <dd>
        <ul> <li>2.1</li> <li>First Name</li> <li>1</li> <li>1</li> </ul>
      </dd>
      <dd>
        <ul> <li>2.2</li> <li>Middle Name</li> <li>-</li> <li>-</li> </ul>
      </dd>
      <dd>
        <ul> <li>2.3</li> <li>Last Name</li> <li>1</li> <li>1</li> </ul>
      </dd>
    </dl>
  </dd>
  <dd>
    <ul> <li>3</li> <li>Age</li> <li>-</li> <li>1</li> </ul>
  </dd>
</dl>

Здесь мы используем описательные списки для описания двух вещей:

  1. Отношение заголовок/подробность, например, между «Имя элемента» и «Идентификатор» и т.д.

  2. Родительско-дочерние отношения, например, между блок «Имя» и блок «Имя».

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

Использование table:

<table>
  <thead>
    <tr>
      <th>Seq</th> <th>Item Name</th> <th>Min</th> <th>Max</th>
    </tr>
  </thead>
  <tbody>
    <tr id=100>
      <td>1</th> <th>Identifier</th> <td>1</td> <td>1</td>
    </tr>
    <tr id=200>
      <th>2</th> <th>Name</th> <td>1</td> <td>1</td>
    </tr>
    <tr id=210 data-parent=200 class=level-1>
      <th>2.1</th> <th>First Name</th> <td>1</td> <td>1</td>
    </tr>
    <tr id=220 data-parent=200 class=level-1>
      <th>2.2</th> <th>Middle Name</th> <td>-</td> <td>-</td>
    </tr>
    <tr id=230 data-parent=200 class=level-1>
      <th>2.3</th> <th>Last Name</th> <td>1</td> <td>1</td>
    </tr>
    <tr id=300>
      <th>3</th> <th>Age</th> <td>-</td> <td>1</td>
    </tr>
  </tbody>
</table>

Здесь родительские/дочерние отношения явно описываются атрибутом data-parent (который может быть доступен через javascript при необходимости), а атрибут class=level-{n} обеспечивает ловушку, которая может использоваться CSS:

.level-1 > th {
  padding-left: 1em;
}

В конечном счете, это вопрос личных предпочтений и удобства, но я думаю, что подход <table> лучше, потому что он удовлетворяет «выглядит ли это разумно без CSS?» Эмпирическое правило намного лучше, чем любой из вышеперечисленных подходов.

20
Zero Piraeus

Я хотел бы представить его с помощью таблицы и путем добавления пользовательских атрибутов данных к тегам td:

<table id="myTable" class="table">
    <tr>
        <td data-indent="0">1</td>
        <td data-indent="0">Test</td>
        <td data-indent="0">Test 1</td>
    </tr>
    <tr>
        <td data-indent="1">1.1</td>
        <td data-indent="1">Another</td>
        <td data-indent="0">Test 1.1</td>
    </tr>
    <tr>
        <td data-indent="2">1.1.1</td>
        <td data-indent="3">Another</td>
        <td data-indent="0">Test 1.1.1</td>
    </tr>
        <tr>
        <td data-indent="2">1.1.2</td>
        <td data-indent="3">Another one</td>
        <td data-indent="0">Another test 1.1.2</td>
    </tr>
    <tr>
        <td data-indent="0">2</td>
        <td data-indent="0">Test</td>
        <td data-indent="0">Test 2</td>
    </tr>
</table>

Затем с помощью jQuery установите заполнение каждого значения ячейки в вашей таблице:

$("td")
    .css("padding-left", function (index) {
    return 10 * parseInt($(this).data("indent")) + "px";
});

Посмотрите, как это работает на jsFiddle .

7
Alex Filipovici

Я думаю, что есть два разумных способа, как представить это в HTML:

  • используйте table и сделайте связь/иерархию явными с естественным языком
  • используйте элементы секционирования (соответственно заголовки, если вы используете HTML 4.01)

table с колонкой, объясняющей иерархию

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

В вашем случае вы можете добавить столбец, который объясняет отношения строк, которые являются «подпунктами»:

<table>

  <tr>
    <th>Seq</th> 
    <th>Relation</th> <!-- or some clever better label -->
    <th>Item Name</th>
    <th>Min</th>
    <th>Max</th>
  </tr>

  <!-- … -->

  <tr id="2">
    <td>2</td>
    <td></td> <!-- "parent", "root", "container", empty -- whatever makes sense for your case -->
    <td>Name</td>
    <td>1</td>
    <td>1</td>
  </tr>

  <tr id="2.1">
    <td>2.1</td>
    <td>child of <a href="#2">Name</a></td>
    <td>First Name</td>
    <td>1</td>
    <td>1</td>
  </tr>

</table>

Каждая строка может получить id (со значением Seq или Item Name), так что эта строка может быть связана {обратите внимание, что значения id, начинающиеся с цифры, не разрешены в HTML 4.01; вы можете использовать что-то вроде id="seq-2.1" там}. Если элемент является дочерним по отношению к другому элементу, вы можете указать ссылку на строку родительского элемента. 

Таким образом, вы проясните для людей, и машины все еще видят, что эти строки связаны, хотя конкретная семантика этого отношения не читается машиной. Вы можете использовать тип ссылки (rel value) здесь, если вы хотите ясно понять значение отношения. В HTML 4.01 вы можете создать значение самостоятельно, в HTML5 оно должно быть зарегистрировано первым.

элементы секционирования/заголовки

Вместо использования table вы можете использовать контуры HTML. {В следующем примере используются элементы секционирования HTML5 . Если вы используете HTML 4.01, просто замените элементы секционирования на div (или вообще без элемента) и используйте только заголовки.}

Каждый раздел (введенный заголовком) представляет элемент. Схема заголовков (соответственно вложенность элементов секционирования) представляет иерархию ваших элементов.

Вот пример, чтобы увидеть всю структуру:

 <article>

   <h1><!-- heading for the whole data --></h1>

   <section class="item" id="1">
     <h2>Identifier</h2>
   </section>

   <section class="item" id="2">
     <h2>Name</h2>

     <section class="item" id="2.1">
       <h3>First Name</h3>
     </section>

     <section class="item" id="2.2">
       <h3>Middle Name</h3>
     </section>

     <section class="item" id="2.3">
       <h3>Last Name</h3>
     </section>

   </section>

   <section class="item" id="3">
     <h2>Age</h2>
   </section>

 </article>

Каждая section может содержать dl для свойств:

<section class="item" id="3">
  <h2>Age</h2>

  <dl>
    <dt>Min</dt>
    <dd>1</dd>
    <dt>Max</dt>
    <dd>1</dd>
  </dl>

</section>

В зависимости от фактического значения вашего контента, вы можете использовать элемент code для имен элементов (например, если он описывает элементы языка разметки) и/или элемент dfn , если следующее содержание является определением этого элемента.

3
unor

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

Например, список описания для первой строки может выглядеть примерно так:

<dl>
  <dt>Item Name</dt>
  <dd>Identifier</dd>
  <dt>Min</dt>
  <dd>1</dd>
  <dt>Max</dt>
  <dd>1</dd>
  <dt>Notes</dt>
  <dd>(Required)</dd>
</dl>

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

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

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

CodePen Link

2
James Holderness

UPDATE: я добавил использование идентификаторов и атрибута «headers» для семантической разметки иерархии.

Это окончательно табличные данные (вы должны толкнуть определение «список», чтобы оправдать использование UL или DL здесь!).

Я думаю, что хорошим подходом было бы использование разных tbodys для группировки этих связанных строк (что-то вроде этого он использовал здесь http://www.w3.org/TR/2012/WD-html5-20120329/the-table-element .html # the-table-element see "таблица, используемая для разметки головоломки Судоку")

<table>
  <thead>
    <tr>
      <th id="seq">Seq</th>
      <th>Item Name</th>
      <th>Min</th>
      <th>Max</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th id="s1" headers="seq">1</th>
      <td>Identifier</td>
      <td>1</td>
      <td>1</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <th id="s2" headers="seq">2</th>
      <td>Name</td>
      <td>1</td>
      <td>1</td>
    </tr>
    <tr class="sub">
      <th id="s2_1" headers="seq s2">2.1</th>
      <td>First Name</td>
      <td>1</td>
      <td>1</td>
    </tr>
    <tr class="sub">
      <th id="s2_2" headers="seq s2">2.2</th>
      <td>Middle Name</td>
      <td>-</td>
      <td>-</td>
    </tr>
    <tr class="sub">
      <th id="s2_3" headers="seq s2">2.3</th>
      <td>Last Name</td>
      <td>1</td>
      <td>1</td>
    </tr>
    <tr class="sub sub">
      <th id="s2_3_1" headers="seq s2 s2_3">2.3.1</th>
      <td>Last Name</td>
      <td>1</td>
      <td>1</td>
    </tr>
    <tr class="sub sub">
      <th id="s2_3_2" headers="seq s2 s2_3">2.3.2</th>
      <td>Last Name</td>
      <td>1</td>
      <td>1</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <th id="s3" headers="seq">3</th>
      <td>Age</td>
      <td>-</td>
      <td>1</td>
    </tr>
  </tbody>
</table>

Тогда вы можете использовать что-то вроде этого:

table { border-collapse: collapse; }
tbody { border-bottom:1px solid #000; }
tbody .sub td { padding-left: 10px; }

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

<tr>
  <td>1</td>
  <td>Identifier</td>
  <td>1</td>
  <td>1</td>
</tr>
<tbody>
  <tr>
    <td>2</td>
    <td>Name</td>
    <td>1</td>
    <td>1</td>
  </tr>
  <tr class="sub">
    <td>2.1</td>
    <td>First Name</td>
    <td>1</td>
    <td>1</td>
  </tr>
  ...
</tbody>
<tr>
  <td>3</td>
  <td>Age</td>
  <td>-</td>
  <td>1</td>
</tr>
2
Coluccini

Я думаю, что вы должны использовать стол. Правда, иерархия важнее, но ее также можно отобразить, записав вручную первый столбец. Но атрибуты min, max и имя элемента не могут быть отображены в списке так же легко, как в таблице. Мое мнение: используйте таблицу и предоставьте колонку seq вручную!

2
Lars Ebert

Почему не оба? Сетка дерева - это хороший способ представления табличных данных, которые также соответствуют иерархии.

Это один из таких примеров .

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

Имейте в виду, что вы всегда должны задавать себе вопрос: «На какие вопросы пытаются ответить мои пользователи?» Затем спросите себя: «Какие графические устройства дают самый ясный и простой способ ответить на этот вопрос?»

Одной книгой, которая действительно помогла мне с этими вопросами, была книга по дизайну приборной панели . Несмотря на то, что вы, возможно, не строите панель мониторинга, у нее есть много методов и теорий UX, которые упростили мне выбор подходящего элемента UI (относительно данных).

Надеюсь, это поможет...

0
Homer6