十一国庆过得好快啊,8天,转瞬即逝,收假回来后,第一天没什么心情,还是分享点东西吧。入门表单技术知识走一波。
此文章针对新手,OK,废话不多说,GOOO。让我们学习如何仅使用HTML和CSS标记表单。
形成基本结构
从<form>
元素开始。
这里没什么好看的。仅介绍基本结构。
<form>
...</form>
如果要自然提交表单数据(即不使用JavaScript),则需要包括action
属性,其中的值是将表单数据发送到的URL。的值method
应为GET
或POST
取决于您要实现的目标(请勿使用发送敏感数据GET
)。
此外,还有一个较少使用的enctype
属性,它定义了要发送的数据的编码类型。同样,该target
属性(虽然不一定是表单唯一的属性)可以用于在新选项卡中显示输出。
基于JavaScript的表单不一定需要这些属性。
<form method="POST" action="/subscribe" enctype="application/x-www-form-urlencoded" target="_blank">
...</form>
表单由期望数据值的输入组成。
<form>
<input type="text"><!-- text input -->
<input type="text" value="Prefilled value"></form>
包括标签以提高可用性和可访问性
每个输入都需要一个标签。
标签是描述输入内容的文本描述符。有三种声明标签的方法,但是其中一种优于其他两种。现在让我们深入研究这些。
相邻标签
相邻标签需要最多的代码,因为我们需要显式声明标签描述的输入。在大多数情况下,这是违反直觉的,因为我们可以将输入包装在标签内,从而用更少的代码即可达到相同的效果。
话虽这么说,但在有情节的情况下,可能需要使用相邻的方法,因此如下所示:
<label for="firstName">First name</label><input id="firstName">
正如你可以从上面的例子看到,for
的属性<label>
必须匹配id
输入的属性,这样做是对的输入设备说明文字描述属于哪个输入端。然后,输入设备会将其中继给用户(例如,屏幕阅读器将通过语音指示输入)。
ARIA标签
尽管语义HTML更好,但ARIA(可访问的富Internet应用程序)标签可以在缺少标签时进行补偿。在这种情况下,这就是缺少实际HTML时标签的外观<label>
:
<input aria-label="First name">
不幸的是,这种方法的缺点是缺少视觉标签。但是,这对于某些标记可能很好(例如,带有标题和占位符的单输入形式):
<h1>Subscribe</h1><form>
<input aria-label="Email address" placeholder="bruce@wayneenterpris.es"></form>
(稍后我将解释什么是占位符。)
包装标签
将输入包装在标签内是最干净的方法。另外,由于CSS的支持:focus-within
,我们甚至可以在标签的子输入获得焦点时设置标签样式,但我们将在后面讨论。
<label>
First name<input></label>
占位符与标签
简要比较:
-
标签说明输入的期望
-
占位符显示上述期望的示例
占位符并不是用来代替标签的,尽管正如我们在上面的ARIA示例中看到的那样,它们可以添加一些在缺少可视标签的情况下丢失的上下文。
不过,理想情况下,我们应该同时使用:
<label>
First name<input placeholder="Bruce"></label>
选择输入类型
占位符仅适用于基于文本的输入,但实际上存在各种不同的输入类型,其中包括:
<input type="button"><input type="checkbox"><input type="color"><input type="date"><input type="datetime-local"><input type="email"><input type="file"><input type="hidden"> <!-- explained later --><input type="image"><input type="month"><input type="number"><input type="password"><input type="radio"><input type="range"><input type="reset"><input type="search"><input type="submit"> <!-- submits a form --><input type="tel"><input type="text"> <!-- the default --><input type="time"><input type="url"><input type="week">
语义输入类型在表单验证期间非常有用,尤其是在依赖本机验证时,我们将在稍后进行介绍。首先,让我们学习如何设置这些输入的样式。
样式输入 {#stylinginputs}
可以说,编码形式最令人生气的方面是覆盖了浏览器的默认样式。值得庆幸的是,appearance: none;
根据caniuse.com的消息,今天有96.06%的浏览器支持。
在使用以下CSS代码重置Web浏览器的默认样式之后,我们可以根据需要设置样式,甚至包括单选和复选框输入类型:
input {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
...}
但是,其中一些输入可能带有难以克服甚至无法克服的怪癖(取决于Web浏览器)。因此,如果许多开发人员type="text"
发现这些怪癖是不受欢迎的(例如,上的"插入符号" input type="number"
),则倾向于使用默认的attribute = value 。
然而,是一线希望...
指定一个 inputmode
{#specifyinganinputmode}
根据caniuse.com,Web浏览器支持82.3%的新inputmode
属性,无论type
使用什么输入,它都将在手持设备上显示哪种键盘布局。
总比没有好,对吗?
<input type="text" inputmode="none"> <!-- no keyboard -->
<input type="text" inputmode="text"> <!-- default keyboard -->
<input type="text" inputmode="decimal"><input type="text" inputmode="numeric">
<input type="text" inputmode="tel">
<input type="text" inputmode="search">
<input type="text" inputmode="email">
<input type="text" inputmode="url">
验证用户输入
如果您选择通过JavaScript解决方案进行本机HTML验证,请记住,inputmode
在这方面没有任何效果。inputmode="email"
不会验证电子邮件地址,而input type="email"
会验证。就是这样。
抛开这些,让我们讨论触发验证的原因:
<input required> <!-- value is required -->
<form required> <!-- all values are required -->
<!-- alternative input types --><input type="email">
<!-- blank or a valid email address --><input type="email" required> <!-- must be a valid address --><!-- text-based inputs --><input minlength="8"> <!-- blank or min 8 characters --><input maxlength="32"> <!-- blank or max 32 characters --><input maxlength="32" required> <!-- max 32 characters --><!-- numeric-based inputs --><input type="date" min="yyyy-mm-dd"> <!-- min date --><input type="number" max="66" required> <!-- max number -->
创建自定义规则
自定义规则要求了解RegExp
对象所使用的JavaScript正则表达式(但不能包含斜杠或引号)。以下是在一个规则中强制使用小写字符(a--z)和minlength / maxlength的示例:
<input pattern="[a-z]{8,12}">
注意:永远不要将前端验证(本地HTML或其他方式)用作服务器端验证的替代品!
设置有效/无效状态的样式
为了更加清晰,这是我们设置有效性的方式:
input:valid {
border-left: 1.5rem solid lime;}input:invalid {
border-left: 1.5rem solid crimson;}form:invalid {
/* this also works, technically! */}
输入尝试立即验证其值(或缺少值),因此以下代码(仅在输入保存值时显示有效/无效状态)可能会更好:
input:not(:placeholder-shown):valid {
border-left: 1.5rem solid lime;}
这将显示有效/无效的样式,但是仅在不显示占位符的情况下(因为用户键入了某些内容)。
其他基本事项
发送表格数据
将表单数据发送到服务器通常需要输入具有name
属性。这也适用于隐藏的输入:
<input type="email" name="email"><input type="hidden" name="email" value="{{ user.email }}">
接受长格式输入
本质上,<textarea></textarea>
与相同<input type="text">
,只是textarea具有多行支持。是的,<input type="textarea">
肯定会更直观,但是a<textarea></textarea>
是接受用户的长格式输入的正确方法。另外,它接受输入所做的大部分(如果不是全部)属性。
分组输入以获得更好的可访问性
尽管较短的表格提供了更好的用户体验,但有时不可避免的是较长的表格。在这种情况下,该<fieldset>
元素可用于包含相关输入,并使用一个子代<legend>
作为标题/标题<fieldset>
:
<fieldset>
<legend>Name</legend>
<input type="text" name="title">
<input type="text" name="firstName">
<input type="text" name="lastName"></fieldset><fieldset>
<legend>Contact details</legend>
<input type="email" name="email">
<input type="tel" name="homePhone">
<input type="tel" name="mobilePhone"></fieldset>
DEMO:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Form</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Rubik:400,700">
<style type="text/css">
* {
margin: 0;
font-family: Rubik;
color: rgb(255 255 255);
-webkit-font-smoothing: antialiased;
}
html {
font-size: 62.5%;
}
body {
display: flex;
min-height: 100vh;
place-items: center;
place-content: center;
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:svgjs='http://svgjs.com/svgjs' width='1440' height='560' preserveAspectRatio='none' viewBox='0 0 1440 560'%3e%3cg mask='url(%26quot%3b%23SvgjsMask1001%26quot%3b)' fill='none'%3e%3crect width='1440' height='560' x='0' y='0' fill='rgba(94%2c 25%2c 230%2c 1)'%3e%3c/rect%3e%3cpath d='M0%2c621.649C113.342%2c603.155%2c203.835%2c529.574%2c299.667%2c466.291C394.245%2c403.837%2c500.562%2c352.715%2c556.518%2c254.153C614.871%2c151.37%2c619.785%2c29.716%2c614.558%2c-88.36C608.879%2c-216.639%2c623.579%2c-372.594%2c525.124%2c-455.023C424.919%2c-538.917%2c269.998%2c-457.102%2c142.092%2c-483.92C28.831%2c-507.667%2c-64.735%2c-630.984%2c-176.822%2c-602.199C-288.639%2c-573.484%2c-326.761%2c-435.738%2c-398.312%2c-345.14C-466.069%2c-259.345%2c-548.911%2c-187.119%2c-585.884%2c-84.237C-628.65%2c34.765%2c-664.248%2c165.208%2c-624.903%2c285.384C-584.01%2c410.289%2c-485.615%2c513.262%2c-369.878%2c575.541C-258.205%2c635.633%2c-125.16%2c642.071%2c0%2c621.649' fill='%234b14b8'%3e%3c/path%3e%3cpath d='M1440 997.543C1528.486 1013.7919999999999 1636.257 1029.5140000000001 1702.893 969.0699999999999 1770.647 907.6120000000001 1734.792 794.21 1760.837 706.521 1782.1109999999999 634.894 1836.342 576.806 1841.541 502.267 1847.517 416.595 1842.002 324.75800000000004 1792.353 254.68400000000003 1741.0059999999999 182.21499999999997 1657.028 134.34199999999998 1569.635 118.505 1486.104 103.368 1407.938 149.781 1325.511 170.086 1238.53 191.51299999999998 1120.201 165.611 1071.969 241.099 1021.9110000000001 319.446 1106.002 419.15 1106.976 512.118 1107.745 585.508 1053.484 656.246 1077.048 725.754 1101.186 796.958 1172.4270000000001 837.643 1232.608 882.7080000000001 1297.167 931.052 1360.672 982.976 1440 997.543' fill='%237e47eb'%3e%3c/path%3e%3c/g%3e%3cdefs%3e%3cmask id='SvgjsMask1001'%3e%3crect width='1440' height='560' fill='white'%3e%3c/rect%3e%3c/mask%3e%3c/defs%3e%3c/svg%3e");
background-size: cover;
}
section {
width: 100%;
max-width: 44rem;
}
h1 {
font-size: 2.125rem;
margin-bottom: 4rem;
}
* :not(h1) {
font-size: 1.6rem;
}
form,
label {
display: grid;
grid-gap: 2rem;
}
label {
align-items: center;
grid-template-columns: auto 1fr;
}
input {
background: white;
color: rgb(7 2 18);
transition: all 200ms ease;
border-left: 0 solid transparent;
}
input:not(:placeholder-shown):valid {
border-left: 2rem solid rgb(31 132 87);
}
input:not(:placeholder-shown):invalid {
border-left: 2rem solid rgb(209 50 81);
}
input,
button {
border: 0;
height: 5.8rem;
padding: 0 calc(5.8rem * 0.5);
border-radius: calc(5.8rem * 0.3);
box-shadow: 0 0 2rem rgb(0, 0, 0, 20%);
}
button {
cursor: pointer;
background: rgb(7 2 18);
}
</style>
</head>
<body>
<section>
<h1>Subscribe</h1>
<form method="POST" action="/subscribe">
<label>
<span>Name</span><input type="text" name="Name" pattern="[A-zÀ-ž\s]{2,}" placeholder="Bruce Wayné">
</label>
<label>
<span>Email</span><input required type="email" name="Email" placeholder="bruce@wayneenterpris.es">
</label>
<button type="submit">Subscribe</button>
</form>
</section>
</body>
</html>
拓展 {#disablinginputs}
禁用输入
添加disabled
属性可以使输入(或任何可聚焦元素)失效,尽管通常可以通过JavaScript来应用/不应用。但是,这是它的工作方式:
<form disabled>...</form><fieldset disabled>...</fieldset><input type="submit" disabled>
以及随附的CSS(如果需要):
:enabled {
opacity: 1;}:disabled {
opacity: 0.5;}
但是,如果您要做的只是添加一个额外的视觉提示,提示用户的输入无效,则您很可能希望使用常规的同级组合器(〜)。以下代码基本上表示"在输入无效的任何元素之后的提交按钮"。这不会改变任何功能,但是当我们利用本机HTML表单验证(可自动处理禁用/启用提交功能)时,这很好:
:invalid ~ input[type=submit] {
opacity: 0.5;}
禁用输入,但仍然发送数据
的混合<input disabled>
和<input type="hidden">
,下面的例子将确保值不能被改变。区别在于,与值不同disabled
,readonly
值作为表单数据发送;不像hidden
,readonly
是可见的:
<input readonly value="Prefilled value">
改变增量
基于数字的输入具有"旋转按钮"来调整数值,并且它们还接受一个step
属性,该属性确定每次调整的替代增量值:
<input type="number" step="0.1" max="1">
重点关注表单,标签和字段集的样式
我们可以使用focus-within:
样式来设置当前获得焦点的输入的任何父级。最有可能的该元素将是输入的<form>
,<label>
或者<fieldset>
容器:
form:focus-within,
fieldset:focus-within,
label:focus-within {
...}
通过一个输入发送多个值
multiple
对文件和电子邮件输入类型有效:
<input multiple type="file"> <!-- multiple files --><input multiple type="email"> <!-- comma-separated emails -->
编写简写形式代码
如果表单仅由单数<button>
,<input type="image">
或组成<input type="submit">
,则有一种简便的方法来标记HTML表单。这是一个例子:
<input type="image" formaction formmethod formenctype formtarget>
与此相反:
<form action method enctype target>
<input type="image"></form>
总结
HTML比十年前更加直观。它在不断发展,毫无疑问,将在适当的时候在HTML / CSS表单主题上添加更多内容。我想到的一个例子是datalist元素,此元素目前可能有很多错误(尤其是在Firefox中)。除此之外,我有什么想念的吗?