web-dev-qa-db-fra.com

Combinaison d'une table et d'une liste hiérarchique en HTML

Je travaille sur la refonte d'un ensemble d'outils hérité et je cherche comment améliorer l'affichage de certaines informations de manière sémantique et présentation.

Les données sont de nature hiérarchique, mais possèdent des propriétés qui doivent être facilement visibles pour les utilisateurs. La mise en page souhaitée est similaire à celle ci-dessous.

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)

Pour le moment, il s’agit d’un tableau entier, et l’objet du nombre de séquence (Seq) est obtenu en insérant des cellules supplémentaires dans le tableau afin de tout déplacer vers la droite.

Le défi que je me pose est de savoir comment afficher efficacement ces informations.

Tout d'abord, s'agit-il de données tabulaires? Je dirais non, car la hiérarchie est importante et les "colonnes" ne sont que des attributs de l'élément dans chaque "ligne".

Si ce n'est pas tabulaire, qu'est-ce que c'est et comment cela serait-il fait? Je dirais personnellement qu'il s'agit d'un ensemble de listes UL imbriquées - le numéro de séquence est facultatif et pas toujours un nombre. Si c'est un ensemble de listes, cela indenterait correctement les sous-listes, mais quel est le meilleur moyen de présenter les attributs courts?

Si c'est une table, quel est le meilleur moyen de présenter l'existence sémantique de la hiérarchie dans la table?

19
user764357

Le défi ici est que les informations que vous voulez représenter se trouvent sous un certain aspect dans un tableau (il s’agit d’un ensemble d’éléments ayant des attributs identiques), et dans un autre hiérarchique (les éléments ont des parents). 

Malheureusement, il n'y a pas de mécanisme de regroupement imbriqué pour les lignes de table en HTML: tbody peut être utilisé pour grouper des lignes, mais l'imbrication est illégale (sauf avec une table intermédiaire dans une td, ce qui est assez horrible).

Cela vous laisse deux choix:

  1. Représentez les informations avec des listes imbriquées, et utilisez CSS pour que le résultat ressemble à un tableau.

  2. Représentez les informations sous forme de tableau et utilisez des attributs pour représenter ses relations hiérarchiques.

Voici quelques exemples de mise en œuvre de ces choix:

Utilisation de listes imbriquées (approche naïve):

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

Cela gère l’aspect hiérarchique de l’information, mais vous finissez par vous répéter souvent et vous allez devoir parcourir certaines étapes du CSS pour afficher le résultat sous forme de tableau. C'est probablement faisable avec une utilisation judicieuse de :first-child, mais le résultat final est que vous avez tout fait pour marquer un élément que vous souhaitez présenter sous forme de tableau de manière non tabulaire, ce qui vous a donné plus de travail. le remettre en forme.

Cela rend également la nature véritablement tabulaire des relations entre les éléments implicite plutôt qu'explicite dans le balisage - sans faire référence à la sortie rendue, il n'est pas clair que ces éléments auront toujours le même nombre et le même type d'attributs.

Utilisation de listes imbriquées (approche "intelligente"):

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

Ici, nous utilisons listes de description pour décrire deux choses:

  1. La relation en-tête/détail entre par ex. 'Nom de l'article' et 'Identifiant' etc.

  2. La relation parent/enfant entre par exemple l'unité 'Nom' et l'unité 'Prénom'.

C'est certes plus compact, mais malheureusement, la relation spécifique entre chaque en-tête et ses éléments de détail est au mieux implicite. Sans un style supplémentaire pour organiser visuellement les informations de manière tabulaire, le rendu de ce qui est réellement représenté sera encore moins évident.

Utilisation d'une 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>

Ici, les relations parent/enfant sont explicitement décrites par l'attribut data-parent (auquel on peut accéder via javascript si nécessaire), et un attribut class=level-{n} fournit un crochet utilisable par le CSS:

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

En fin de compte, c’est une question de préférence personnelle et de commodité, mais je pense que l’approche <table> est préférable simplement parce qu’elle satisfait le principe «cela at-il l’air raisonnable sans CSS?». La règle empirique est bien meilleure que l’une ou l’autre des approches de listes imbriquées ci-dessus.

20
Zero Piraeus

Je le présenterais en utilisant un tableau et en ajoutant les attributs de données personnalisés aux balises 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>

Ensuite, à l'aide de jQuery, définissez le remplissage de chaque valeur de cellule dans votre tableau:

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

Voyez le travail sur jsFiddle .

7
Alex Filipovici

Je pense qu'il y a deux manières sensées de représenter cela en HTML:

  • utiliser une table et rendre la relation/hiérarchie explicite avec le langage naturel
  • utiliser des éléments de sectionnement (resp. titres si vous utilisez HTML 4.01)

table avec une colonne expliquant la hiérarchie

S'il n'y a pas de balisage pour définir cette relation, vous devez utiliser du texte. Si la représentation visuelle est sans ambiguïté, vous pouvez masquer visuellement ce texte afin qu'il ne soit accessible qu'aux utilisateurs de lecteur d'écran/navigateur de texte.

Dans votre cas, vous pouvez ajouter une colonne qui explique la relation entre les lignes qui sont des "sous-éléments":

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

