热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

初识CSS中的sprite技巧

所谓的CSSSprites技术,就是将一些较小的图片统一排放在一个大的图片文件中,然后依靠代码来显示其中所需的图标部分,从而代替将这些小图标单独保存为多个较小图片文件。我们先来看一个例子:这个页面主

所谓的CSS Sprites技术,就是将一些较小的图片统一排放在一个大的图片文件中,然后依靠代码来显示其中所需的图标部分,从而代替将这些小图标单独保存为多个较小图片文件。我们先来看一个例子:


这个页面主要实现的是一个日历功能(参考jquery Javascript与css开发入门经典一书第七章AJAX)。最下方的控制按钮就是采用了CSS Sprites技术。当用户点击最左方的箭头时可查看前一个月的日历,点击右方按钮时可查看后一个月的日历,同时按钮颜色瞬变变换颜色。这个按钮的原始图片如下:


 

即在一张大图里包含了按钮所有的状态。一个更复杂的例子是我在虾米的@关注微博网页中见到过的。主要是右侧的导航栏(原始图片如右所示,也是包含了所有按钮的状态):


如果你曾经使用过某些游戏引擎,如Unity,就会发现这与其中的NGUI中的Atlas十分相似!(详细请看这里)在NGUI里,大贴图中的小贴图被称为Sprite(精灵),而大贴图被称为Atlas(图集)。使用Atlas主要是为了减少游戏的Drawcall,从而提高游戏性能,具体不在这里赘述。同样,CSS中使用Sprite技术的原因也类似:主要有以下几点:

  • 多个单独的小图片文件将会占用更多的存储空间和带宽,而只需花费少量的额外时间就可以方便地将多个分离的小图片创建为一个较大的图片。相反,如果把大图片切割成多个小图片后,这些小图片的总大小将超过原来的大图片。
  • 使用CSS Sprites后,根据用户的交互行为切换不同的图片的响应速度将变得更快,这是因为当用户单击一个命令按钮或者鼠标移动过某个页面元素时,浏览器无需下载这些图片文件——因为每个状态的文件已经被包含在同一个图片文件中。
  • 像服务器发送过多的HTTP请求将导致服务器变慢,都会给服务器带来一定的负载和延迟。而对一个较大的文件发送请求的负载,要比对多个较小的文件发起多个请求要快得多。
好啦,现在我们就以日历为例子,来具体讲讲是怎么实现的吧!

首先看下html中的主要框架代码(只粘贴控制按钮的部分):


















主要是把一个大的div(id = 'webExample_CalendarControls',即下图中最外面的红色区域)分成了九个div。向前和向后的按钮(
)、按钮之间的四个分界线(
,id分别包含One、Two、Three、Four),以及三个分别控制Day、Week、Month的按钮(
等)。细心的童鞋可以发现在上述代码中,Month对应的div下比Day和Week多了一层下属div:
,同时两侧的分界线的div下也分别多了一行空的div代码:
。正是因为如此,日历的初始画面是Month被选中,这是在CSS中实现的效果,换句话说,哪个按钮被选中,就会增加一层div,并将其类名设为'webExample_CalendarControlOn',哪个按钮两侧的分界线对应的div便会增加一个div区域,从而实现蓝色被按下的效果。

再来看它的样式表。首先是最外部div的样式表:

div#webExample_CalendarControls
{
position : absolute;
left : 50%;
bottom : 8px;
width : 188px;
height : 25px;
margin : 0 0 0 -94px;
}

主要是实现将图片居中显示,需要说明是的原图片的大小为188px*75px,因为共有三层状态所以height设为25。下面的样式规则定义了CSSSprites的基本布局,即九个较小div的布局:

div#webExample_CalendarControls div 
{
position : absolute;
height : 25px;
top : 0;
left : 0;
background : url('../img/Navigation.png') no-repeat top left;
}

