如何在不使用INPUT标签的ID属性的情况下,使用LABEL标签的FOR属性?

95
以下代码中所示的问题是否有解决方案?打开浏览器即可直接了解问题,无需在查看所有代码之前就知道自己要寻找什么。
<html>
 <head>
  <title>Input ID creates problems</title>
  <style type="text/css">
   #prologue, #summary { margin: 5em; }
  </style>
 </head>
 <body>
  <h1>Input ID creates a bug</h1>
  <p id="prologue">
   In this example, I make a list of checkboxes representing things which could appear in a book. If you want some in your book, you check them:
  </p>
  <form>
   <ul>
    <li>
     <input type="checkbox" id="prologue" />
     <label for="prologue">prologue</label>
    </li>
    <li>
     <input type="checkbox" id="chapter" />
     <label for="chapter">chapter</label>
    </li>
    <li>
     <input type="checkbox" id="summary" />
     <label for="summary">summary</label>
    </li>
    <li>
     <input type="checkbox" id="etc" />
     <label for="etc">etc</label>
     <label>
    </li>
   </ul>
  </form>
  <p id="summary">
   For each checkbox, I want to assign an ID so that clicking a label checks the corresponding checkbox. The problems occur when other elements in the page already use those IDs. In this case, a CSS declaration was made to add margins to the two paragraphs which IDs are "prologue" and "summary", but because of the IDs given to the checkboxes, the checkboxes named "prologue" and "summary" are also affected by this declaration. The following links simply call a javascript function which writes out the element whose id is <a href="javascript:alert(document.getElementById('prologue'));">prologue</a> and <a href="javascript:alert(document.getElementById('summary'));">summary</a>, respectively. In the first case (prologue), the script writes out [object HTMLParagraphElement], because the first element found with id "prologue" is a paragraph. But in the second case (summary), the script writes out [object HTMLInputElement] because the first element found with id "summary" is an input. In the case of another script, the consequences of this mix up could have been much more dramatic. Now try clicking on the label prologue in the list above. It does not check the checkbox as clicking on any other label. This is because it finds the paragraph whose ID is also "prologue" and tries to check that instead. By the way, if there were another checkbox whose id was "prologue", then clicking on the label would check the one which appears first in the code.
  </p>
  <p>
   An easy fix for this would be to chose other IDs for the checkboxes, but this doesn't apply if these IDs are given dynamically, by a php script for example.
   Another easy fix for this would be to write labels like this:
   <pre>
    &lt;label&gt;&lt;input type="checkbox" /&gt;prologue&lt;/label&gt;
   </pre>
   and not need to give an ID to the checkboxes. But this only works if the label and checkbox are next to each other.
  </p>
  <p>
   Well, that's the problem. I guess the ideal solution would be to link a label to a checkboxe using another mechanism (not using ID). I think the perfect way to do this would be to match a label to the input element whose NAME (not ID) is the same as the label's FOR attribute. What do you think?
  </p>
 </body>
</html>

5
除了缺乏明确的问题之外,这是一个重复问题,与https://dev59.com/4Woy5IYBdhLWcg3wddxv相同。 - Mark E. Haase
7个回答

164

11
只有在标签和复选框相邻的情况下,这才有效。 - Shawn
12
@Shawn 原贴情况就是这样。 - Igor Zevaka
我唯一建议的是将文本放在输入标签之前。否则,完美! - Stan
9
问题在于当你需要样式化它时。CSS 中没有父选择器。 - Maciej Krawczyk
1
在某些布局中可能无法实现,但是如果没有JS,将标签和输入框链接起来就根本不可能。这是WC3批准的解决方案,而不使用ID进行链接。如果你真的遇到了样式或标记问题,那就使用JS吧。 - perry
显示剩余3条评论

16

在我看来,最好的做法是给所有复选框重命名,例如添加一些前缀到它们的id中,比如 input

   <ul>
    <li>
     <input type="checkbox" id="input_prologue" />
     <label for="input_prologue">prologue</label>
    </li>
    <li>
     <input type="checkbox" id="input_chapter" />
     <label for="input_chapter">chapter</label>
    </li>
    <li>
     <input type="checkbox" id="input_summary" />
     <label for="input_summary">summary</label>
    </li>
    <li>
     <input type="checkbox" id="input_etc" />
     <label for="input_etc">etc</label>
    </li>
   </ul>

这样,您就不会与页面上其他id发生冲突,点击标签将切换复选框而无需任何特殊的JavaScript函数。


7

编辑:回顾我的解决方案,也远非理想。我建议您改为使用“隐式标签关联”,如此答案所示:stackoverflow.com/a/8537641/884734

我的提议,不太理想的解决方案如下:

这个问题可以很容易地通过一些javascript来解决。只需将以下代码放入你页面js文件中的一个中,即可使<label>标签具有以下行为:

当单击标签时:

如果页面上有一个元素的id与标签的for属性匹配,则恢复默认功能并聚焦该输入。

如果使用id找不到匹配项,则查找带有class匹配标签的for属性的label的兄弟元素,并对其进行聚焦。

这意味着您可以按照以下方式布局您的表格:

<form>
    <label for="login-validation-form-email">Email Address:</label>
    <input type="text" class="login-validation-form-email" />
</form>

遗憾的是,实际代码如下:

$(function(){
    $('body').on('click', 'label', function(e){
        var labelFor = $( this ).attr('for');
        if( !document.getElementById(labelFor) ){
            e.preventDefault(); e.stopPropagation();
            var input = $( this ).siblings('.'+labelFor);
            if( input )
                input[0].focus();
        }
    })
});

注意:这可能会导致在根据W3C规范验证您的网站时出现问题,因为<label> for属性应始终与页面上具有匹配ID的对应元素对应。
希望这能帮到您!

感谢那位给我点了踩的人。回想起来,我的解决方案远非理想。我建议您改为利用“隐式标签关联”,如此答案所示:https://dev59.com/4Woy5IYBdhLWcg3wddxv#8537641 - Eric Seastrand
2
这不仅会导致与W3C验证器的兼容性问题,而且对于辅助技术(例如屏幕阅读器)也无法正常工作。正如您在评论中所写的那样,它们需要一个隐式标签关联。 - Volker E.

3

简单来说,一个ID只应该在页面上使用一次,因此他们不会为单个页面上不存在的多个ID设计解决方法。

回答问题的其余部分:不,ID属性是标签“for”属性将查看的唯一内容。您始终可以使用JavaScript onclick事件按名称获取输入并更改它,但这似乎过于复杂,当您可以修复ID问题时,这将更有意义。


一石二鸟,解决两个问题。一些无意义的FYI:for属性是IDREF数据类型,它看起来像是唯一的ID类型值。这些是XML Schema可用的遗留数据类型,所以我想这意味着它们是SGML的常驻数据类型。 - austin cheney
13
问题出现在动态创建输入框的id上。我无法预知它们的id,因此无法确保与页面上其他元素的id不重复。正如你所说,使用JavaScript的解决方案过于复杂(而且有些人没有JavaScript)。 - Shawn
1
为ID生成GUID。 - Triynko

3
与被接受的答案不同,我赞同FantomX1提出的解决方案:为每个复选框生成一个随机id,并将此id用于与复选框相关联的标签。 但我会使用uuid生成随机id(请参见在JavaScript中创建GUID / UUID?)。

2
也许最简单的解决方案是使用 uniqueid() 函数,无论是在 PHP 还是其他编程语言中。

0
今天我在处理这个问题时遇到了困难,想分享一下我的结果,因为似乎谷歌排名前几页没有其他相关内容。所以这是我第一篇 Stack-Post(诀窍是将复选框拉伸到其他元素上方,但通过使用 z-index 使它们仍然可点击):
首先:感谢基础手风琴的贡献者: https://code-boxx.com/simple-responsive-accordion-pure-css/

.tab{
    position: relative;
    max-width: 600px;
    z-index:1;
}
.tab input{
    padding: 100%;
    position: absolute;
    width: 100%;
    height: 100%;
    opacity: 0;
    z-index:2;
    cursor: pointer;
}
.tab label{
    display: block;
    margin-top: 10px;
    padding: 10px;
    color: #fff;
    font-weight: bold;
    background: #2d5faf;
}
.tab label span{
    position:relative;
    z-index:3;
    cursor:text;
}
.tab .tab-content{
    position:relative;
    background: #ccdef9;
    overflow: hidden;
    transition: max-height 0.3s;
    max-height: 0;
    z-index:3;
}
.tab .tab-content p{
    padding: 10px;
}
.tab input:checked ~ .tab-content{
    max-height: 100vh;
}
.tab label::after{
    content: "\25b6";
    position: absolute;
    right: 10px;
    top: 10px;
    display: block;
    transition: all 0.4s;
}
.tab input:checked ~ label::after{
    transform: rotate(90deg);
}
<div>
                            <div class="tab">
                                <input type="checkbox">
                                <label><span>Tab 1</span></label>
                                <div class="tab-content"><p>Should the pace attack?</p></div>
                            </div>
                            <div class="tab">
                                <input type="checkbox">
                                <label><span>Tab 2</span></label>
                                <div class="tab-content"><p>Some other Text</p></div>
                            </div>
                        </div>

编辑: 抱歉没有回答原问题,但我正在工作,我认为原则是清楚的,对吧?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接