在HTML中组合表和分层列表

时间:2013-07-17 06:10:25

标签: html css html-table wcag wcag2.0

我正在努力重新设计一个遗留工具集,我正在研究如何更好地在表现和语义上显示一些信息。

数据本质上是分层次的,但具有需要用户容易看到的属性。所需的布局类似于下面。

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)

目前这是一个完整的表格,并且序列(Seq)数字的交叉数量是通过插入额外的表格单元格来实现的,以便将所有内容碰到右边。

我所面临的挑战是如何有效地显示这些信息。

首先是这个表格数据?我会说不,因为层次结构很重要,而'列'只是每个'行'中项目的属性。

如果它不是表格,它是什么以及如何做?我个人认为这是一组嵌套的UL列表 - 序列号是可选的,并不总是一个数字。如果它是一组列表,那将正确缩进子列表,但是呈现短属性的最佳方式是什么?

如果是表格,那么在表格中显示层次结构的语义存在的最佳方法是什么?

7 个答案:

答案 0 :(得分:21)

这里的挑战是,您要表示的信息在一个方面是表格式的(它是一组具有相同标记属性的项目),而在另一个层次结构中(项目具有父项)。

不幸的是,HTML中的表行没有嵌套分组机制:tbody可用于对行进行分组,但嵌套它是非法的(除了table中的中间td ,这太可怕了。)

这给你两个选择:

  1. 使用某种嵌套列表表示信息,并依靠CSS使结果看起来像一个表。

  2. 将信息表示为一个表,并依赖某种属性来表示其层次关系。

  3. 以下是一些如何实施这些选择的示例:

    使用嵌套列表(天真的方法):

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

    在这里,我们使用description lists来描述两件事:

    1. 例如,标题/细节关系'项目名称'和'标识符'等。

    2. 例如,父/子关系“姓名”单位和“名字”单位。

    3. 它肯定更紧凑,但不幸的是,每个标题及其细节元素之间的特定关系充其量是隐含的,并且没有额外的样式以表格方式可视地组织信息,当渲染实际的内容时,它将更不明显被代表。

      使用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它看起来合理吗?”经验法则比上面任何一种嵌套列表方法都好得多。

答案 1 :(得分:7)

我会使用表格并将custom data attributes添加到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上查看它。

答案 2 :(得分:3)

我认为有两种明智的方法可以用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),以便可以链接此行{请注意,HTML 4.01中不允许以数字开头的id值;你可以使用像id="seq-2.1"这样的东西。如果某个项目是另一个项目的子项,则可以链接到该项目的行。

通过这种方式,您可以清楚地了解人类,并且机器仍然会看到这些行已连接,尽管此关系的特定语义不是机器可读的。如果要明确说明关系的含义,可以在此处使用链接类型(rel值)。在HTML 4.01中,您可以自己创建一个值,在HTML5中首先需要registered

切片元素/标题

您可以使用HTML的大纲,而不是使用table。 {以下示例使用HTML5’s sectioning elements。如果您使用的是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 element作为项目名称(例如,如果它描述了标记语言的元素)和/或dfn element,如果以下内容是该项目的定义。

答案 3 :(得分:2)

我认为你应该使用一张桌子。确实,层次结构更重要,但也可以通过手动写下第一列来显示。但是,属性min,max和item name无法像列表一样轻松地显示在列表中。我的意见是:使用表并手动提供seq列!

答案 4 :(得分:2)

我的建议是使用嵌套的有序列表来保留层次结构,然后使用描述列表来表示每行的“列”。

例如,第一行的描述列表可能如下所示:

<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

答案 5 :(得分:2)

更新:我已经添加了ID和“headers”属性的使用,以某种方式在语义上标记了层次结构。

这是明确的表格数据(你应该真正推动“列表”的定义,以证明在这里使用UL或DL!)。

我认为一个好的方法是使用不同的tbodys将这些相关的行组合在一起(这里使用的类似http://www.w3.org/TR/2012/WD-html5-20120329/the-table-element.html#the-table-element请参阅“用于标记数独谜题的表格”)

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

答案 6 :(得分:0)

为什么不两者兼而有之?树网格是表示也符合层次结构的表格数据的好方法。

这是one such example

然而,在两个非常大的项目中使用Extjs,我个人的建议是,如果你要生产一个大型应用程序,请远离它。虽然对于一次性网格可能没什么问题,但我个人发现它实施得很差,随着项目规模的增加会变得更加繁琐。但是,它功能非常丰富,因此examples panel可能会为您提供更多可能对您有帮助的网格(表格)。

请记住,您应该总是问自己,“我的用户试图回答哪些问题?”然后,问问自己,“哪些图形设备提供了回答这个问题的最清晰,最简单的途径?”

一本真正帮助我解决这些问题的书是the dashboard design book。即使您可能没有构建仪表板,它也有许多用户体验技术和理论,使我在选择适当的UI元素(相对于数据)时更容易。

希望有帮助...