它把每个子
元素都设置成绝对定位,并把高度设为25像素,正好等于每个CSS Sprites图片的高度。最后把背景图片都设置为包含了所有图片的大图片。

div#webExample_CalendarControls div div
{
width : 100%;
height : 100%;
background : url('../img/Navigation.png') no-repeat top left;
}

上面这条样式规则定义了每一个嵌套的
元素(即我们刚才说到的多出来的那些
元素)的样式,它首先将嵌套的
元素尺寸设为父元素的100%,然后将背景图片也设置为主图片。如上所说,这些按钮将用于显示主sprites文件中选中按钮和鼠标按下的图片状态。

div div#webExample_CalendarControlPrevious
{
width : 23px;
}
div div#webExample_CalendarControlPrevious div
{
background-position : 0 -50px;
}

终于到了关键的部分~上面两条样式规则用于定义向前按钮。要显示该按钮的初始状态,只需将默认的图片显示出来即可,并将width属性设置为23像素,即该按钮的宽度。而为了显示被鼠标按下的状态,只需调整该属性图片的位置,使之沿Y轴方向移动-50像素即可。在jQuery代码的协助下,当用户单击按钮时,背景图片沿Y轴移动-50像素后将最后一行图片显示出来(如有童鞋不懂background-position的用法,可以参见 这里)。上面展示了Sprites的奥秘——其原理在于对背景图片位置的调整。


div div#webExample_CalendarControlNext
{
width : 23px;
left : 165px;
background-position : -165px 0;
}
div div#webExample_CalendarControlNext div
{
background-position : -165px -50px;
}

向后按钮的样式规则与向前按钮类似。向前和向后按钮都只有两个状态(未选中、被按下),而不像Day、Week、Month按钮有三个状态(未选中、被按下、选中),因此规则也多了一条。

/* Control Day */
div div#webExample_CalendarControlDay
{
width : 46px;
left : 24px;
background-position : -24px 0;
}
div div#webExample_CalendarControlDay div.webExample_CalendarControlOn
{
background-position : -24px -25px;
}
div div#webExample_CalendarControlDay div
{
background-position : -24px -50px;
}

上面是对Day按钮的样式规则定义。第一个样式规则定义了Day按钮的

元素在其父类
元素中的位置。为了不与向前按钮重叠,样式规则将其left属性设置为24px(关于CSS定位的解释请看这里),即向前按钮的宽度加上1像素的分界线的宽度。Day按钮的宽度是46像素,且其初始状态图片位于主图片的(-24,0)位置处。第二条样式规则用于定义被选中状态的图片位置(此时该按钮增加了一个类名——webExample_CalendarControlOn,以区别按钮的被按下状态)。

/* Control Week */
div div#webExample_CalendarControlWeek
{
width : 46px;
left : 71px;
background-position : -71px 0;
}
div div#webExample_CalendarControlWeek div.webExample_CalendarControlOn
{
background-position : -71px -25px;
}
div div#webExample_CalendarControlWeek div
{
background-position : -71px -50px;
}
/* Control Month */
div div#webExample_CalendarControlMonth
{
width : 46px;
left : 118px;
background-position : -118px 0;
}
div div#webExample_CalendarControlMonth div.webExample_CalendarControlOn
{
background-position : -118px -25px;
}
div div#webExample_CalendarControlMonth div
{
background-position : -118px -50px;
}

而Week和Month按钮的定义与其相似,如上所示。下面介绍最后一类区域——分割线。

div#webExample_CalendarControl div.webExample_CalendarSeparator
{
left : 23px;
width : 1px;
background-position : -23px 0;
}
div#webExample_CalendarControl div.webExample_CalendarSeparator div
{
background-position : -23px -50px;
}
div#webExample_CalendarControl div#webExample_CalendarSeparatorTwo
{
left : 70px;
}
div#webExample_CalendarControl div#webExample_CalendarSeparatorThree
{
left : 117px;
}
div#webExample_CalendarControl div#webExample_CalendarSeparatorFour
{
left : 164px;
}
接下来是Javascript代码部分,其中引用了jQuery代码。

