假设在一个表单中,您需要允许用户选择一个唯一的选项。 这可以使用下拉菜单或一组单选按钮来实现。 现在,假设每个选项都有一个直接的后续问题。 例如,一个科学液体的订购表格。 它有盎司、杯或品脱,一旦选择,就需要指定要订购的盎司、杯或品脱数量。 这是一个有趣的、可以使用多种方式实现的设计模式。
为了实现深度的浏览器兼容性,您可能需要使用一些 JavaScript 来隐藏/显示特定的表单元素。 但为了好玩,让我们只使用 CSS 来实现。
单选按钮和数字输入都在标签内
对于每个唯一选项,我们将使用标签包装单选按钮、标签本身的文本和数量的数字输入。
<label for="oz">
<input type="radio" name="choice" value="oz" id="oz" data-label="Ozs">
Ounces
<input type="number" name="oz-val">
</label>
默认情况下隐藏数字输入
因为单选按钮和数字输入现在是相邻兄弟元素,所以我们可以使用 相邻兄弟选择器 来专门针对这些输入,并默认隐藏它们。
input[type='radio'] + input[type='number'] {
display: none;
}
单选按钮被选中时显示输入
我们可以使用几乎相同的选择器来显示单选按钮被选中时的数字输入,只需将 伪类选择器 :checked 附加到单选按钮上。 然后我们将它定位到右侧。
input[type='radio']:checked + input[type='number'] {
display: inline; /* unhide */
float: right;
margin-right: 20px; /* space for "label" */
width: 100px;
}
“标记”数字输入
为了更明确地说明我们使用这些数字输入请求的内容,我们可以在输入附近应用文本。 请注意单选按钮上的“data-label”属性,我们将捕捉它并将其放入伪元素文本中。
input[type='radio']:after {
position: absolute;
right: 9px;
top: 9px;
}
input[data-label]:checked:after {
content: attr(data-label);
}
突出显示整个选定选项/值
为了非常直观地显示我们选择了哪个选项,以及该选项与数量值是如何配合的,我们将应用一个突出显示的行来覆盖这两个区域。
input[type='radio']:checked:before {
background: #ebdcad;
content: "";
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
border-radius: 8px;
z-index: -1;
}
可访问性? 浏览器兼容性?
订购表格是那些非常重要的事情,您需要尽可能地提高可访问性和浏览器兼容性。 这只是一个有趣、可能会在将来派上用场的 CSS 练习,但可能稍微超前了。
从可访问性的角度来看,它可能没问题。 对未使用的输入使用 display: none 是可以的,因为我们实际上希望它们在进行选择之前隐藏,但我不知道它们是否会明显地显示出来。 如果有谁想代表可访问性专家在评论区发言,我非常乐意听到。
浏览器兼容性更棘手。 为了使其正常工作,浏览器需要支持相邻兄弟选择器,而这我们只讨论到 IE 8+。 尽管如果该选择器失败,所有数字输入都会显示出来,这并不算什么大问题。 您需要将样式转移到不使用“+”的选择器中。 字段突出显示和伪标记需要伪元素,因此它也有 自身的兼容性问题。 最后但同样重要的是,伪元素在单选按钮元素上是否允许使用并不明确。 输入是“无内容”样式元素(它们自闭合,例如 img 元素)。 Opera 和 WebKit 恰好支持它,但目前还不清楚它们是否应该支持。 Firefox 不支持,因此您在该浏览器中将看不到突出显示或标记。
如果您需要一个 100% 万无一失的解决方案,您可以使用 Wufoo 表单,并使用 字段规则 来隐藏/显示其他字段。
完成
感谢 Bradley Staples 发送电子邮件关于这个想法。
很好的例子和教程,但这经过验证了吗? 我的意思是标签里面的输入... :))
是的。
实际上,它没有通过验证,因为每个标签中有多个输入,规范只允许一个。
这种技术似乎在 Firefox 4.0.1 中不起作用。
当您尝试点击文本输入以在其中输入时,它不允许您这样做。 相反,它只是再次点击了单选按钮。
FF 4 的问题是它们实现了一个系统,其中点击标签会选中它所关联的元素。 双击输入可以选中它,但这并不是很实用。 为了解决这个问题,您可以简单地从标签中删除 for 属性。 如果你想保留通过点击标签文本来选中单选按钮的功能,你可以将两个输入都移到标签外面,然后重新定位。
在 IE8 中不起作用。
这是一个具有改进 HTML 的版本,应该具有更深层的支持。
http://jsfiddle.net/chriscoyier/3YdN4/7/
不再有双重嵌套的输入和规则过滤器来阻止旧版 IE 搞砸。
@Ryan King
这不是标签 + for 属性的作用吗? 点击标签 => 选中(或聚焦)在 for 属性中提到的输入?
@Peter 是的,这正是标签中 for 属性的作用,这就是为什么我建议将数字输入移到标签外面而不是删除 for 属性(如果你仍然希望通过点击文本选中单选按钮)。 也许我应该更清楚地说明我的回复。 一个更好的解释是,点击数字输入(当它在标签内时)会触发对输入的点击,然后操作冒泡到标签,触发对标签的点击,然后触发对单选按钮的聚焦。 显然,FF4 是唯一允许传播(或至少识别它)的浏览器。
我想在一个标签中有多个输入是无效的 ;-)。
谈论可用性,我认为将复选框的可点击区域做得更宽是可以的。 为什么不把它做成和它们所在的有色框一样大呢?
一个针对常见问题的有趣的设计模式。 特别是如果您有足够的空间可以工作。
兄弟选择器在 IE7 上也有效:http://msdn.microsoft.com/en-us/library/cc351024%28VS.85%29.aspx#combinators
不幸的是,在 IE<9 中,无法通过 CSS 判断一个单选按钮是否被选中,但 JS 团队可以介入,为选中的单选按钮添加一个类名。
但使用 CSS 进行一些基本的分支逻辑是一个非常棒的想法。
如果你只能选择一个选项,为什么还要使用单选按钮?使用下拉菜单并节省大量空间不是更好吗?你还在重复显示度量单位,浪费了额外的空间。
如果用户决定更改第一个输入,他将不得不重新进行第二个输入。你可以通过自动转换为另一个度量单位或第一个选项来提高可用性。
单选按钮:1 次查看,1 次点击
下拉菜单:1 次点击,查看列表,再点击一次
它更友好。
那么你会用单选按钮做什么呢?
我尽量避免使用单选按钮,除非我确实能承受浪费空间。在这里它可以工作,因为只有 3 个选项,并且只有一组按钮。如果你有多个组,每个组至少有 5 个选项,你的页面很快就会变成一个滚动页面。
大多数带有单选按钮的表单不会像这里一样突出显示选中的选项。如果你想在填写完整个表单后查看你的选择,这真的让人头疼。
我不撒谎,我对 CSS 还很陌生,但每次我访问你的博客时,我都会学到一些新的东西,想尝试一下——这里有一些新的东西可以添加到我的学习列表里。
我发现了一些怪癖
如果你使用按钮来增加或减少值,而它仍然是空白的,它会跳到 +/- 1.7 左右(是 e 还是其他特殊常数?)。如果你输入一个值,那么按钮就会正常工作,按整数递增。
如果输入字段处于活动状态(带有闪烁的光标),你无法选择另一个单选按钮。我假设这是因为输入字段还没有“释放”来隐藏。一旦你点击输入字段之外,就可以正常选择另一个单选按钮。
即使你切换到另一个单选按钮然后返回,输入字段的值也会被记住。这会影响表单提交时发送的数据吗?我对 GET 或 POST 这样的东西了解不够,但似乎你必须在服务器端添加一些额外的逻辑,以确保只使用与选中的单选按钮匹配的值,以防用户改变主意并在另一个输入字段中输入数据。
我正在使用 Mac 版 Reeder 的 Beta 版,我假设它只是使用了一个 webkit 视图,但如果不是这样,任何 CSS 可用性问题可能就不是那么重要了。
我真的很喜欢它,即使它还没有准备好投入生产。
奇怪的数字旋转器问题与 Safari 5.0.x 的一个错误有关(http://wufoo.com/html5/types/7-number.html)。
是的,似乎有点小问题。我认为解决方案需要将数字输入从标签中提取出来。也许吧。
是的,未使用的数字值(如果已填写)将与表单一起提交,你需要检查单选按钮组的值,只对相关数字输入值做任何操作。这有点像处理表单的程序员的责任。
太棒了!
我得喜欢这个聊天框,哈哈。
我喜欢你博客中所有这些巧妙的小技巧,Chris,尽管看到像这样很棒的技巧没有被很多浏览器支持,我确实感到很难过,哈哈。
为了验证你的代码,你不能将第二个
input
从label
中移出,并使用 ~ 兄妹选择器来定位它吗?我还会使用 JS 来实现网页可访问性(屏幕阅读器),除了“深度浏览器兼容性”之外,这也是在 JS 中进行的原因。我会去掉 CSS 中的 display:none;,只操作 DOM 来隐藏未选中的单选输入的背景和下拉菜单对。这样,能够解释 JS 的人和浏览器仍然可以获得流畅的交互,而交互不会成为普遍访问的障碍;换句话说,渐进增强。