标签归档:UI

Inline Form Labels(2)

很多网站在填写表单的时候,都可以看到这样一种UI,input[type=text]里面有提示的文字,当鼠标点进去之后提示文字就消失了。关于这种UI,之前有写过文章介绍过http://www.zhoumingzhi.com/?p=182。在本文中主要是介绍以HTML 5的实现方式以及兼容方案。

一,HTML 5的实现方式

HTML 5的input元素引入了placeholder的属性,就是为了实现本文开头所说的效果,代码也很简单。

<input type="text" placeholder="请输入一些文字" />

二,对不支持HTML 5浏览器的兼容方案

对于不支持HTML 5的浏览器,上面的方法就不可行了。但是placeholder这个属性可以利用起来,结合JS实现想达到的效果。下面结合代码说明实现方法:

首先要用JS检测一下浏览器支不支持placeholder这个属性。

(function() {
	var tmp = document.createElement("input");
	window.supports = {
		// 检测input是否支持placeholder特性
		placeholder: "placeholder" in tmp
	}
})();

如果支持的话就什么也不做,浏览器会帮你实现这个效果。

如果不支持则要写段JS。为了方便说明用到了jQuery,代码如下:

// 绑定input的placeholder
function bindPlaceholder(input) {
	if(!window.supports.placeholder) {
		var jqInput = $(input),
			placeholder = jqInput.attr("placeholder");
		
		if(placeholder) {
			if(input.value == "") {
				input.value = placeholder; 
				$(input).addClass("placeholder");
			}
			jqInput.focus(function() {
				if(this.value == placeholder) {
					$(this).removeClass("placeholder");
					this.value = "";
				}
			}).blur(function() {
				if(this.value == "") {
					$(this).addClass("placeholder");
					this.value = placeholder;
				}
			});
		}
	}
}

上述代码中有个叫placeholder的CSS类,这个主要是让占位符的字体颜色变灰。CSS如下:

.placeholder {
	color: #a9a9a9;
}

实现上面的函数之后,就可以在页面初始化的时候调用了。

$("input[placeholder]").each(function() {
	bindPlaceholder(this);
});

三,结论

HTML 5中有很多很方便的特性,但是目前不是所有浏览器都支持,所以在用HTML 5的时候要考虑到兼容方案。

制作Google Reader风格的按钮

用了很久的Google Reader,发现它的按钮很好看(如下图),而且圆角和渐变效果的处理方式也值得学习一下。

一,实现圆角效果

这里的圆角是用border来模拟出来的,把图片放大之后就可以看到其中的奥秘。

分析一下,要实现这种效果,就得用两个div嵌套实现。

<div class="btn-outer">
	<div class="btn-inner">
		HELLO WORLD
	</div>
</div>

里面的div负责上下的边框,外面的div负责左右的边框,并且左右的边框分别往外扩张一个象素,用负边距可以实现这样的效果。为了实现自适应内容的宽度,这两个div必须浮动,CSS如下:

.btn-outer, .btn-inner {
	float: left;
	border-color: #ccc;
}
.btn-outer {
	border-width: 1px 0;
	border-style: solid none;
}
.btn-inner {
	margin: 0 -1px;
	border-width: 0 1px;
	border-style: none solid;
	position: relative;
}

.btn-inner里面的position: relative是为了修复IE6的BUG,如果不加这个,在IE6下面左右两个边框会消失掉。

二,实现渐变效果

圆角做好之后,接下来制作button的背景,这里的背景是个渐变的效果。Google的做法是加多一个div,并用这个div的背景色和下边框色来模拟渐变的效果。改动一下上面的HTML:

<div class="btn-outer">
	<div class="btn-inner">
		<div class="btn-top-shadow"></div>
		<div class="btn-content">HELLO WORLD</div>
	</div>
</div>

接下来改动CSS为:

.btn-outer, .btn-inner {
	float: left;
	border-color: #ccc;
}
.btn-outer {
	border-width: 1px 0;
	border-style: solid none;
}
.btn-inner {
	font-size: 24px;
	line-height: 1.4em;
	color: #333333;
	margin: 0 -1px;
	border-width: 0 1px;
	border-style: none solid;
	position: relative;			
	background: #E3E3E3;
	overflow: hidden;
}
.btn-top-shadow {				
	border-bottom: 0.1em solid #EEEEEE;
	height: 0.7em;
	width: 100%;
	background: #F9F9F9;
	position: absolute;
	overflow: hidden;
}
.btn-content {
	position: relative;
	padding: 0 4px;
}

其中.btn-inner和.btn-top-shadow的overflow: hidden是为了修复IE6的BUG。可以看出用.btn-inner和.btn-top-shadow的背景色,以及.btn-top-shadow的下边框色就可以实现出渐变。

DEMO

终极攻略——元素垂直居中

转载须写明出处,附带本文链接。文中提到的居中,如没有特别说明,均指垂直居中。

有的同学看到题目就会想:我把父元素设成display: table-cell; vertical-align: middle不就行了吗?很不幸,IE6下没有display: table-cell这个玩意,所以本攻略中一概不讨论上述方式实现的居中。本攻略中,要垂直居中的元素分以下三种情况:

  1. 块级元素
  2. 不可替换(non-replaced)的行元素
  3. 可替换(replaced)的行元素

如果上面说的概念不是很清楚,请参考一下w3的文档。

一,块级元素垂直居中。

因为是未知高度的块元素,通常来说没有办法用绝对定位的方式使它居中。最好的办法是把它变成行内块元素(display: inline-block),这样的话就变成了类似第三种情况:可替换的行元素垂直居中

二,不可替换的行元素垂直居中。

这种情况恐怕是最简单的了,比如:

<div style="height: 300px;line-height: 300px;">
  <span>我要垂直居中啊。</span>
</div>

只要把div的行高(line-height)设成高度(height)一样就可以了,span会自动补白(leading),占满div的高度,以达到垂直居中对齐的效果。这个方法对一行里有多个non-replaced inline elements的情况也是适用的。这里要注意,如果内容太长导致换行的话,这个方法就不适用了,碰到这种情况可以先把元素变为display: inline-block,然后再参考第三种情况:可替换的行元素垂直居中

三,可替换的行元素垂直居中。

如果出现这种情况:

<div style="height: 300px;line-height: 300px;">
  <span>我要垂直居中啊。</span>
  <span>我也要垂直居中。</span>
  <input type="text" />
</div>

上面的代码中,前两个span是不可替换元素,后面的input是可替换元素。在标准浏览器下看,一切正常,可是换到IE6下,情况就不同了,你会发现,这三个元素全都跑到上面去了。这是一个IE6的BUG,简单的说,如果一行中有某些可替换元素,那么IE6会把这一行上面的补白(half-leading)给去掉。如果你打算深入研究,请看http://www.positioniseverything.net/explorer/lineheightbug.html

方法一:

在上述情况下,如果你要兼容IE6,就不得不使用HACK,IE的CSS下面有个特殊的属性writing-mode,它可以改变流的书写方向,我们就用它来做这种垂直居中的事情。拿上面的例子来说,先给input加个容器(用行内元素,这样不会改变FF下的布局):

<div style="height: 300px;line-height: 300px;">
  <span>我要垂直居中啊。</span>
  <span>我也要垂直居中。</span>
  <span class="tmp"><input type="text" /></span>
</div>

然后针对IE6写HACK:

<!--[if IE 6]>
<style type="text/css">
  div .tmp {
    /* 这里的height要和外层容器的行高一致,
       如果内容只有一行的话,可以直接用height: 100% */
    height: 100%;
    writing-mode: tb-rl;
    text-align: center;
    vertical-align: middle;
  }
</style>
<![endif]-->

方法二:

这种居中方案,可以说是万能的。如果方法一可以解决问题,请尽量不要用此方法,毕竟增加了一个没有意义的空标签是很不爽的。

请看如下代码:

<div style="height: 400px;">
  <img src="http://www.xxxxxx.com/摄影作品1.jpg" alt="" />
</div>

上面的img元素是可替换元素,它有固有的高度和宽度(由图片大小决定)。就目前的布局来说,vertical-align对它还不能起到居中对齐的作用,因为它没有占满父级div所有的高度。有的同学就说了:好办,我给img来个line-height。这样是不行的,因为它是可替换元素。难道没有办法了吗?有的,我们知道一行在屏幕上实际占有的高度,是由这行里最高的行级元素决定的(还有多种决定因素),而其它比较矮的行元素通过设置vertical-align: middle就会在这行里垂直居中对齐。通过上一点分析,我们就在img的后面加上一个空的行级元素,让它占满div的高度。这个任务交给inline-block级别的元素完成,因为它可以设高度,而且又是行布局。完整代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>垂直居中</title>
	<style type="text/css">
	#container {		
		border: 1px solid black;
		text-align: center;
		height: 500px;
	}
	#container b {
		display: inline-block;
		height: 100%;
		vertical-align: middle;
	}
	</style>
</head>
<body>
	<div id="container">
	  <img src="http://img1.cache.netease.com/img09/logo/logo.gif" alt="logo" />
	  <b></b>
	</div>
</body>
</html>

这种方法也适合一行中同时出现non-replaced elements和replaced elements的情况。

星级评价

闲来无事,想做一个星级评价系统的UI,又不想用JavaScript。分析一下,只能从:hover这个伪类入手,但是IE6除了a标签,别的标签都不支持:hover伪类。所以问题就限定在怎么样用a标签来实现星级评价。

假设星级评价有5个等级,每个星星有20象素的高度和宽度。

最初的想法是用嵌套的方式去实现,但a标签是不能嵌套使用的。所以又想到了重叠的方式,比如等级5是100象素的宽度,等级4是80个象素,并且覆盖到等级5的上面。等级3是60个象素,覆盖到等级4的上面。以此类推,并且把这5个a标签左对齐,设置一下hover时的背景图片就搞定了。

CSS代码:

#rating {
  position: relative;
}
#rating a {
  display: block;
  height: 20px;
  position: absolute;
  left: 0;
  top: 0;
}
#rating a:hover {
  background: red;
}
#rank5 {
  width: 100px;
}
/* 每个rank都要设置宽度,很麻烦。省略不写了。 */

HTML代码:

<div id="rating">
  <a id="rank5" href="#"></a>
  <a id="rank4" href="#"></a>
  <a id="rank3" href="#"></a>
  <a id="rank2" href="#"></a>
  <a id="rank1" href="#"></a>
</div>

但是这样很麻烦,每个等级的a标签都要设置宽度。那么就结合一下嵌套和重叠的方法,每个等级再加入div标签做嵌套,实现自动适应宽度。

CSS代码:

#rating {
  width: 100px;
  height: 20px;
  background: transparent url(star_rating.gif) repeat;
}
#rating div {
  margin-right: 20px;       
}
#rating, #rating div
{
  zoom: 1; /* 如果不加这个,在IE6,7下你会很纠结 */       
  position: relative; 
}
#rating a {
  position: absolute;
  height: 20px;
  width: 100%;
}
#rating a:hover {
  background: transparent url(star_rating.gif) repeat;
  background-position: 0 -20px;
}     

HTML代码:

<div id="rating"> 
  <a href="#"></a>
  <div> 
    <a href="#"></a>
    <div> 
      <a href="#"></a>
      <div> 
        <a href="#"></a>
        <div> 
          <a href="#"></a>
        </div>
      </div>
    </div>
  </div>
</div>

解释一下,#rating这个div是等级5的容器,设定它的宽度为100象素,这时候它里面的div也都是宽100象素。然后它里面的div分别向右间隔20个象素,这样就变成了宽100px,80px,60px,40px和20px的五个div。再让a标签绝对定位重叠起来,并且让它们和容器一样的大小。设置好背景图片之后,一个星级评价的UI就完成了。

点我查看完整的演示

