名值对的语义与结构

这个问题我已经纠结了一段时间了。标记名称/值对的正确方法是什么?

我喜欢 < dl > 元素,但是它提出了一个问题: 没有办法将一对元素从另一对元素中分离出来——它们没有唯一的容器。在视觉上,代码缺乏定义。不过,从语义上讲,我认为这是正确的标记。

<dl>
<dt>Name</dt>
<dd>Value</dd>
<dt>Name</dt>
<dd>Value</dd>
</dl>

在上面的代码中,无论是在代码中还是在渲染中,都很难在视觉上正确地偏移这些对。例如,如果我想要,但是在每一对的周围都有一个边框,那将是一个问题。

我们可以指着桌子。可以认为,名称-值对是表格数据。这对我来说似乎不正确,但我看到了论点。但是,除了在位置或添加类名之外,HTML 并不区分名称和值。

<table>
<tr>
<td>Name</td>
<td>Value</td>
</tr>
<tr>
<td>Name</td>
<td>Value</td>
</tr>
</table>

从可视化的角度来看,这在代码和 CSS 中都更有意义。设计前面提到的边框是微不足道的。然而,如上所述,语义充其量是模糊的。

有什么想法,评论,问题吗?

编辑/更新 也许我应该在结构方面明确提到这一点,但是定义列表还存在不能从语义上对这些对进行分组的问题。dddt之间的顺序和隐含边界很容易理解,但是我仍然觉得有点不对劲。

37110 次浏览

Hmm. dt/dd sound best for this and it is possible to offset them visually, although I do agree it's more difficult than for a table.

As for source code readability, how about putting them into one line?

<dl>
<dt>Name</dt> <dd>Value</dd>
<dt>Name</dt> <dd>Value</dd>
</dl>

I agree it's not 100% perfect, but seeing as you can use space characters for indentation:

<dl>
<dt>Property with a looooooooooong name</dt>   <dd>Value</dd>
<dt>Property with a shrt name</dt>             <dd>Value</dd>
</dl>

it might be the nicest way.

I do like Unicron's idea of putting them all on one line, but another option would be to indent the value below the definition name:

<dl>
<dt>Name</dt>
<dd>Value</dd>
<dt>Name</dt>
<dd>Value</dd>
</dl>

This way might be a little easier on the eye in ridiculously long definitions (although if you're using ridiculously wrong definitions then perhaps a definition list isn't what you really want after all).

As for the rendering on screen, a fat bottom margin applied to the dd is plenty visual separation.

I think a definition list is probably a bad idea. Semantically, they are used for definitions. Other key-value lists will often differ from definition titles and descriptions.

A table is one way to go, but what about an unordered list?

<ul>
<li class="key-value-pair">
<span class="key">foo</span>
<span class="value">bar</span>
</li>
</ul>

How about just placing a blank line between each pair?

This requires no special handling for long values.

<dl>
<dt>Name</dt>
<dd>Value</dd>


<dt>Name</dt>
<dd>Value</dd>


<dt>Name</dt>
<dd>Value</dd>
</dl>

it is difficult to properly offset the pairs visually, both in code and rendered. If I wanted to, for instance, but a border around each pair, that would be a problem.

Others before me have dealt (quite well I think) with the problem of providing visual definition in code. Which leaves the problem of rendering and CSS. This can be done quite effectively in most cases. The biggest exception is placing a border around each set of dt/dds, which is admittedly extremely tricky - perhaps impossible to style reliably.

You could do:

dt,dd{ border:solid; }
dt{ margin:10px 0 0 0; border-width:1px 1px 0 1px; }
dd{ margin:0 0 10px 0; border-width:0 1px 1px 1px; padding:0 0 0 10px; }
dd::before{ content:'→ '; }

Which works for key-value PAIRS, but presents problems if you have multiple dds within one "set" like:

<dt>Key1</dt>
<dd>Val1.1</dd>
<dd>Val1.2</dd>
<dt>Key2</dt>
<dd>Val2.1</dd>
<dd>Val2.2</dd>

However, border-styling limitations aside, doing anything else to associate sets (backgrounds, numbering, etc.) is quite possible with CSS. There's a nice overview here: http://www.maxdesign.com.au/articles/definition/


Another point I think is worth noting, if you're looking to optimally style definition-lists to provide visual separation - CSS's automatic-numbering features (counter-increment and counter-reset) can come in quite handy: http://www.w3.org/TR/CSS2/generate.html#counters

Thanks for this interesting question. There are few more things to consider here.

What is a pair? Two elements together. So we need a tag for this. Let's say it is pair tag.

 <pair></pair>

The pair contains the key, and the corresponding value:

 <pair><key>keyname</key><value>value</value></pair>

Then, we need to list the pairs:

<pairlist>
<pair><key>keyname</key><value>value</value></pair>
<pair><key>keyname</key><value>value</value></pair>
</pairlist>

The next thing to consider, is the display of the pairs. The usual layout is the tabular one:

key value
key value

and the optional separator, which is usually colon:

key : value
key : value

The colons can be easily added via CSS, but this certainly won't work in IE.

Case described above is the ideal one. But there is no valid HTML markup to fit in this easily.


To sum up:

dl is semantically closest, for simple cases of key and value, but is hard to apply visual styles (eg. to display the pairs inline or to add red border to just hovered pair). The case which fits most for dl is glossary. But this is not the case we discuss.

The only alternative I can see in this case is to use table, like this:

<table summary="This are the key and value pairs">
<caption>Some notes about semantics</caption>
<thead class="aural if not needed">
<tr><th scope="col">keys</th><th scope="col">values</th></tr>
</thead>
<tbody class="group1">
<tr><th scope="row">key1</th><td>value1</td></tr>
<tr><th scope="row">key2</th><td>value2</td></tr>
</tbody>
<tbody class="group2">
<tr><th scope="row">key3</th><td>value3</td></tr>
<tr><th scope="row">key4</th><td>value4</td></tr>
</tbody>
</table>

One more:

<ul>
<li><strong>key</strong> value</li>
<li><strong>key</strong> value</li>
</ul>

or:

<ul>
<li><b>key</b> value</li>
<li><b>key</b> value</li>
</ul>

or, when the keys may be linked:

<ul>
<li><a href="/key1">key1</a> value</li>
<li><a href="/key2">key1</a> value</li>
</ul>

The key and value pairs are usually stored in database, and those usually store tabular data, so the table would fit best IMHO.

What do you think?

What about using lists?

Ordered:

<ol>
<li title="key" value="index">value</li>
…
</ol>

Or use <ul> for an unordered list, and skip the value="index" bit.

XHTML 2 introduces the ability to group terms and definitions using the di element

<!-- Do not us this code! -->
<dl>
<di>
<dt>Name</dt>
<dd>John</dd>
</di>
<di>
<dt>Age</dt>
<dd>25</dd>
</di>
</dl>

X/HTML 5 vs XHTML 2 > Enhancement To Definitions Lists

Unfortunately though, XHTML 2 is dead and HTML5 doesn't have di element

So, you can combine ul > li with dl > dt + dd :

<ul>
<li>
<dl>
<dt>Name</dt>
<dd>John</dd>
</dl>
</li>
<li>
<dl>
<dt>Age</dt>
<dd>25</dd>
</dl>
</li>
</ul>

Except for the <dl> element, you've pretty much summed up all the options of HTML: limited ones.

However you're not lost, there is one option left: using a markup language that can be translated to HTML. A very good option is Markdown.

Using a table extension that some markdown engines provide, you can have code like this:

| Table header 1 | Table header 2 |
-----------------------------------
| some key       | some value     |
| another key    | another value  |

This means that you need a build step to translate the Markdown to HTML of course.