$(document).ready(
function () {
$('div#webExample_CalendarControls > div').mousedown(
function () {
if (!$(this).hasClass('webExample_CalendarSeparator')) {
$(this).html("
");
$(this).prev().html("
");
$(this).prev().next("
");
}
}
).mouseup(
function () {
if (!$(this).hasClass('webExample_CalendarSeparator')) {
if ($(this).hasClass('webExample_CalendarControlToggle')) {
$('div#webExample_CalendarControls > div').not(this).empty();
$(this).find('div').addClass('webExample_CalendarControlOn');
$(this).prev().html("
");
$(this).prev().next("
");
} else {
$(this).empty();

if (!$(this).prev().prev().find('div').length) {
$(this).prev().empty();
}

if (!$(this).next().next().find('div').length) {
$(this).next().empty();
}

var $isNext = ($(this).attr('id').indexof('next') != -1);
$('div#webExample_Calendar').load('Example%20' + ($isNext ? 'Next' : 'Previous') + '.html');
}
}
}
);
}
);

第一段代码为ID为webExample_CalendarControls(即最外部的
元素)中所包含的每一个直接子元素
元素挂钩了一个mousedown事件,主要用以处理各个按钮被鼠标按下的状态,实现这些按钮的Sprites功能。首先,代码检查用户单击的是否是一个分界线如果不是,则为该
元素添加一个子
元素,并未该元素的前一兄弟节点和后一兄弟节点各添加一个子
元素,这样使得样式表中为这些按钮定义的被按下状态和按钮前后分隔栏状态被激活。类似于以下代码:

div div#webExample_CalendarControlNext div
{
background-position : -165px -50px;
}

当用户释放鼠标按键时,即发生mouseup时间,即第二段代码。代码首先仍确定该元素不是一个分割线。再判断是否是一个Day、Week或Month按钮(类名为webExample_CalendarControlToggle)。如果是,则将其他所有非此元素的子

元素清空,清除其他按钮被选中状态,并为当前选中按钮的子
元素(在mousedown事件中添加)动态添加webExample_CalendarControlOn类名以实现被选中状态。剩下的就是对两侧分割线的修饰,就像在mousedown事件中做的一样。如果不是Day、Week或Month按钮,就说明是向前或向后按钮。因为这两个按钮没有被选中状态,因此一旦用户单击了这两个按钮,则应该将按钮状态恢复到未单击之前的状态。接下来的代码用于移除与向前或者向后按钮相连接的样式,但是仅在与该分隔栏相邻其他按钮未被选中时才移除。接下来的代码主要是为了加载日历,这里就不再讲述了。

————————————————————————————————————————————————————————————————

总结一下,CSS Sprites主要是利用了背景图片位置的变换,利用background-position和left等CSS属性,加上不同状态下的类名来实现不同状态的转换。而类名主要是通过Javascript代码实现动态添加和去除的。

不知道看到这里大家懂了多少。。。如果有什么不懂或者建议神马的可以留言告诉我~



推荐阅读
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • Android实战——jsoup实现网络爬虫,糗事百科项目的起步
    本文介绍了Android实战中使用jsoup实现网络爬虫的方法,以糗事百科项目为例。对于初学者来说,数据源的缺乏是做项目的最大烦恼之一。本文讲述了如何使用网络爬虫获取数据,并以糗事百科作为练手项目。同时,提到了使用jsoup需要结合前端基础知识,以及如果学过JS的话可以更轻松地使用该框架。 ... [详细]
  • 本文介绍了在满足特定条件时如何在输入字段中使用默认值的方法和相应的代码。当输入字段填充100或更多的金额时,使用50作为默认值;当输入字段填充有-20或更多(负数)时,使用-10作为默认值。文章还提供了相关的JavaScript和Jquery代码,用于动态地根据条件使用默认值。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
author-avatar
前所未闻啊_549
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有