星级评价控件(jQuery版)

前几天写一个打分的UI,没有实现功能,现在把功能加入进来,并且用jQuery封装一下。

演示地址:http://www.zhoumingzhi.com/wp-content/uploads/2010/01/rating/demo.html

下载地址:http://code.google.com/p/rating-widget/downloads/list

用法:

$(function () {
    $(".ui-rating").rating({
        "activate": 7,
        "total": 10,
        "select": function (event, ui) {
        },
        "change": function (event, ui) {
        }
    });
});

用一个空的块元素标签实例化即可,最好是用div。

参数说明:

参数 类型 说明
total number/string 级别总数,通常来说就是指星星的个数,除非是用半个星星表示一个等级。
activate number/string 当前选中的级别,一般用来指示所有用户选的平均值。
select function(event, ui) 处理点击事件的函数。event参数代表事件,ui.level表示选中的级别。
change function(event, ui) 这个函数在鼠标移动时被触发。event参数代表事件,ui.level表示鼠标划过的级别。

方法说明:

$(".ui-rating").rating("option", "activate", 5);
$(".ui-rating").rating("enable");
$(".ui-rating").rating("disable");

activate方法有一个参数,表示要设定的等级。

终极攻略——未知高度元素垂直居中

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

有的同学看到题目就会想:我把父元素设成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就完成了。

点我查看完整的演示

文本自动换行

当一行文本的长度超出容器的最大宽度,就要产生自动换行的问题。CSS的white-space属性可以决定自动换行的行为。white-space有下面几个值:

属性值 空白符 换行符 自动换行 最早出现于
normal 合并 忽略 允许 CSS 1
nowrap 合并 忽略 不允许 CSS 1
pre 保留 保留 不允许 CSS 1
pre-wrap 保留 保留 允许 CSS 2.1
pre-line 合并 保留 允许 CSS 2.1

如果一个单词的长度超过了容器的最大宽度,也会出现自动换行的问题,这个是由word-wrap决定的。word-wrap有三个值:normal | break-word | inherit

normal
单词不会自动换行,这是默认值。
break-word
如果单词的长度超过容器最大宽度,单词会被截断,产生换行。

li的多余空白

在IE6下,li标签中有浮动元素的话,就有可能在两个li之间出现一条多余的空白。

CSS:

ul li
{
    width: 300px;
    height: 50px;
}
ul li div
{
    width: 30px;
    height: 50px;
    float: left;
}

HTML:

<ul>
    <li>
        <div>123</div>
        <div>456</div>
    </li>
    <li>456</li>
</ul>

解决的办法:

  1. 在任意一个div上加个vertical-align: top
  2. 让li浮动并清除浮动

IE 8 CSS hack

body
{
    padding-left: 0px\0;
}