Chaque ligne peut avoir une valeur id (avec la valeur Seq ou Item Name), de sorte que cette ligne puisse être liée {notez que les valeurs id commençant par un chiffre ne sont pas autorisées dans HTML 4.01; vous pouvez utiliser quelque chose comme id="seq-2.1" ici}. Si un élément est l'enfant d'un autre élément, vous pouvez créer un lien vers la ligne de l'élément parent. 

De cette façon, vous faites comprendre aux humains, et les machines voient toujours que ces lignes sont connectées, bien que la sémantique spécifique de cette relation ne soit pas lisible par machine. Vous pouvez utiliser un type de lien (valeur rel) ici si vous souhaitez clarifier le sens de la relation. En HTML 4.01, vous pouvez créer une valeur vous-même, en HTML5, il devrait être enregistré premier.

éléments de coupe/titres

Au lieu d’utiliser une table, vous pouvez utiliser les contours HTML. {L’exemple suivant utilise Les éléments de sectionnement de HTML5 . Si vous utilisez HTML 4.01, remplacez simplement les éléments de sectionnement par div (ou aucun élément du tout) et utilisez uniquement les en-têtes.}

Chaque section (introduite par un en-tête) représente un élément. Le contour des en-têtes (resp. Imbrication des éléments de sectionnement) représente la hiérarchie de vos éléments.

Voici un exemple pour voir la structure entière:

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

Chaque section peut contenir une dl pour les propriétés:

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

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

</section>

En fonction de la signification réelle de votre contenu, vous pouvez utiliser l'élément code pour les noms d'éléments (par exemple, s'il décrit des éléments d'un langage de balisage, par exemple) et/ou l'élément dfn , si le contenu suivant est une définition de cet élément.

3
unor

Ma suggestion serait d'utiliser des listes ordonnées imbriquées pour conserver votre structure hiérarchique, puis des listes de description pour représenter les "colonnes" de chaque ligne.

Par exemple, la liste de description de la première ligne pourrait ressembler à ceci:

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

Vous devrez utiliser CSS pour masquer les termes de la description (car vous ne voulez pas qu'ils apparaissent à chaque ligne) et pour ajuster la mise en page afin qu'elle ressemble davantage à un tableau.

L'inconvénient de ce format est que vous allez dupliquer les en-têtes de colonne sur chaque ligne. Mais sur le plan sémantique, je pense que cela a le plus de sens et que cela devrait également rendre le contenu plus significatif pour un lecteur d'écran.

J'ai fait une première tentative de CSS pour cela afin que vous puissiez avoir une idée de la façon dont cela pourrait fonctionner. Ce n'est probablement pas très bien fait, mais au moins, ça vous donnera quelque chose pour commencer.

CodePen Link

2
James Holderness

UPDATE: j'ai ajouté l'utilisation des identifiants et des attributs "en-têtes" pour, d'une manière ou d'une autre, marquer sémantiquement la hiérarchie.

C'est définitivement des données tabulaires (vous devriez vraiment pousser la définition de "liste" pour justifier l'utilisation d'un UL ou DL ici!).

Je pense qu'une bonne approche consisterait à utiliser différents types de groupes pour regrouper ces lignes (quelque chose de similaire à ceci utilisé ici http://www.w3.org/TR/2012/WD-html5-20120329/the-table-element .html # the-table-element voir "tableau utilisé pour baliser un puzzle de Sudoku")

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

Ensuite, vous pourriez utiliser quelque chose comme ceci:

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

En fait, je pense que vous ne pouvez utiliser tbody que pour regrouper des lignes et laisser une seule ligne. 

<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

Je pense que vous devriez utiliser une table. Certes, la hiérarchie est plus importante, mais elle peut également être affichée en écrivant manuellement la première colonne. Mais les attributs min, max et le nom de l'élément ne pouvaient pas être affichés aussi facilement dans une liste que dans une table. Mon avis: utilisez un tableau et fournissez la colonne seq manuellement!

2
Lars Ebert

Pourquoi pas les deux? Une grille d'arborescence est un bon moyen de représenter des données tabulaires qui sont également conformes à une hiérarchie.

C'est un exemple .

Cependant, après avoir utilisé Extjs sur deux projets très volumineux, ma recommandation personnelle est de ne pas en parler si vous voulez produire une application volumineuse. Bien que cela puisse convenir pour un réseau ponctuel, j’ai personnellement constaté qu’il était mal mis en œuvre et pouvait devenir plus encombrant à mesure que la taille du projet augmentait. Toutefois, comme il est très riche en fonctionnalités, le panneau exemples peut vous donner quelques idées supplémentaires sur les grilles (tableaux) qui pourraient vous aider.

N'oubliez pas que vous devez toujours vous demander: "Quelles questions mes utilisateurs essaient-ils de répondre?" Puis, demandez-vous quels appareils graphiques donnent le moyen le plus clair et le plus simple de répondre à cette question?

Un livre qui m'a vraiment aidé avec ces questions était le livre de conception de tableau de bord . Même si vous ne construisez peut-être pas de tableau de bord, il comporte de nombreuses techniques et théories qui facilitent la sélection de l'élément d'interface utilisateur approprié (en ce qui concerne les données).

J'espère que cela pourra aider...

0
Homer6