【问题标题】:Should I put input elements inside a label element?我应该将输入元素放在标签元素中吗?
【发布时间】:2010-10-20 22:01:23
【问题描述】:

有没有关于嵌套labelinput HTML 元素的最佳做法?

经典方式:

<label for="myinput">My Text</label>
<input type="text" id="myinput" />

<label for="myinput">My Text
   <input type="text" id="myinput" />
</label>

【问题讨论】:

  • &lt;input /&gt; 放在&lt;label&gt; 中的一大优点是,您可以在示例中省略forid&lt;label&gt;My text &lt;input /&gt;&lt;/label&gt;。好多了!
  • 虽然我同意input 在语义上不属于label,但我今天注意到developers of Bootstrap disagree with me。根据input 是在内部还是外部,某些元素(例如内联复选框)的样式会有所不同。
  • 顺便说一句,创建&lt;label for="id"&gt; 是一个非常糟糕的主意,因为我在页面上有多个表单,并且我不能为许多小部件使用id 属性而不落入unique id per page 陷阱。访问小部件的唯一可接受方式是通过form + widget_name
  • @MaxZoom 如果您的页面上有很多不同的表单具有相同的字段名称,以至于您无法想出唯一的 ID,您可能需要重新考虑一下您的页面设计,恕我直言;显然我不知道你的情况,但对我来说只是smells bad
  • @kenbellows 将两个搜索表单放在一个页面上是设计师/企业(不是我)的想法。最佳用户体验实践可能会随着时间而改变,但 HTML 应该足够灵活(恕我直言)以涵盖任何可见的场景。

标签: html semantics


【解决方案1】:

来自 W3 的HTML4 specification

标签本身可以位于之前、之后或周围 关联控件。


<label for="lastname">Last Name</label>
<input type="text" id="lastname" />

<input type="text" id="lastname" />
<label for="lastname">Last Name</label>

<label>
   <input type="text" name="lastname" />
   Last Name
</label>

请注意,当表格用于布局时,不能使用第三种技术,其中一个单元格中的标签和另一个单元格中的相关表单字段。

任何一个都有效。我喜欢使用第一个或第二个示例,因为它为您提供了更多的样式控制。

【讨论】:

  • 正如回答的那样,所有这些都是有效的,但在我自己的实践中,我通常选择 superUntitled 在这里给出的第一个示例,用于文本框、文本区域和选择。但是对于单选按钮和复选框,我通常使用第三个示例,我希望在随附文本之前输入,并且不希望其他标签和字段正在使用相同类型的固定宽度和/或浮动。所以在任何一个给定的表格上,你可能会发现我同时使用这两种格式。
  • 我想知道&lt;label for="inputbox"&gt;&lt;input id="inputbox" type="text" /&gt;&lt;/label&gt;是否符合他们的标准。
  • 太糟糕了,您不能在输入标签内嵌套标签。如果从抽象的角度来看,标签实际上是输入的属性,因此在语义上会更加合理。
  • 链接的 WCAG 文档包括以下选项“控件包含在包含标签文本的标签元素中。”我不知道自@Sorcy 发表评论以来的几年中是否添加了该内容,但现在认为标签输入场景有效。
  • 标签内的输入存在问题,至少在 chrome 中,当您将单击事件处理程序附加到标签时,单击标签时处理程序会被触发两次。您可以在处理程序末尾使用return false; 来解决此问题,但如果您可能有其他处理程序需要随后执行,并且无法停止传播,这将成为一个问题。
【解决方案2】:

我更喜欢

<label>
  Firstname
  <input name="firstname" />
</label>

<label>
  Lastname
  <input name="lastname" />
</label>

结束

<label for="firstname">Firstname</label>
<input name="firstname" id="firstname" />

<label for="lastname">Lastname</label>
<input name="lastname" id="lastname" />

主要是因为它使 HTML 更具可读性。而且我实际上认为我的第一个示例更容易使用 CSS 设置样式,因为 CSS 非常适合嵌套元素。

但我想这是一个品味问题。


如果您需要更多样式选项,请添加 span 标签。

<label>
  <span>Firstname</span>
  <input name="firstname" />
</label>

<label>
  <span>Lastname</span>
  <input name="lastname" />
</label>

在我看来,代码仍然看起来更好。

