玩转 HTML5 Placeholder
Placeholder(占位符) 是 HTML5 新增的一个 HTML 属性,用来对可输入字段的期望值提供提示信息,目前已经得到主流浏览器的广泛支持,使用方式非常简单:
<input id="username" name="username" placeholder="请输入用户名" type="text">
该属性适用于 <textarea> 多行文本框和 type 属性值为 text, password, search, tel, url 或者 email 等的 <input>。

自定义样式
如果想改变 placeholder 的默认呈现样式,应该使用 ::placeholder 伪元素选择器,不过当前还没有浏览器支持,因此只能根据不同浏览器的不同实现方式分别定义:
::-webkit-input-placeholder { /* Chrome/Safari/Opera */
color: green;
}
::-moz-placeholder { /* Firefox 19+ */
color: green;
}
:-ms-input-placeholder { /* IE 10+ 注意这里只有一个冒号 */
color: green;
}
为什么样式要分别定义呢,如果像下面这样组合到一起:
::-webkit-input-placeholder,
::-moz-placeholder {
color: green;
}
不应该把针对不同浏览器的选择器写在一起,这样写会因为无法识别的选择器而造成这整个规则集被忽略(当然,像类似 IE 7 这种具有超强错误处理能力的浏览器除外,不过这里和 IE 7 没什么关系)。
Firefox 定义方式的改变
如果需要兼容老版本的 Firefox 浏览器,还需要添加下面这种只有一个冒号的样式规则:
:-moz-placeholder { /* Firefox 4 - 18 */
color: green;
}
因为从 Firefox 19 开始一个冒号的伪类定义方式 :-moz-placeholder 被废弃了,切换为两个冒号的伪元素定义方式。与此同时,它还添加了一个默认的 opacity: 0.54 不透明度样式,如果需要,可以覆盖掉该样式,否则文字是半透明的:
::-moz-placeholder {
color: green;
opacity: 1;
}
伪类和伪元素
伪类和伪元素有什么区别呢?伪类可以理解为给某个元素添加了一个类,比如 :first-child 伪类,选择第一个子元素:
p:first-child {
font-size: 16px;
}
也可以理解为元素当前的状态,同样也可以通过添加一个真正的 class 来实现类似效果:
p.first-child {
font-size: 16px;
}
无论是伪类还是真正的类,样式都是直接添加到 <p> 元素上的。
而伪元素可以理解为添加了一个虚拟的元素。比如 p:before 伪元素,可以像下面这个伪代码这样理解:
<before>p:before</before>
<p>paragraph</p>
这里 <p> 元素和 p:before 可以理解为是两个不同的元素。如果被绕晕了,没关系,毕竟这不是本文的重点,更多伪元素与伪类的信息可以参考 Pseudo-classes - CSS | MDN 和 Pseudo-elements - CSS | MDN
关于伪类选择器引发的问题
因为 IE 浏览器使用的是伪类 :-ms-input-placeholder 选择器来定义 placeholder 的样式,实际上样式是作用于文本输入框的,如果另外还有针对文本输入框的选择器特殊性更高的样式规则,将会覆盖掉该样式,参考下面代码:
input:-ms-input-placeholder { /* 0, 0, 1, 1 */
color: green;
}
#username { /* 0, 1, 0, 0 */
color: blue;
}
注释中的数字用来表示该选择器的特殊性。
上面两个样式规则当中使用 ID 选择器的特殊性更高,所以在 IE 10/11 中测试会看到 placeholder 显示为蓝色,与期望的有点不一样。同样使用伪类选择器的旧版本 Firefox 也会出现这个问题,因此,在书写样式的时候需要特别注意,实在搞不定,别忘了还有 !important 规则可以用。其它使用两个冒号的伪元素选择器的浏览器不会出现这个问题,例如:
input::-webkit-input-placeholder { /* 0, 0, 0, 2 */
color: green;
}
#username { /* 0, 1, 0, 0 */
color: blue;
}
上面两个样式规则互相之间不会影响,使用 Chrome 测试 placeholder 的颜色为绿色。
关于选择器的特殊性可以参考拙作CSS选择器特殊性与重要性。
让行为保持一致
虽然样式是可以自定义了,不过在行为上还有些差异,在 Chrome 和 Firefox 中当文本输入框输入内容时 placeholder 才会消失,清除内容时又会显示出来;而在 IE 中则是当文本输入框获取焦点时 placeholder 就消失了,失去焦点同时没有输入内容时才会重新显示。如果希望在 Chrome 和 Firefox 等浏览器中实现获取焦点就消失的效果,可以借助 :focus 伪类选择器来将 placeholder 的文本颜色设置为透明:
:focus::-webkit-input-placeholder {
color: transparent;
}
当文本输入框获取焦点时,placeholder 的颜色被设置为透明,感官上就好像消失一样。
JavaScript
获取或者修改 placeholder 的内容直接获取或者修改对应文本输入框的 placeholder 属性的值就行了:
$('input').attr('placeholder', 'Please enter your name');
So easy,妈妈再也不用担心我写代码了。不过,想要像普通 DOM 元素那样通过 javaScript 获取伪元素对象直接操作估计很难,目前可以使用 window.getComputedStyle() 方法来得到其样式属性,该方法的第二个参数是一个伪元素:
window.getComputedStyle(document.getElementById('username'),
'::-moz-placeholder').getPropertyValue('color'); // "rgb(0, 255, 0)"
如果要通过 JavaScript 来修改 placeholder 伪元素的样式的话比较好的一种方式是预先定义好几种不同的样式:
.style-1::-moz-placeholder {
color: green;
}
.style-2::-moz-placeholder {
color: red;
}
然后通过切换文本输入框的 class 属性来实现修改样式的目的:
$('input').addClass('style-2').removeClass('style-1');
另外也可以通过直接添加样式规则来实现。
Polyfill
对于不支持该属性的浏览器,会简单地忽略掉。原则上,placeholder 仅仅是用来对期望的输入起个提示的作用,对于不支持的浏览器在可用性上不受任何影响。如果需要兼容,那么应该使用特性检测的方式,针对不支持的浏览器使用 Polyfill,对于支持的浏览器来说,原生的当然是最好。
判断浏览器是否支持 <input> 元素的 placeholder 属性,可以引入 Modernizr 库来判断:
if (!Modernizr.input.placeholder) {
// 做点什么事
}
也可以自己写判断,简单易行的办法就是生成一个 <input> 元素对象,并判断该元素对象是否具有 placeholder 属性:
'placeholder' in document.createElement('input')
同理,对于 <textarea> 元素也是一样:
'placeholder' in document.createElement('textarea')
另外,Opera Mini 明明不支持 placeholder 属性,却装成自己很懂的样子。这时候可以使用客户端检测技术来将之排除掉,Opera Mini 的 window 对象包含一个 operamini 对象:
({}).toString.call(window.operamini) === '[object OperaMini]'
结合起来就是这样:
if (!('placeholder' in document.createElement('input'))
|| ({}).toString.call(window.operamini) === '[object OperaMini]') {
// 做点什么事
}
在编写 Polyfill 的时候应该尽量与原生功能保持一致,我这里选择向 IE 的方式看齐,即当文本输入框获取或失去焦点的时候处理 placeholder 是否显示,将文本输入框的 value 值设置为 placeholder 的值来模拟显示 placeholder 的状态。再添加上事件处理程序,当文本输入框获取焦点时如果 value 的值为 placeholder 则清空文本输入框;当文本输入框失去焦点时如果 value 值为空则将 placeholder 的内容赋给它,同时当 placeholder 显示的时候应该给文本输入框添加一个 class="placeholder" 用来设置样式以区别是显示的 placeholder 和还是显示的普通 value:
// 做点什么事
$('input[placeholder]').on('focus', function() {
var $this = $(this);
if (this.value === $this.attr('placeholder') && $this.hasClass('placeholder')) {
this.value = '';
$this.removeClass('placeholder');
}
}).on('blur', function() {
var $this = $(this);
if (this.value === '') {
$this.addClass('placeholder');
this.value = $this.attr('placeholder');
}
});
这只是一个简单的模拟实现,实际上还有很多需要处理的情况。
处理密码输入框
如果需要处理 placeholder 的是个密码输入框,它的 value 值会显示为圆点之类的字符,呈现几个莫名其妙的圆点来作为 placeholder 提示恐怕不妥,因此需要特殊对待一下,将密码输入框拷贝一份出来然后修改其 type 属性为 'text' 来替代显示 placeholder,并把原本的密码输入框隐藏:
$('input[placeholder]').on('blur', function() {
var $this = $(this);
var $replacement;
if (this.value === '') { // 失去焦点时值为空则显示 placeholder
if (this.type === 'password') {
$replacement = $this.clone().attr('type', 'text');
$replacement.data('placeholder-password', $this);
// 替代显示的文本输入框获取焦点时将它删掉,并且重新显示原来的密码输入框
$replacement.on('focus', function() {
$(this).data('placeholder-password').show().focus();
$(this).remove();
});
$this.after($replacement).hide();
$this = $replacement;
}
$this.addClass('placeholder');
$this[0].value = $this.attr('placeholder');
}
});
对于 IE 8 来说它不支持修改 input 元素的 type 属性,使用 jQuery 的 .attr() 方法来修改的话只会默默地失败。此时,可以新建一个文本输入框,然后把密码输入框上的属性赋给这个新建的文本输入框:
try {
$replacement = $this.clone().prop('type', 'text'); // 使用 .prop() 方法在 IE 8 下会报错
} catch(e) {
$replacement = $('<input>').attr({
'type': 'text',
'class': this.className // 还可以赋予 id, name 等属性
});
}
需要注意的是 id 和 name 属性不要重复了,可以先用一个变量保存下来,再用 .removeAttr() 方法来删除属性。
处理表单提交
当表单提交的时候应该将那些正在显示 placeholder 的文本输入框过滤掉,毕竟没有必要将那些没有用的数据提交给服务器,在提交时候将那些文本输入框的 value 值设为空,提交之后再恢复成显示 placeholder 的状态:
$(document).on('submit', 'form', function() {
var $input = $('.placeholder', this);
$input.each(function() {
this.value = '';
});
setTimeout(function() {
$input.each(function() {
this.value = $(this).attr('placeholder');
});
}, 10);
});
离开页面时
当用户离开页面时也需要清空正在显示 placeholder 的文本输入框,防止浏览器记住文本输入框当前的值,这里可以给 window 对象绑定一个 beforeunload 事件来处理:
$(window).on('beforeunload', function() {
$('.placeholder').each(function() {
this.value = '';
});
});
另外还需要考虑的问题:
- 使用代码给一个文本输入框赋值时,应该同时处理 placeholder 的状态。
- 使用代码获取一个正在显示 placeholder 的文本输入框的值的时候应该得到的是一个空字符串。
如此多的问题也就是说无论 Polyfill 写到如何极致,都很难与原生的功能相提并论,因此推荐的方式使用特性检测技术仅针对不支持的浏览器做 Polyfill,而 Polyfill 的功能应尽可能地向原生功能看齐。
总结
将所有样式总结起来:
input::-webkit-input-placeholder,
textarea::-webkit-input-placeholder {
color: #999;
}
input::-moz-placeholder,
textarea::-moz-placeholder {
color: #999;
opacity: 1;
}
input:-ms-input-placeholder,
textarea:-ms-input-placeholder {
color: #999;
}
.placeholder {
color: #999;
}
input:focus::-webkit-input-placeholder,
textarea:focus::-webkit-input-placeholder {
color: transparent;
}
input:focus::-moz-placeholder,
textarea:focus::-moz-placeholder {
color: transparent;
}
Polyfill 可以直接使用这个 jQuery 插件 mathiasbynens/jquery-placeholder,已经相当完善了。
参考资料
- Can I Use
- Style Placeholder Text | CSS-Tricks
- Bug 737786 - Switch from :-moz-placeholder to ::-moz-placeholder (pseudo-class to pseudo-element)
- Pseudo-elements
玩转 HTML5 Placeholder的更多相关文章
- html5 placeholder ie 不兼容问题 解决方案
解决HTML5 placeholder的方案 来源: 时间:2013-09-05 20:06:49 阅读数:11375 分享到: 0 [导读] 使低版本浏览器支持Placeholder有很多方 ...
- IE8 不支持html5 placeholder的解决方案
IE8不支持html5 placeholder的解决方法. /** * jQuery EnPlaceholder plug * version 1.0 2014.07.01戈志刚 * by Frans ...
- 玩转HTML5移动页面
(1) 动画雪碧图涉及的动画十分多,用的元素也十分多,请务必使用雪碧图(Sprite)!网上的工具有一些可以帮助你生成雪碧图的工具,例如CssGaga,GoPng等等,自动化构建工具Grunt和Gul ...
- 玩转HTML5移动页面(动效篇)(转载)
本文转载自: 玩转HTML5移动页面(动效篇)
- Cross-Browser HTML5 Placeholder Text
One of the nice enhancement in HTML5 web form is being able to add placeholder text to input fields. ...
- 玩转HTML5移动页面(优化篇)
原文:http://www.grycheng.com/?p=472 承接上文<玩转HTML5移动页面(动效篇)>,上次说的是让页面动起来的一些小技巧.而页面动起来的根基是功能可用的页面,因 ...
- 玩转HTML5移动页面(动效篇)
原文:http://www.grycheng.com/?p=458 作为一名前端,在拿到设计稿时你有两种选择: 1.快速输出静态页面 2.加上高级大气上档次狂拽炫酷屌炸天的动画让页面动起来 作为一个有 ...
- (转)html5 Placeholder属性兼容IE6、7方法
使低版本浏览器支持Placeholder有很多方法,都不是很完美,或多或少有点问题,且有些原生支持的浏览器在获得焦点时会清空Placeholder提示.发现zhihu的解决方法不错,特记录下 wind ...
- HTML5 placeholder(空白提示) 属性
原文地址:HTML5′s placeholder Attribute 演示地址: placeholder演示 原文日期: 2010年08月09日 翻译日期: 2013年8月6日 浏览器引入了许多的HT ...
随机推荐
- 使用 CSS3 动画实现的 3D 图片过渡特效
这是一个基于 CSS3 动画实现的图片过渡效果,共有 Flip.Rotation.Multi-flip.Cube.Unfold 等6种效果,它们将证明 CSS3 Transform 和 Transit ...
- Elasticsearch 连接查询
在一般的关系型数据库中,都支持连接操作. 在ES这种分布式方案中进行连接操作,代价是十分昂贵的. 不过ES也提供了相类似的操作,支持水平任意扩展,实现连接的效果. 其他内容,参考Elasticsear ...
- SQL Server安全(6/11):执行上下文与代码签名(Execution Context and Code Signing)
在保密你的服务器和数据,防备当前复杂的攻击,SQL Server有你需要的一切.但在你能有效使用这些安全功能前,你需要理解你面对的威胁和一些基本的安全概念.这篇文章提供了基础,因此你可以对SQL Se ...
- 一对多关系domain Model中设置使用AutoMapper时出错
在使用AutoMapper时,把数据从VO-PO时显示如下错误,错误提示说在一对多关系中已将集合设置为EntityCollection,那么这个是为什么呢. 看下action中的代码,我们可以发现这是 ...
- 常用的 SQL语句------CRUD
复习之前课本上的sql语句,以前上课的时候都是老师在上面讲,我们在下面玩,根本没有把这个放在心上,等到考试的时候临时学习突击下,就可以顺利过60了,但是现在不行了,自己要重新的学习sql,应该把里面最 ...
- 初探Spring - IOC原理
一.IOC是什么 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来降低代码之间的耦合度.其中最常见的方式叫做依赖注入(Dependency ...
- 基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览
在博客园很多文章里面,曾经有一些介绍Office文档预览查看操作的,有些通过转为PDF进行查看,有些通过把它转换为Flash进行查看,但是过程都是曲线救国,真正能够简洁方便的实现Office文档的预览 ...
- 载入条LoadingBar
这个控件太傻瓜了,只搁在博客里算了.日前需要用到一个载入条, 但不想找GIF图片,.NET里面没有提供这个控件,只有ProgressBar.自己写吧!要写也不难,就是周期性绘制一个长方形,让那个长方形 ...
- 关于EF的 序列化类型为“XXX”的对象时检测到循环引用。
在用Ef的时候,也许经常会遇到循环引用的错误. 下面提供解决办法.(不是Json.Net,如果是Json.Net可以给导航属性通过增加特性标签来解决该问题) ef大多数问题,可以通过ToList()来 ...
- MySQL中select * for update锁表的范围
MySQL中select * for update锁表的问题 由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执行Row lock (只锁住被选取的资料例 ...