harry

我曾想输入一个数字 | Filament Group, Inc., Boston, MA

harry · 2017-01-10翻译 · 937阅读 原文链接

表单是用户和网页交互的基础。在很长的一段时间中,表单控件稳定可靠变化不大。去年HTML5通过给表单控件添加属性给我们带来了一些更新。针对于最新的web特性和标准的测试结果证明了这些表单控件确实很不错:但浏览器对它们的实现不同。

在触摸设备上,这种浏览器的实现差异表现的很明显,特别是这种新特性与触摸屏的内置键盘有关联:它要根据input的模式去找到最好的输入方式。举例来说,当一个网站明确说明用户只能输入数字的时候,浏览器能弹出一个数字键盘(0到9),并且每个按钮都很大,大到能让用户更加简单快速并准确的输入数字。对于数字的输入,按钮大小的不同所导致的用户输入体验的差异是非常明显的。

type="text" 时,Android 6上显示的键盘 (三星 Galaxy S7)

type="number" 时,Android 6上显示的数字键盘 (三星 Galaxy S7)

然而浏览器是如何得知什么情况下该使用数字键盘呢?开发者又如何去让浏览器得知用户将要输入什么类型的数据呢?可想而知,浏览器间的差异就在于此。

在web表单中我们可能需要获取很多不同类型的数字,例如下面这些:

  1. 价格(有时是每三位用一个逗号分隔的整数,有时也需要负数)
  2. 邮政编码(在美国,邮编可能是0开头)
  3. 信用卡(非常长的数字)
  4. 信用卡安全码:CVV,CVC,CSC(可能0开头)
  5. 礼品券(格式各有不同)
  6. 年龄
  7. 年份
  8. 时间 (分和秒也可能0开头)
  9. 电话号码

你也许会这么想,对于上面的这些情况都用就好了。很不幸,这样想是不对的。

Let’s consult the Specification

让我们来看下规范怎么说

等等,回来!HTML5对于input type="number"的规范表明对于type控制器来说,任何类型的输入都是可接受的,所以让我们降一个维度来分析这个事情。

这个难题中最重要 的部分就是input的value属性,它必须是一个浮点数

浮点数由一个或多个0-9的字符组成,通常跟在多个0-9的数字和小数点后面。浮点数也可能会用-开头来表示负数。

为了简化,我省略掉了科学记数法的规则,通常我们也会尽量避免为用户展示这种记数方式(后面会解释为什么)

重要并且还为得到解决的事情是,遵循浮点数规范定义的值结合我们今天要讲的属性当你可能有用。引自W3关于HTML5表单规范的最新绿皮书):

input中type=number的状态并不适用于哪些只允许输入数字但没有严格限制数字的情况。举例来说,它并不适用于信用卡号码或者美国邮政编码。一个辨别你是否需要使用type=number的很简单的方法就是使用一个带有spinbox控制的input是否有意义(spinbox:即type=number时input右侧用来加减数字的上下箭头)。

这段话含糊不清给令人不解。分和秒这样的字段明显和规范是相反的。Spinbox也可用,但这些字段可能需要0开头。

从规范的说明中可以看出,type="number"是被设计用于价格,年龄和年份这样的数字的;type="tel"是用户电话号码的;type="text"适用于这之外的情况。这样,对于其他要输入数字的字段,默认只能使用type="text"使得用户只能使用键盘上小小的数字按钮,这是很不友好的。

type="text" 时 Android 6上的键盘 (三星 Galaxy S7)

下面的内容非常实用

有以下方法来使用带有大按钮的数字键盘,这些方法能用于现在的浏览器。

  • type="number"

  • pattern 属性 (iOS中才有)

  • type="tel"

type="number"

我们可以选择遵循规范或者在一大堆不同的设备中使用一个还可以的数字键盘,又或者我们可以探索其他方式来完成这项工作。在测试Android(包括Chrome和很老的Android浏览器), 火狐安卓版,和Windows Phone中发现,要想使用大按钮的数字键盘的唯一方式就是忽略W3C规范而使用type="number"

在你的浏览器上测试

type="number"

在相同的Android操作系统版本中,Android大按钮数字键盘实现大有不同,很多都没有正确地遵循负数和小数点这一规范。

没有浮点数: type="number" 时 Android 2.3 (三星 Galaxy S2)

像是用来输入电话号的: type="number" 时 Android 2.3 (Motorola Droid Razr)

没有负数标志: type="number" 时 Android 6 (三星 Galaxy S7)

对于资深web开发者来说,这并不稀奇,Firefox是最接近规范,最为可靠的,它的数字上小数点和负号都有。

看起来很赞: type="number" 时 Firefox 47 on Android 5.1.1 (Motorola Nexus 6)

type="number"时的键盘在Windows Phone上不支持负号