【讨论】:

  • 在标签中包含输入与使用HTML进行布局相同。
  • 我也喜欢这样的解决方案:&lt;label&gt;Expires after &lt;input name="exp" /&gt; days&lt;/label&gt;(标签在输入元素之前和之后)
  • 我认为最后一个例子 - 除了 for 和 id 属性 - 与在输入旁边放置标签并包装成divli 或其他什么没有什么不同,是吗!?
  • @retrovertigo - 功能上?不,它只是减少了标记,并减少了术语的语义过度使用。我们知道输入firstname 应该跟在firstname 的标签后面,但是浏览器需要声明。这完全取决于您的喜好以及您认为在您的代码中看起来最好(并且最容易调试)的内容。我现在更喜欢使用嵌套,虽然我花了一段时间才习惯它。
  • @MPavlak - 快速浏览一下,我从 w3.org 找到了这个指导。 w3.org/WAI/tutorials/forms/labels。然后我检查了w3.org/TR/WCAG20-TECHS/H44.html。在底部(它是模糊的)它说为了声明符合性,您需要通过测试标准,并且特别说明您应该使用 for 属性。实际上,当我上次在 Apple Voiceover(桌面屏幕阅读器市场份额 10%,移动屏幕阅读器市场份额 60%)中进行测试时,隐含标签不起作用,所以这是另一个主要因素。希望有帮助!
【解决方案3】:

行为差异:点击标签和输入之间的空间

如果您单击标签和输入之间的空格,则仅当标签包含输入时才会激活输入。

这是有道理的,因为在这种情况下,空格只是标签的另一个字符。

div {
  border: 1px solid black;
}
label {
  border: 1px solid black;
  padding: 5px;
}
input {
  margin-right: 30px;
}
<p>Inside:</p>
<label>
  <input type="checkbox" />
  Label. Click between me and the checkbox.
</label>

<p>Outside:</p>
<input type="checkbox" id="check" />
<label for="check">Label. Click between me and the checkbox.</label>

能够在label和box之间点击表示是:

  • 更容易点击
  • 不太清楚事情的开始和结束

Bootstrap checkbox v3.3 示例使用内部输入:http://getbootstrap.com/css/#forms 遵循它们可能是明智的。但是他们在 v4.0 https://getbootstrap.com/docs/4.0/components/forms/#checkboxes-and-radios 中改变了主意,所以我不知道什么是明智的了:

复选框和收音机的使用旨在支持基于 HTML 的表单验证并提供简洁易懂的标签。因此,我们的&lt;input&gt;s 和&lt;label&gt;s 是兄弟元素,而不是&lt;label&gt; 中的&lt;input&gt;。这稍微有点冗长,因为您必须指定 id 和属性来关联 &lt;input&gt;&lt;label&gt;

详细讨论这一点的用户体验问题:https://ux.stackexchange.com/questions/23552/should-the-space-between-the-checkbox-and-label-be-clickable

【讨论】:

  • 这不是规格差异。在所有兼容的浏览器中,切换适用于这两种情况。
  • @hexalys 感谢您的报告。我已经更新了答案。你的意思是兼容的浏览器应该在这两种情况下切换还是不切换?如果你能链接到相关的标准段落,那就太棒了。
  • 是的。尽管我没有注意到您的示例具有误导性,因为您的空间并不是真正的文本空间。这是复选框的margin。您示例中的 Firefox 行为很奇特,似乎是一个错误。 label 将包含内联内容周围的空格或填充作为可点击。但是考虑到标签的内容模型是 inline/Phrasing content,输入的边距不应该是可点击的,除非你的标签是 display: block,在这种情况下标签的内部 block 在所有浏览器中都可以点击。跨度>
  • 请注意,答案中的 Bootstrap 链接指向 v3.3 的文档。 docs for v4.0 似乎表明他们改变了主意:“复选框和收音机的使用旨在支持基于 HTML 的表单验证并提供简洁、可访问的标签。因此,我们的 s 和
  • 这种行为差异对我来说是最大的差异。当元素是同级元素时,任一元素上的任何边距会减少将触发输入元素的可点击表面积。将输入嵌套在标签内可保留最大的可点击区域,即使对于难以精确鼠标或触摸移动的用户,也能提供最大的可访问性。在 Bootstrap 4 中,嵌套仍然有效并且仍然显示相同,无需调整或覆盖任何 Bootstrap CSS。
【解决方案4】:

如果标签标签中包含输入标签,则不需要使用'for'属性。

也就是说,我不喜欢在标签中包含输入标签,因为我认为它们是独立的,不包含实体。

