一、相关知识讲解
看过雅虎的前端优化35条建议,都知道优化前端是有多么重要。页面的加载速度直接影响到用户的体验。80%的终端用户响应时间都花在了前端上,其中大部分时间都在下载页面上的各种组件:图片,样式表,脚本,Flash等等。
减少组件数必然能够减少页面提交的HTTP请求数。这是让页面更快的关键。减少页面组件数的一种方式是简化页面设计。但有没有一种方法可以在构建复杂的页面同时加快响应时间呢?嗯,确实有鱼和熊掌兼得的办法。
这里我们就拿雅虎的第一条建议:尽量减少HTTP请求数里的减少图片请求数量 进行讲解。
我 们都知道,一个网站的一个页面可能有很多小图标,例如一些按钮、箭头等等。当加载html文档时,只要遇到有图片的,都会自动建立起HTTP请求 下载,然后将图片下载到页面上,这些小图片可能也就是十几K大甚至1K都不到,假如我们的一个页面有一百个小图标,我们在加载页面时,就要发送100个 HTTP请求,如果你的网站访问量很大并发量也很高,假如上百万访问量,那发起的请求就是千万级别了,服务器是有一定的压力的,并且一个用户的一个页面要 发起那么多请求,是很耗时的。
所以,我们优化的方案就是:将这些十几K、几K的小图标合并在一张图片里,然后用CSS的background-image
和background-position
属性来定位要显示的部分。
二、代码实现
1、思路:
将一个文件夹里的图标,自动生成在一张图片里面,同时自动生成对应的css文件,我们只要在HTML里的标签中添加相应的属性值就能显示图片了。
2、实现过程:
<?php //自己定义一个根目录 define('ROOT', $_SERVER['DOCUMENT_ROOT'].'iconwww'); //这个是图片的目录 define('RES_BASE_URL', 'http://localhost:8080/iconwww/img'); /** * 生成背景图的函数 */ function generateIcon() { //网站根目录 $webRoot = rtrim(ROOT, '/'); //背景图目录 $root = "$webRoot/img/bg"; //Php-SPL库中 的 目录文件遍历器 $iterator = new DirectoryIterator($root); //开始遍历该背景图目录下的目录,我们是把想生成背景图的目录,放在bg目录中以各个模块的目录分类存放 foreach ($iterator as $file) { //遇到目录遍历 if (!$file->isDot() && $file->isDir()) { //取得文件名 $fileName = $file->getFilename(); generateIconCallback("$root/$fileName", "$webRoot/img/$fileName", "$webRoot/css/$fileName.css"); } } } /** * 用户生成合并的背景图和css文件的函数 * @param string $dir 生成背景图的图标所在的目录路径 * @param string $bgSavePath 背景图所保存的路径 * @param string $cssSavePath css保存的路径 */ function generateIconCallback($dir, $bgSavePath, $cssSavePath) { $shortDir = str_replace('\\', '/', substr($dir, strlen(ROOT-1))); //返回文件路径信息 $pathInfo = pathinfo($bgSavePath.'.png'); $bgSaveDir = $pathInfo['dirname']; //确保目录可写 ensure_writable_dir($bgSaveDir); //背景图名字 $bgName = $pathInfo['filename']; //调用generateIconCallback_GetFileMap()函数生成每一个图标所需要的数据结构 $fileMap = array('a' => generateIconCallback_GetFileMap($dir)); $iterator = new DirectoryIterator($dir); foreach ($iterator as $file) { if ($file->isDot()) continue; if ($file->isDir()) { //二级目录也要处理 $fileMap['b-'.$file->getFilename()] = generateIconCallback_GetFileMap($file->getRealPath()); } } ksort($fileMap); //分析一边fileMap,计算整个背景图的大小和每一个图标的offset //初始化偏移量和背景图 $offsetX = $offsetY = $bgWidth = 0; //设定每个小图标之间的距离 $spaceX =$spaceY = 5; //图片最大宽度 $maxWidth = 800; $fileMd5List =array(); //这里需要打印下$fileMap就知道它的数据结构了 foreach ($fileMap as $k1 => $innerMap) { foreach ($innerMap as $k2 => $itemList) { //行高姐X轴偏移量初始化 $offsetX = $lineHeight = 0; foreach ($itemList as $k3 => $item) { //变量分别是:图标的宽度,高度,类型,文件名,路径,MD5加密字符串 list($imageWidth, $imageHeight, $imageType, $fileName, $filePathname, $fileMd5) = $item; $fileMd5List []= $fileMd5; //如果图片的宽度+偏移量 > 最大宽度(800) 那就换行 if ($offsetX !== 0 && $imageWidth + $offsetX > $maxWidth) { $offsetY += $spaceY + $lineHeight; $offsetX = $lineHeight = 0; } //如果图片高度 > 当前行高 那就讲图片高度付给行高我们这的 if ($imageHeight > $lineHeight) $lineHeight = $imageHeight; $fileMap[$k1][$k2][$k3] = array($imageWidth, $imageHeight, $offsetX, $offsetY, $imageType, $fileName, $filePathname); //X轴偏移量的计算 $offsetX += $imageWidth + $spaceX; if ($offsetX > $bgWidth) $bgWidth = $offsetX; } //Y轴偏移量的计算 $offsetY += $lineHeight + $spaceY; } } //把右下两边多加了的空白距离给干掉 $bgWidth -= $spaceX; $bgHeight = $offsetY - $spaceY; $fileMd5List = implode("\n", $fileMd5List); //生成背景图和 css文件 //资源路径 $resBaseUrl = RES_BASE_URL; $suffix = base_convert(abs(crc32($fileMd5List)), 10, 36); $writeHandle = fopen($cssSavePath, 'w'); fwrite($writeHandle, "/** bg in dir: $shortDir/ */\n[icon-$bgName]{background:url({$resBaseUrl}/$bgName.png?$suffix) no-repeat;display:inline-block;}"); //做图片,这些函数具体可以查看PHP手册 $destResource = imagecreatetruecolor($bgWidth, $bgHeight); imagealphablending($destResource, false); imagesavealpha($destResource, false); $color = imagecolorallocatealpha($destResource, 255, 255, 255, 127); imagefill($destResource, 0, 0, $color); //对每一张小图片进行处理,生成在大背景图里,并生成css文件 foreach ($fileMap as $innerMap) { foreach ($innerMap as $itemList) { foreach ($itemList as $item) { list($imageWidth, $imageHeight, $offsetX, $offsetY, $imageType, $fileName, $filePathname) = $item; if ($imageType === IMAGETYPE_PNG) { $srcResource = imagecreatefrompng($filePathname); } else if ($imageType === IMAGETYPE_JPEG) { $srcResource = imagecreatefromjpeg($filePathname); } imagecopy($destResource, $srcResource, $offsetX, $offsetY, 0, 0, $imageWidth, $imageHeight); imagedestroy($srcResource); //写入css $posX = $offsetX === 0 ? 0 : "-{$offsetX}px"; $posY = $offsetY === 0 ? 0 : "-{$offsetY}px"; fwrite($writeHandle, "\n[icon-$bgName=\"$fileName\"]{width:{$imageWidth}px;height:{$imageHeight}px;background-position:$posX $posY;}"); } } } //压缩级别 7 imagepng($destResource, "$bgSavePath.png", 7); imagedestroy($destResource); fclose($writeHandle); $shortCssSavePath = substr($cssSavePath, strlen(ROOT)); } /** * 将图片的信息处理成我们想要的数据结构 * @param [type] $dir [description] * @return [type] [description] */ function generateIconCallback_GetFileMap($dir) { $map = $sort = array(); $iterator = new DirectoryIterator($dir); foreach($iterator as $file) { if(!$file->isFile()) continue; $filePathname = str_replace("\\", '/', $file->getRealPath()); //这些函数可以查看PHP手册 $imageInfo = getimagesize($filePathname); $imageWidth = $imageInfo[0]; $imageHeight = $imageInfo[1]; $imageType = $imageInfo[2]; if(!in_array($imageType, array(IMAGETYPE_JPEG, IMAGETYPE_PNG))) { $fileShortName = substr($filePathname, strlen(ROOT) - 1); echo "<p> $fileShortName 图片被忽略: 因为图片类型不是png|jpg.</p>"; continue; } //这是我们的图片规格,行高分别有 16 32 64 128 256 99999 foreach(array(16, 32, 64, 128, 256, 99999) as $height) { if($imageHeight <= $height) { $mapKey = $height; break; } } if(!isset($map[$mapKey])) $map[$mapKey] = array(); $filePathInfo = pathinfo($filePathname); $map[$mapKey] []= array($imageWidth, $imageHeight, $imageType, $filePathInfo['filename'], $filePathname, md5_file($filePathname)); $sort[$mapKey] []= str_pad($imageHeight, 4, '0', STR_PAD_LEFT) . $filePathInfo['filename']; } foreach($map as $k => $v) array_multisort($map[$k], SORT_ASC, SORT_NUMERIC, $sort[$k]); ksort($map, SORT_NUMERIC); return $map; } /** * 判断目录是否可写 * @param string $dir 目录路径 */ function ensure_writable_dir($dir) { if(!file_exists($dir)) { mkdir($dir, 0766, true); @chmod($dir, 0766); @chmod($dir, 0777); } else if(!is_writable($dir)) { @chmod($dir, 0766); @chmod($dir, 0777); if(!@is_writable($dir)) { throw new BusinessLogicException("目录不可写", $dir); } } } generateIcon(); ?> <!DOCTYPE html> <html> <head> <link rel="stylesheet" type="text/css" href="css/Pink.css"> <title></title> </head> <body> <div>我们直接引入所生成的css文件,并测试一下是否成功</div> <br> <div>这里在span标签 添加属性 icon-Pink ,值为About-40,正常显示图片</div> <span icon-Pink="About-40"></span> </body> </html>
调用以上代码,我们的浏览器是这样显示的:
然后css目录生成了Pink.css文件:
img目录下生成了Pink.png文件:
看看生成的背景图是长啥样子:
接下来我们再看一下所生成的图片大小与Pink文件夹里所有小图片总和的大小,对它们做个比较:
从上图可以看出,我们生成的图片的大小明显小于文件夹所有图片的大小,所以在将100个小图标下载下来的速度 会明显小于 将背景图下载下来和将CSS下载下来的速度。
当访问量大时,或者小图片的量大时,会起到很明显的优化效果!!!
代码中的每一个点都基本上有注释,很方便大家去理解,只要大家用心去看,肯定能将这一网站优化技术用到自己的项目中。
本次博文就写到这!!!
如果此博文中有哪里讲得让人难以理解,欢迎留言交流,若有讲解错的地方欢迎指出。
如果您觉得您能在此博文学到了新知识,请为我顶一个,如文章中有解释错的地方,欢迎指出。
互相学习,共同进步!
原文:http://www.cnblogs.com/it-cen/p/4618954.html
相关推荐
大型网站性能优化实战:从前端、网络、CDN 到后端、大促的全链路性能优化详解 本文档详细介绍了大型网站性能优化的重要性和价值,以及如何从前端、网络、CDN 到后端、大促等多个方面进行性能优化。性能优化是提高...
另外,前端优化还包括代码压缩和合并,通过压缩JavaScript和CSS文件减小传输大小,合并多个文件以减少HTTP请求。此外,利用懒加载技术,可以按需加载非首屏内容,进一步提高首屏加载速度。利用HTTP/2的多路复用功能...
1. **减少HTTP请求** - 通过合并图片(如雪碧图)、使用Base64编码或采用WebP格式,可以减少网络请求次数,提高页面加载效率。 2. **减小图片大小** - 通过压缩工具(如TinyPNG、JPEGmini等)压缩图片,减小文件...
- **减少HTTP请求**:通过合并CSS和JavaScript文件、使用图片精灵等技术来减少页面加载时的HTTP请求次数,从而加快页面加载速度。 - **异步处理**:利用ASP.NET AJAX或SignalR等技术实现页面部分刷新,避免整个页面...
CSS精灵图片(Sprites)是一种优化网页性能的技术,通过将多个小图片合并成一张大图,然后利用CSS背景定位(background-position)来展示需要显示的部分,以此减少HTTP请求,提高网页加载速度。CSS Sprites在处理...
1. **CSS整合与压缩**:Autoptimize能够合并多个CSS文件为一个,减少HTTP请求次数,同时对CSS代码进行压缩,去除不必要的空格和注释,降低文件大小。 2. **JavaScript优化**:类似地,插件会将分散的JavaScript文件...
- **案例1:减少HTTP请求**:例如,将多个小图标合并成一张大图并通过CSS Sprites技术实现,减少图片请求次数。 - **案例2:使用内容发布网络**:对于大型网站而言,使用CDN可以显著减少跨区域访问延迟,提高全球...
在网页开发中,CSS精灵(CSS Sprites)是一种高效优化页面加载速度的技术,通过将多个小图合并成一张大图,然后利用CSS背景定位的方式来显示需要的部分,以此减少HTTP请求,加快页面加载。"csssprites_3.2.1.zip"这...
这种技术尤其适用于那些需要频繁加载的小图标或者背景图片,减少了HTTP请求的数量,从而提升了页面的加载速度。 **一、Sprite技术原理** 1. **合并图像**:将网页中多个小图整合到一张大图上,通常称为"精灵图"。 ...
合理使用分区技术减少查询数据量。 - **案例分析**:假设有一个订单表,包含数百万条记录,如果查询条件不使用索引,则会导致全表扫描,消耗大量时间。通过添加适当的索引,可以显著减少查询所需的时间。 **2. 返回...
- **合并技术(Spriting)**:通过将多个图像合并到一个文件中来减少HTTP请求的数量。 - **内联技术(Inlining)**:将某些资源(如图片或样式表)直接嵌入HTML文档中,以减少额外的请求。 - **拼接技术...
2. **HTTP Concatenation (http-concat)**:这个模块允许Nginx在服务静态资源时,将多个CSS或JS文件合并成一个文件,从而减少HTTP请求的数量,提高页面加载速度,遵循了减少HTTP往返次数的性能优化原则。 3. **源码...
### Oracle PGA详解:深入理解与优化策略 #### PGA概述与重要性 在Oracle数据库系统中,PGA(Program Global Area)是每个服务器进程所拥有的专用内存区,它为每个会话提供私有数据结构和控制信息。PGA的重要性...
### SQL查询语句优化策略详解 #### 一、选择最有效率的表名顺序 在基于规则的优化器中,如Oracle,SQL语句中表的处理顺序至关重要。Oracle的解析器遵循从右至左的处理逻辑,因此,位于FROM子句最右侧的表将被最先...
**CSS Sprite技术详解** CSS Sprite,也被称为精灵图或雪碧图,是一种在网页设计中广泛应用的优化图像加载的技术。它的主要目的是减少网页HTTP请求的数量,从而提高页面加载速度,优化用户体验。通过将多个小图标...
19. 优化网络请求:合并多个小请求为一个大请求,或者使用HTTP/2以减少网络延迟。 20. 使用轻量级的对象池:对于短生命周期且频繁创建销毁的对象,可以使用对象池来复用,减少内存分配和释放。 21. 限制KVO(Key-...
### Unity优化建议详解 #### 一、Unity脚本系统优化 Unity引擎因其强大的跨平台能力,在游戏开发领域占据着重要地位。为了确保游戏在不同设备上都能流畅运行,对Unity项目进行性能优化变得尤为重要。其中,脚本...