没有负号标志: type="number" 时 Windows Phone 8.1 (Lumia 930

在iOS上,这type=“number”键盘不同于type=“text”(它既有负号的键也有小数点键,虽然这样很好)但这并不是我们想要的大按钮。

小按钮: type="number" 时 iOS 9

pattern属性

在iOS(iPhone)上,当你给input的pattern属性添加为[0-0]*或者\d*的值时,它会显示大按钮的数字键盘。iOS(iPhone)不区分type属性值。它可以是textnumber等值。但如果pattern=“[0-9]”pattern=“d”,iOS(iPhone)将显示一个大按钮的数字键盘。

大按钮的数字键盘不会在iPad上显示。随着更多的人在iPad上最更多的事情,使用一个有效的pattern值,或者使用type=“tel”,或者使用type=“number”都会得到一个小按钮的数字键盘。

像是用来输入电话号的: type="text" pattern="[0-9]* 时 iOS 9 (on an iPhone)

需要注意的是,即使你写的正则表达式和[0-9]*或者\d*\等价,你也不会得到数字键盘,例如:[0123456789]*[0-9]{0,}[0123456789]{0,}

逻辑上来说,因为iOS(iPhone)的只将匹配数字的正则绑定在pattern属性上,所以负号键和小数点件在大按钮的数字键盘上根本不存在。重要的是,当大按钮数字显示键盘显示的时候,iOS(iPhone)不允许用户切换键盘类型,输入浮点数是不被允许的,pattern所允许的正则值明确定义的这一点。

在你的浏览器上试一下

type="text" pattern="[0-9]*"

需要注意的是,pattern属性对值要求很严格HTML5表单验证。这使得开发者要么使用小的数字键盘,要么仔细验证你的pattern属性的值会不会产生一个大按钮的键盘,如表示两位数字的正则表达式pattern=“[0-9] { 2 }”就不会使用数字键盘。

不幸的是,pattern这种hack只在iOS上有效。使用pattern属性时其他Web浏览器将显示默认键盘text,所以我们需要结合其他技术。幸运的是,综合patterntype="nubmer"将触发一个大按钮的数字键盘上的所有平台,目前为止,我们的讨论就到这里了。

在你的浏览器上试试

type="number" pattern="[0-9]*"

type="tel"

如果在其他比较自由的数字格式上使用type="number"会与规范背道而驰,对一个不是电话号码的input使用type="tel"是很糟糕的。即使在可以遇见的未来,我也不认为这是一种对type="number"很好的替代方式。

在你的浏览器上试试

type="tel"

这里有一个更好的方式

幸运的是,制作web标准的人也意识到了这个混乱并给了另一种可行的方法: inputmode属性InputMode可以直接指定要使用哪种类型的键盘,独立于type属性值。例如,在一个信用卡号码字段可以使用tpye="text"inputmode="numeric"一起解决问题。

在笔者写这篇文章的时候,inputmode什么浏览器都不支持的属性。这真是不幸,但它减轻很多与规范不匹配的用法。这将有助于针对Android,Firefox Android和Windows Phone,在type="number"时他们都显示大按钮的数字键盘。

边注:虽然inputmode="numeric"是很好的设计又解决了规范的一些问题,但它仍然缺乏一个非整数的规范。即使浏览器支持此功能的发展我们仍然不得不对于非整数使用不带有inputmodetype="text"来给用户呈现一个带有小数点按钮的键盘.

在你的浏览器上试试

type="text" inputmode="numeric"

虽然很局限但还是要使用啊

当我们探讨这个问题,它变得很清楚,如果我们想在大多数设备中提供一个有效的方式来输入数字,我们需要结合patterntype="number"。由于我们在更多的地方使用type="number",但规范可能会随时改变,我们需要时刻注意规范的变更。

我们已经试用过一个称为numeric-input的小工具,让我们能够使用大按键的数字键盘,而回避一些令人讨厌的bug。这是它做的:

限制只能输入数字

既然这个input是用来输入数字的,那么该numeric-input插件会在你输入或者粘贴的时候过滤掉任何非0-9的字符充。

注:这个过滤装置意味着"-"和"."字符会被过滤掉,所以负数浮点数不支持。尽管事实上,这些数字格式也最好不要使用数字键盘来输入,使用type="text"来输入。

支持0开头

Safari 6中,0开头被用于美国的邮编或分钟或秒钟中。例如,邮政编码将从“01234”改为“1234”。我们的插件简单地将type="number"切换为type="text",所以开头的0得以保留。幸运的是,这pattern这种hack仍能保证在旧的iOS中呈现大键盘。

防止大数字四舍五入

Firefox 桌面版中大于16未的数字会被四舍五入。例如:el.value = "9999999999999999"; 会渲染为 10000000000000000.这对于16未的信用卡号码来说是灾难,对此这个插件会在Firefox(桌面版)中将type="number"转成type="text"来解决这个bug。

支持 maxlength

如果我们想要输入一个特定的长度(例如5位数邮编),没有办法指定为原生的数字输入框指定maxLength="5"。当然,你可以添加一个max="99999"属性,但针对这种情况,插件也增加了对maxLength的支持。

移除了Spinners 和 箭头

大多数的桌面浏览器在渲染数字输入框的时候,都会在输入框的右边渲染一个非常小的向上的箭头和向下的箭头,可以使用键盘的上下键或者鼠标滚轮来辅助增加数值或者减小数值,这是非常好的特性。但在某些情况下,这非常有破坏性,比如当你输入信用卡时不小心点到了加数值的箭头。numeric-input包含了一个选项( data-numeric-input-nav-disabled属性)用来禁止在type="number"时显示辅助的上下箭头,只是简单的css隐藏了

Spinbox arrows on Chrome with type="number"

使用 numeric-input

使用numeric-input 插件非常简单:

`<input type="number" pattern="[0-9]*" data-numeric-input>`

这只是 formcore中的一小个使用示例,这在将来会添加更多特性。

在你的浏览器上试试

data-numeric-input

一些小忠告

不支持科学记数法

因为插件过滤了字母字符,所以e也被过滤了, 科学记数法 也就不支持. 在这种情况下需使用 type="text"

负数,非整数

如果字段需要负数浮点数numeric-input在这种情况下帮不到你很多,这种情况请使用type="text"

译者harry尚未开通打赏功能

相关文章