Inline elements的一些事

Inline elements的定义

Inline-level elements are those elements of the source document that do not form new blocks of content; the content is distributed in lines (e.g., emphasized pieces of text within a paragraph, inline images, etc.). Several values of the ‘display’ property make an element inline: ‘inline’, ‘inline-table’, ‘inline-block’ and ‘run-in’ (part of the time; see run-in boxes). Inline-level elements generate inline boxes.

replaced elements and non-replaced elements

An element whose content is outside the scope of the CSS formatting model, such as an image, embedded document, or applet. For example, the content of the HTML IMG element is often replaced by the image that its “src” attribute designates. Replaced elements often have intrinsic dimensions: an intrinsic width, an intrinsic height, and an intrinsic ratio. For example, a bitmap image has an intrinsic width and an intrinsic height specified in absolute units (from which the intrinsic ratio can obviously be determined). On the other hand, other documents may not have any intrinsic dimensions (for example, a blank HTML document).

User agents may consider a replaced element to not have any intrinsic dimensions if it is believed that those dimensions could leak sensitive information to a third party. For example, if an HTML document changed intrinsic size depending on the user’s bank balance, then the UA might want to act as if that resource had no intrinsic dimensions.

replaced elements的大概意思是那些有自己尺寸和比例的元素,比如img有自己的宽和高。img,input,textarea,select,object这些都是replaced elements,除了它们别的元素就是non-replaced elements。

Inline elements的宽和高

对于non-replaced的inline元素,设置width和height是没有作用的,不过此类元素的高度可以由line-height来指定。

Inline elements的padding和margin

对于non-replaced的inline元素,padding和margin作用方式是一样的,margin和padding只会在左右两个方向起到实际作用。如下面的例子,将a元素的padding设置了50px,只在左右留出了空白。

Lorem ipsum dolor sit amet consect etuer adipi scing elit sed diam nonummy nibh euismod tinunt ut laoreet dolore magna aliquam erat volut. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.

Inline Form Labels

很多网站在填写表单的时候,都可以看到这样一种UI,input[type=text]里面有提示的文字,当鼠标点进去之后提示文字就消失了。以前做这个效果的时候都是用很笨的方法,就是把提示文字写进input的value里,然后在focus的时候去掉,在blur的时候再判断一下input的value是不是空,如果为空再把提示加上去。这样做很笨,不仅代码难看,也不符合“规范”(提示就应该是提示,不应该是input的值)。

有一天在网上发现的一种很容易的做法,下面就介绍一下。先是普通的HTML:

<div class="row">
  <label class="hint" for="textbox_name">
    <span>User name</span>
  </label>
  <input class="textbox" type="text" id="textbox_name" />
</div>

注意这里的label有一个for的属性,这个是必需的,它可以确保点击label的时候,让input获得焦点,因为之后我们要让label定位到input的上方(label与input重叠)。接下来添加样式:

.row {
  position: relative;
  padding: 1px;
}
.row .hint{
  opacity: 0.4;
  filter:alpha(opacity=40);
  padding: 4px 0 0 6px;     
  position: absolute;
}
.row .textbox {      
  height: 18px;
  outline: none;
  border: 1px solid Gray;
  padding: 4px 3px 2px;     
  -webkit-border-radius: 2px
  -moz-border-radius: 2px;
}
.focus {
  padding: 0;
}
.focus .textbox {
  border: 2px solid #7B8AAC;
}

这样label就和input重叠起来了。

然后处理用户的操作,当input获得焦点的时候,让label隐藏,失去焦点的时候需要判断一下input的value是不是空值,如果是空值就让label显示出来,下面是JavaScript:

$(function() {
  $(".textbox").focus(function() {
    var self = $(this);
    self.closest(".row").addClass("focus");
    self.prev().css("display", "none");
  }).blur(function() {
    var self = $(this);
    self.closest(".row").removeClass("focus");
    if(self.val() == "") {
      self.prev().css("display", "inline");
    }
  });
});

为了方便,这里用到了jQuery。