This way you get meaningful markup (table for tabular data) and maintainable code.

This is not my preferred solution, but it is a clever abuse of the semantic element:

Use a new <dl> per <dt>/<dd> pair:

<div class="terms">
<dl><dt>Name 1</dt><dd>Value 1</dd></dl>
<dl><dt>Name 2</dt><dd>Value 2</dd></dl>
</div>

An example with css floats and red border on hover:

dt:after { content:":"; }
dt, dd { float: left; }
dd { margin-left: 5px }
dl { float: left; margin-left: 20px; border: 1px dashed transparent; }
dl:hover { border-color: red; }
<div class="terms">
<dl>
<dt>Name 1</dt>
<dd>Value 1</dd>
</dl><!-- etc -->
<dl><dt>Name 2</dt><dd>Value 2</dd></dl>
<dl><dt>Name 3</dt><dd>Value 3</dd></dl>
<dl><dt>Name 4</dt><dd>Value 4</dd></dl>
<dl><dt>Name 5</dt><dd>Value 5</dd></dl>
<dl><dt>Name 6</dt><dd>Value 6</dd></dl>
</div>

The line from spec:

Name-value groups may be terms and definitions, metadata topics and values, questions and answers, or any other groups of name-value data.

I assume use of elements <dl>, <dt> and <dd>.

Of course, you could just use HTML Custom elements. ( spec )They're completely valid HTML5.

Unfortunately, browser support isn't that great, but if rarely do we care about such pedestrian things as browser support when we're dealing with semantics. :-)

One such way you could represent it:

After registering your brand new fancy element like so:

var XKey = document.registerElement('x-key');
document.body.appendChild(new XKey());

You write markup like so:

<ul>
<li>
<x-key>Name</x-key>
Value
</li>
</ul>

The only condition that HTML Custom elements have are that they need a dash in them. Of course, you can now be super creative... if you're building an auto parts warehouse, with lists of parts and serial numbers:

<ul>
<li>
<auto-part>
<serial-number>AQ12345</serial-number>
<short-description>lorem ipsum dolor...</short-description>
<list-price>14</list-price>
</auto-part>
</li>
</ul>

You can't get much more semantic than that!

However, there IS a chance I have gone too far into semantic-shangri-la-la (a real place) and might be tempted to scale it back to something a little more generic:

<ul>
<li class='auto-part' data-serial-number="AQ12345">
<p class='short-description'>lorem ipsum dolor...</p>
<p class='list-price'>14</p>
</li>
</ul>

Or perhaps this ( if I needed to style and show the key visually )

<ul>
<li class='auto-part'>
<x-key>AQ12345<//x-key>
<p class='short-description'>lorem ipsum dolor...</p>
<p class='list-price'>14</p>
</li>
</ul>

Following the specification (and further details) provided by Alexandr Antonov: use ABC0, ABC1, ABC2, and optionally div.

A combination of dl, dt, and dd is semantically fine for key-value pairs:

<dl>
<dt>Key1</dt>
<dd>Value1</dd>
<dt>Key2</dt>
<dd>Value2</dd>
</dl>

For easier styling or parsing, divs can be used as children of dl to group the key-value pairs (and makes dt and dd be grandchildren of dl):

dl { display: table; }
dl > div { display: table-row; }
dl > div > dt, dl > div > dd { display: table-cell; border: 1px solid black; padding: 0.25em; }
dl > div > dt { font-weight: bold; }
<dl>
<div>
<dt>Key1</dt>
<dd>Value1</dd>
</div>
<div>
<dt>Key2</dt>
<dd>Value2</dd>
</div>
</dl>

dl {
display: grid;
grid-template-columns: auto auto;
}


dd {
margin: 0
}
<dl>
<dt>key</dt>
<dd>value</dd>
<dt>key</dt>
<dd>value</dd>
</dl>

I used <dl> <dt> <dd> and styled them with grid