CSS 中有一个 :checked
伪类。我经常将其与 “复选框技巧” 联系起来,在这种技巧中,您将其用于带有 ~ 通用同级组合器的隐藏复选框,以模拟切换行为,而无需任何 JavaScript。这是一种技巧,因为现在您在页面上有了这些无关的表单元素,这些元素实际上并不属于表单。这不是什么大问题,我相信您可以通过辅助功能解决它,但有一种方法可以在实际表单上以完全非技巧的方式使用相同的概念!
我在 CodePen 招聘表单 上使用了这种技术,仅在需要时显示其他表单字段。
让我们用一个演示来切入正题
查看 Chris Coyier 在 CodePen 上创作的笔 LEGXOK。(@chriscoyier)
HTML
假设我们在这里使用单选按钮。复选框或单选按钮都可以被“选中”(:checked)。我们要显示的 div 必须在它之后,并且是同级元素(在同一个父元素内)。
<input type="radio" name="choice-animals" id="choice-animals-dogs">
<label for="choice-animals-dogs">I like dogs more</label>
<div class="reveal-if-active">
Anything you want in here.
</div>
CSS
默认情况下,“reveal-if-active” div 将被隐藏。我们将通过多种不同的方式来实现这一点。它们并非全部都是隐藏它的必要条件,但它们将影响它如何显示自身。
.reveal-if-active {
opacity: 0;
max-height: 0;
overflow: hidden;
}
现在,当与其处于同一级别的单选按钮或复选框被选中时,它就会显示出来
input[type="radio"]:checked ~ .reveal-if-active,
input[type="checkbox"]:checked ~ .reveal-if-active {
opacity: 1;
max-height: 100px; /* little bit of a magic number :( */
overflow: visible;
}
这可以工作,但让我们以一种花哨的风格过渡一切,并使用 Sass 来增强它
.reveal-if-active {
opacity: 0;
max-height: 0;
overflow: hidden;
transform: scale(0.8);
transition: 0.5s;
input[type="radio"]:checked ~ &,
input[type="checkbox"]:checked ~ & {
opacity: 1;
max-height: 100px;
overflow: visible;
padding: 10px 20px;
transform: scale(1);
}
}
这就可以了。
必填字段怎么办?
这有点棘手。假设在“reveal-if-active” div 中,您放置了更多表单字段(这确实是重点)。如果字段显示,您可能希望将其设为必填,但如果未显示,则无需必填。隐藏的必填字段仍然是必填的,因此您不能只是在这些隐藏字段上添加 required
属性并忽略它,以免陷入糟糕的用户体验境地。
我通过在输入上添加“require-if-active” 类和一个 data-*
属性来处理此问题,该属性引用与其配对的 ID。
...
<div class="reveal-if-active">
<label for="which-dog">Good call. What's the name of your favorite dog?</label>
<input class="require-if-active" type="text" id="which-dog" name="which-dog" data-require-pair="#choice-animals-dogs">
</div>
然后,在页面加载时以及每次复选框或单选按钮的值发生变化时,您都会运行一些 JavaScript 来确定该输入是否应该为必填。
var FormStuff = {
init: function() {
// kick it off once, in case the radio is already checked when the page loads
this.applyConditionalRequired();
this.bindUIActions();
},
bindUIActions: function() {
// when a radio or checkbox changes value, click or otherwise
$("input[type='radio'], input[type='checkbox']").on("change", this.applyConditionalRequired);
},
applyConditionalRequired: function() {
// find each input that may be hidden or not
$(".require-if-active").each(function() {
var el = $(this);
// find the pairing radio or checkbox
if ($(el.data("require-pair")).is(":checked")) {
// if its checked, the field should be required
el.prop("required", true);
} else {
// otherwise it should not
el.prop("required", false);
}
});
}
};
FormStuff.init();
是的,需要一点 JavaScript。我们也可以通过 JavaScript 来实现隐藏/显示,但 CSS 非常适合它。您甚至可以说这是一个设计问题,因此它属于 CSS。#辩论
奇怪的问题
Becca Rice 写信告诉我,显示其他字段的 CSS 东西存在一个错误,**尤其是在 iOS 9 及更早版本上的 UI WebView 中。**不是 Safari 本身,而是使用内置 WebView 在其自己的应用中显示网页的应用。即使在撰写本文时,iOS 上的整个 Chrome 应用也使用 UI WebView。
错误是:您可以点击一个单选按钮来展开其他字段。甚至可以点击另一个关闭原始字段并打开一组新的其他字段,但随后它停止工作了。您可以继续切换单选按钮,但不再有任何变化。目前尚不清楚单选按钮是否只是视觉上改变了状态,但实际上没有改变值,或者 CSS 是否没有对新的 :checked
值做出反应。
我们都确认了这一点。有一个 应用 专门用于测试 UI WebView 与 WK WebView。
非常有趣!哇!
将来我们是否能够在某个时候过渡到 height: auto 而不是必须使用 max-height 过渡到某个数字?有时使用 max-height 可能会很麻烦。根据您使用的数字,它可能会改变过渡的持续时间。
此外,这是一篇很棒的文章。我最近一直在处理这类事情。非常棒的方法。
我猜是的,我们最终将能够做到。可能就是这样,到
height: auto;
。CSS 规范人员认为这是一个合理的愿望,并且浏览器应该能够做到这一点。动态表单会让用户感到紧张。即使表单是多步骤表单,他们也需要知道接下来会发生什么。
在选项之间进行选择,然后根据他们选择的选项输入更多信息,这是大多数用户不喜欢的。
如果经过深思熟虑,它可以成为您网页中非常有吸引力的部分。
我使用它没有过渡,效果很好。在最终效果出来之前,我花了几小时,但这是值得的。
我的“r”怎么了?我的意思是“用户”
我真的很喜欢您对表单所做的事情,我只是在将它插入我的表单以发送电子邮件到 php 时遇到困难……您能帮我解决这个问题吗?
这些示例在 Android 4.4 webview 中有点损坏。
~ 不被称为“通用同级选择器”吗?
是的。谢谢。
嗨,Chris,
在我们公司,我们实际上是这样做的,而不是 JS 切换(我在 2 年前就禁止了)。与 JS 相比,需要注意一些关于此方法优势的重要事项
结合 WCAG 和 ARIA 规范/建议,您可以使这对于有可访问性需求的用户更加自然。
核心功能无需 JS 即可工作,因此在我看来,它对浏览器的负担更轻(需要更多测试来证明这一点)
如果您在实现中小心谨慎,您实际上可以使用此后端做出决策,那么单选按钮/复选框就不会毫无用处,事实上,它比单独使用 JS 更有用。
有趣的是,我从未想过要为每个用例设计一个适合必填项的解决方案,但我真的很喜欢您使用 data 属性的方法。
最近一直困扰我的一件事是 DOM 与内容的比率以及这些 data 属性的传输。我会说为任何隐藏的元素的 onblur 实现一个回调,通过类实现;然后,您可以将闪存消息或页面通知挂钩到此处,以让用户知道某些内容是否为必填项且未填写(也许在某些实际可用性方面强制将焦点重新设置到该内容上),仅当他们退出框时(我知道很狡猾)。一种真正非常不干净的强制焦点实现方式,无需 JS,就是将复选框包装在一个标签中,其中 for=”id” 为隐藏输入字段的 id(强制焦点,点击其他位置强制模糊…)
无论如何,这只是我的想法,很棒的文章,希望您已经解决了 DB 问题的巨大托管费用!
不错 :-)
文章中没有提到的一点,但在你的 CodePen 演示中是正确的:隐藏的输入元素必须一开始就出现在 HTML 中,而不是由 JavaScript 动态添加。我多次看到一些 JavaScript 代码动态添加输入元素:结果是在浏览历史记录(后退/前进按钮)时,该输入元素会丢失。
我个人更喜欢使用 :not(:checked) 来简化隐藏操作。这样,在浏览器不支持 :checked 的极少数情况下,回退方案是显示过多的数据而不是过少的数据。此外,在我看来,当你不想与可能非常具体的、始终想要隐藏元素的选择器作斗争时,使用 :not(:checked) 进行样式设置更容易。
前几天我正好在处理这个问题。如果你禁用一个输入元素,它会覆盖
required
属性。概念证明:http://codepen.io/anon/pen/zxqxer 不输入任何值提交表单。第一个输入元素不会检查值,第二个会检查。基于此,我更倾向于在切换辅助输入元素时切换
disabled
属性,保持required
属性不变。这提供了两个有益的副作用。隐藏一个输入元素意味着你不想发送它的值(当然,
[type="hidden"]
不需要用户交互的除外)。在隐藏输入元素时禁用它,将阻止发送之前设置的任何值,即使它在可见时是必需的。你不需要添加额外的类或
data-
属性来跟踪哪些输入元素应该是必需的。如果它们已启用(可见),则遵循验证规则。否则,眼不见心不烦。使用 CSS 影响表单的动态行为?
这是一个好主意吗?
我一直认为 CSS 只用于为元素设置样式。
我看不出有什么问题。从远古时代起,我们就通过 :hover 伪元素来影响菜单的行为。
有趣的一点,我也想说 CSS 成为了一些脚本函数的半继承者,部分替代了 jQuery、Java 等。
我认为这很好,因为你可以专注于你正在处理的项目,而不是你如何完成它。
IMO,复选框技巧可能不再是技巧了。
一旦你开始使用这种方法,你就不想再用 JS 了。
它非常易于使用,你可以用它做出一些非常棒的东西。
我最近用这种方法创建了一个图片库。
是否可以将 reveal-if-active 显示在单选按钮选项下方?
现在结果必须正好位于单选按钮下方/旁边,然后是下一个单选按钮。
如果例如可以将 3 个单选按钮并排放置,并将 reveal-if-active 文本动态显示在这些按钮下方,那就太好了。
这可能吗?