【讨论】:

  • for 要求你使用一个 id,这使得分层结构布局非常困难:-(
【解决方案5】:

我个人喜欢把标签放在外面,就像你的第二个例子一样。这就是 FOR 属性存在的原因。原因是我经常将样式应用于标签,例如宽度,以使表单看起来不错(下面的简写):

<style>
label {
  width: 120px;
  margin-right: 10px;
}
</style>

<label for="myinput">My Text</label>
<input type="text" id="myinput" /><br />
<label for="myinput2">My Text2</label>
<input type="text" id="myinput2" />

这样我就可以避免表格和表格中的所有垃圾。

【讨论】:

  • 您不应该将演示文稿留给 CSS,而不是使用 &lt;br /&gt; 来分隔输入吗?
  • @Znarkus - 是的,通常我将它们包装在 OL/LI 中以处理这样的格式,这只是一个速记示例。
  • @Parrots:这在语义上没有多大意义,imo。如果你需要包裹它们,为什么不直接用标签包裹它们呢?
  • @Parrots 出于这个原因,我认为页面上的所有内容都应该放在 ul/li 中。使用&lt;label&gt; &lt;span&gt;My text&lt;/span&gt; &lt;input /&gt; &lt;/label&gt;,您拥有(曾经)需要的所有样式选项。
  • 使用“for”会强制您使用 id,这对分层布局不利。
【解决方案6】:

有关 W3 建议,请参阅 http://www.w3.org/TR/html401/interact/forms.html#h-17.9

他们说这两种方法都可以。他们将这两种方法描述为显式(使用带有元素 id 的“for”)和隐式(将元素嵌入标签中):

显式:

for 属性将标签与另一个控件显式关联:for 属性的值必须与关联控件元素的 id 属性的值相同。

隐式:

要将标签与另一个控件隐式关联,控件元素必须在 LABEL 元素的内容内。在这种情况下,LABEL 可能只包含一个控制元素。

【讨论】:

  • 我刚刚发现隐式在 IE 中不起作用......有什么想法吗?
【解决方案7】:

两者都是正确的,但是将输入放在标签中会使其在使用 CSS 进行样式设置时变得不那么灵活。

首先,a &lt;label&gt; is restricted in which elements it can contain。例如,如果&lt;input&gt; 不在&lt;label&gt; 内,则只能在&lt;input&gt; 和标签文本之间放置&lt;div&gt;

其次,虽然有一些变通方法可以使样式更容易,例如用 span 包裹内部标签文本,但某些样式将从父元素继承,这会使样式变得更加复杂。

第三方编辑

根据我的理解html 5.2 spec for label 声明标签Content modelPhrasing content。这意味着只有其内容模型是短语内容&lt;label&gt; are allowed inside &lt;/label&gt; 的标签。

内容模型 对必须包含哪些内容的规范性描述 作为元素的子元素和后代。

大多数被归类为短语内容的元素只能 包含本身被归类为短语内容的元素, 没有任何流内容。

【讨论】:

  • 不太灵活?你能详细说明吗?正如其他人所提到的,您可以简单地用跨度包装内部标签文本,除非这使它变得不那么灵活?
  • @nicholaides 你是说这个标签只能包含某些其他标签的原因吗?
  • @surfmuggle 是的
【解决方案8】:

一个值得注意的“陷阱”规定,您永远不应在具有显式“for”属性的

<label for="child-input-1">
  <input type="radio" id="child-input-1"/>
  <span> Associate the following text with the selected radio button: </span>
  <input type="text" id="child-input-2"/>
</label>

虽然这对于自定义文本值次于单选按钮或复选框的表单功能来说可能很诱人,但标签元素的单击焦点功能将立即将焦点转移到其 id 在其 ' 中明确定义的元素for' 属性,使用户几乎不可能单击包含的文本字段来输入值。

就个人而言,我尽量避免带有输入子项的标签元素。一个标签元素包含的不仅仅是标签本身,这在语义上似乎是不合适的。如果您在标签中嵌套输入以达到某种美感,您应该改用 CSS。

【讨论】:

  • 这不是“陷阱”。它是规范的明确部分;标签中最多可以包含 1 个控件。您还在这里混合了隐式和显式样式-如果将控件放在标签内,则不需要for...如果要使用for,则将控件放在标签内没有多大意义。
  • 是的,但是这个规范似乎没有被很好地理解。我们在使用 Drupal 6 的表单 API 时遇到了这个问题,它生成的标记创建了一个与上述情况不同的场景。这让我和我的同事摸不着头脑一两分钟,所以我想我会在这里提出这个问题,以避免将来出现潜在的混乱。
  • 标签->输入场景中不需要“for”。每个标签一个输入,它的好处是不必知道名称或 id,您可以做漂亮的 css 样式以保持封装以及在单击任何其他元素时出现焦点。请参阅 zipstory.com/signup 以了解执行此操作的干净方式。
  • 谢谢;这回答了我的另一个相关问题,即标签内是否可能有多个输入。 (上下文:几个单选按钮选项,每行一个,每个单选按钮条目有 1、2、3 个或可能更多文本类型的输入,目的是单击具有选择该行单选按钮结果的行,如果未选中,并允许编辑该行上的输入/输入。)这为在表单中为非输入文本设置多个标签打开了大门,但它回答了我关于我的想法是否可行的问题。 (不是。)
【解决方案9】:

正如大多数人所说,这两种方式确实有效,但我认为只有第一种应该。由于语义严格,标签不“包含”输入。在我看来,标记结构中的包含(父/子)关系应该反映视觉输出中的包含。即,标记中中另一个元素周围的元素应在浏览器中周围绘制。据此,标签应该是输入的兄弟,而不是父。因此,选项二是任意且令人困惑的。读过Zen of Python 的每个人都可能同意(扁平比嵌套好,稀疏比密集好,应该有一种——最好只有一种——明显的方法......)。

由于 W3C 和主要浏览器供应商的决定(允许“以您喜欢的方式做”,而不是“以正确的方式做”)是当今网络如此混乱,我们开发人员必须处理复杂多样的遗留代码。

【讨论】:

  • 前两个选项的根本缺陷是它们需要 ID,因此不适合模块化内容。表单应该在不了解其周围环境的情况下注意它在页面上的可重复性,并且在使用 ID 时,这意味着前缀或其他恶作剧,而嵌套避免了这种情况。
【解决方案10】:

我通常选择前两个选项。我见过使用第三个选项的场景,当嵌入在标签和 css 中的单选选项包含类似

label input {
    vertical-align: bottom;
}

为了确保收音机的正确垂直对齐。

【讨论】:

    【解决方案11】:

    我非常喜欢将元素包装在我的&lt;label&gt; 中,因为我不必生成 ID。

    我是一名 Javascript 开发人员,使用 React 或 Angular 生成可以被我或其他人重用的组件。那么在页面中很容易复制一个 id,导致出现奇怪的行为。

    【讨论】:

      【解决方案12】:

      参考 WHATWG (Writing a form's user interface) 将输入字段放在标签内并没有错。这可以节省您的代码,因为不再需要来自 labelfor 属性。

      【讨论】:

        【解决方案13】:

        您需要考虑的一件事是复选框和单选输入与 javascript 的交互。

        使用以下结构:

        <label>
          <input onclick="controlCheckbox()" type="checkbox" checked="checkboxState" />
          <span>Label text</span>
        </label>
        

        当用户点击“标签文本”时,controlCheckbox() 函数将被触发一次。

        但是当点击输入标签时,controlCheckbox() 函数可能会在一些较旧的浏览器中被触发两次。那是因为输入和标签标签都会触发附加到复选框的 onclick 事件。

        那么你的 checkboxState 中可能有一些错误。

        我最近在 IE11 上遇到了这个问题。我不确定现代浏览器是否存在这种结构的问题。

        【讨论】:

          【解决方案14】:

          将输入嵌套到标签有几个优点,尤其是单选/复选框字段,

          .unchecked, .checked{display:none;}
            label input:not(:checked) ~ .unchecked{display:inline;}
            label input:checked ~ .checked{display:inline;}
          <label>
            <input type="checkbox" value="something" name="my_checkbox"/>
            <span class="unchecked">Not Checked</span>
            <span class="checked">Is Checked</span>
          </label>

          从演示中可以看出,首先嵌套输入字段,然后是其他元素允许,

          • 要单击以激活字段的文本
          • 输入字段后面的元素将根据字段状态动态设置样式。

          此外,HTML std 允许 multiple labels 与输入字段相关联,但这会混淆屏幕阅读器,解决此问题的一种方法是将输入字段和其他元素嵌套在单个标签元素中。

          【讨论】:

          • 您仍然可以对未嵌套的标签执行相同的操作:jsfiddle.net/n4zc95s1 并且使用单个标签表示像此提案这样的 2 个不同的事物可能难以获得可访问的表单。为了WCAG,我会和这个分开。
          • true,但我仍然发现一个输入字段的一个标签更易于使用。将输入嵌套在标签中还允许插入伪元素并执行更复杂的 UI,例如 checkbox tree views
          猜你喜欢
          • 1970-01-01
          • 2011-10-19
          • 1970-01-01
          • 2018-10-04
          • 2010-10-29
          • 1970-01-01
          相关资源
          最近更新 更多