前端优化技巧之img sprites

作者:nunumick 发布时间:04 Jan 2011 分类: front-end

背景知识:

css sprites是前端开发必须掌握的一项优化技巧,此技巧的意义常被作为基础题放入面试环节。可以这么说:不知道css sprites的前端不是好前端。

html:

<div class="sample">某某示例</div>

css:

.sample{
    height:50px;
    width:50px;
    overflow:hidden;
    background:url(../sprites/img-sprites.png) no-repeat -50px -10px;
    line-height:99em;
}

而img sprites可以说是css sprites的变种,此技巧的使用最早可以追溯到2007年,主要用于提升网页的可用性。img sprites与css sprites两者原理上基本是一致的,区别在于img sprites把css样式表中的背景图挪到了标签中

html:

<div class="sample">
    <img src="../sprites/img-sprites.png" alt="某某示例" />
</div>

css:

.sample{
    height:50px;
    width:50px;
    overflow:hidden;
}
.sample img{
    margin:-10px 0 0 -50px;
}

还可以使用clip属性来控制图片显示区域

那么,使用img sprites有哪些好处呢?

一、img sprites 的优势:

1.支持windows高对比度显示模式

windows用户如果把显示设置成高对比度模式,则在一些特定浏览器下(Opera),css sprites就会显的面目全非,而img sprites可以避免此类问题。

2.打印终端友好

css sprites背景图无法被打印,而img sprites则可以,这一点我力挺img sprites。

3.SEO友好

使用img sprites,搜索爬虫可以抓到网页中的图片,只需要给图片加上相应的alt注释,用户也可以理解搜索到的图片。

4.顺序加载

浏览器的渲染和操作顺序大致如下:

  1. HTML解析完毕。
  2. 外部脚本和样式表加载完毕。
  3. 脚本在文档内解析并执行。
  4. HTML DOM 完全构造起来。
  5. 图片和外部内容加载。
  6. 网页完成加载。

需要注意一点是:背景图和普通图片还不一样,背景图要比普通图片加载的顺序来的靠后,这有一篇实验性文章可以说明这一点,而换成img sprites则可以按照实际的顺序进行加载。

5.语义化

该是图片的时候就是图片,比如LOGO,比如网站介绍性图片

6.提升可用性

当用户禁用图片时,至少可以通过alt注释知道网页要讲些什么

二、img sprites 的劣势:

  1. 图片过大时会阻塞网页加载进度
  2. 右键另存为图片,会将整张sprites图下载到电脑里
  3. 开发成本比css sprites要高,需要权衡性价比

其实css sprites在1、2两方面多少也存在着同样的问题。

三、如何权衡

  1. 图片较大或是纯修饰图片的,用css sprites会更好一些
  2. 有具体意义的图片或者需要较快出现图片或者需要照顾特殊用户群体和打印终端的,采用img sprites则会更好
  3. 在一些较重要的图片,如网站LOGO,我认为更适合做单独的一张图片,css sprites和img sprites两者都不用。虽然多了一个HTTP请求,换之带来的是对用户体验和SEO的友好。

标签: css , sprites
<<< EOF

JavaScript学习笔记-详解in运算符

作者:nunumick 发布时间:31 Dec 2010 分类: front-end

in运算符是javascript语言中比较特殊的一个,可以单独使用作为判断运算符,也常被用于for…in循环中遍历对象属性

一、判断

语法

prop in objectName

如果objectName指向的对象中含有prop这个属性或者键值,in运算符会返回true。

var arr = ['one','two','three','four'];
arr.five = '5';
0 in arr;//true
'one' in arr; //false,只可判断数组的键值
'five' in arr;//true,'five'是arr对象的属性
'length' in arr;//true

原型链

in运算符会在整个原型链上查询给定的prop属性

Object.prototype.sayHello = 'hello,world';
var foo = new Object();
'sayHello' in foo;//true;
'toString' in foo;//true;
'hasOwnProperty' in foo;//true;

对象与字面量

in运算符在对待某些特定类型(String,Number)的对象和字面量时显得不尽相同

var sayHelloObj = new String('hello,world');
var sayHello = 'hello,world';
var numObj = new Number(1);
var num = 1;

'toString' in sayHelloObj; //true
'toString' in sayHello; //类型错误

'toString' in numObj;//true
'toString' in num;//类型错误

究其原因,在MDN找到这样一段关于String对象和字面量转换的介绍,似乎可以解释这个原因:

Because JavaScript automatically converts between string primitives and String objects, you can call any of the methods of the String object on a string primitive. JavaScript automatically converts the string primitive to a temporary String object, calls the method, then discards the temporary String object. For example, you can use the String.length property on a string primitive created from a string literal

试着这样理解:因为in是运算符而非一个方法(method),所以无法让string字面量自动转换成String对象,又因为in运算符待查询方不是对象而是一个字符串(按老道Douglas的说法,只是object-like的类型),所以报类型错误。

二、遍历

很常用到的for…in循环语句,此语句中的in需要遵循另外一套语法规范:

for (variable in object)
statement

与单独使用in作为运算符不同,for…in循环语句只遍历用户自定义的属性,包括原型链上的自定义属性,而不会遍历内置(build-in)的属性,如toString。

对象

function Bird(){
    this.wings = 2;
    this.feet = 4;
    this.flyable = true;
}
var chicken = new Bird();
chicken.flyable = false;
for(var p in chicken){
    alert('chicken.' + p + '=' + chicken[p]);
}

String对象,经过测试Firefox,Chrome,Opera,Safari浏览器都是给出了注释中的结果,只有IE浏览器只给出’more’和’world’

function Bird(){
var str = new String('hello');
str.more = 'world';
for(var p in str){
    alert(p);//'more',0,1,2,3,4
    alert(str[p]);//'world','h','e','l','l','o'
}

字面量

遍历数组字面量的键值和属性

var arr = ['one','two','three','four'];
arr.five = 'five';
for(var p in arr){
    alert(arr[p]);//'one','two','three','four','five'
}

遍历string字面量,虽说单独在string字面量前面使用in运算符会报类型错误,不过下面的代码却能够正常运行,此时IE浏览器是毫无声息

var str = 'hello';
str.more = 'world';
for(var p in str){
    alert(p);//0,1,2,3,4
    alert(str[p]);//'h','e','l','l','o'
}

综上

ECMA虽然有这方面的规范,但浏览器之间还是存在着差异,鉴于此,并不推荐用for…in去遍历字符串,也不推荐拿去遍历数组(如例子所示,为数组加上自定义属性,遍历就会被搞乱)

在遍历对象方面,我们还可以使用对象的内置方法hasOwnProperty()排除原型链上的属性,进一步加快遍历速度,提升性能

function each( object, callback, args ){
    var prop;
    for( prop in object ){
        if( object.hasOwnProperty( i ) ){
            callback.apply( prop, args );
        }
    }
}

标签: javascript , operator
<<< EOF

博客转移到Typecho平台

作者:nunumick 发布时间:30 Dec 2010 分类: blog

作为码农,崇尚简约是美,wordpress对于我来说显的过于笨重,很多功能用不上,不需要,界面繁杂不友好。加之godaddy的空间速度慢如乌龟,博客页面更是不堪重负。看到朋友转移到简洁小巧的typecho,感觉很好,心里痒痒。

Type,有打字的意思,博客这个东西,正是一个让我们通过打字,在网络上表达自己的平台。
Echo,意思是回声、反馈、共鸣,也是PHP里最常见、最重要的函数,相信大部分PHP爱好者都是
从echo ‘Hello,world!’;开始自己的PHP编程之路的。
将这两个词合并在一起,就有了Typecho,我们期待着越来越多的人使用我们开发的程序,
也期待着越来越多的人加入到开源的行列里。
大家一起来,Typecho )))))))))))))))))))))

熟悉的hello,world,熟悉的echo,typecho的名字就充满了php的味道,甚是诱人。

前不久,我的新博客地址nunumick.me开张,正是转移平台的好时机,于是我利用中午休息时间做了转移,整个过程用时很短,typecho不愧是轻量级的。

由于godaddy空间apache配置的不给力,typecho安装成功后一直无法访问除首页之外的其他页面,费了我不少力气。

幸好有互联网和搜索引擎,仅仅靠copy和paste一些现成的代码就解决了难题: 在blog根目录 index.php 的 Typecho_Plugin::factory(‘index.php’)->begin(); 这行前面加上

$baseInfo = @explode('?', $_SERVER['REQUEST_URI'], 2);
if (is_array($baseInfo))
{
        $_SERVER['REQUEST_URI'] = $_SERVER['REQUEST_URI'];
        $_SERVER['PATH_INFO'] = $baseInfo[0];
        unset($_GET);
        if ($baseInfo[1])
        {
                $getInfo = @explode('&', $baseInfo[1]);
                foreach ($getInfo as $v)
                {
                        $getInfo2 = @explode('=', $v);
                        $_GET[$getInfo2[0]] = $getInfo2[1];
                }
        }
}

如果启用了伪静态,则还需要修改 .htaccess 文件:

RewriteEngine On
RewriteBase /
RewriteRule index(\.)php/(.*) /index.php?/$2 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?/$1 [L]

如果不是很明白htaccess的语法规则,可以参考htaccess语法教程

OK,成功进入后台,恢复数据,自定义设置,感受typecho的简洁和亲切,国人就应该支持国人的产品!

Enjoy!

标签: wordpress , typecho , php , htaccess
<<< EOF

JavaScript学习笔记-delete运算符

作者:nunumick 发布时间:29 Dec 2010 分类: front-end

关于javascript的delete运算符,MDN里有相关文档。以下是我的学习笔记,更多是要关注特殊情况的使用和注意点。

一、语法

delete后面的表达式必须给出一个属性的引用,比如

var o = {a:1};
delete o.a; //此处o.a是对象o的属性a的引用

只有在with语句里才能使用单独的属性名

with(o){
   delete a;
}

二、delete的返回值

delete是普通运算符,会返回true或false。规则为:当被delete的对象的属性存在并且不能被删除时 返回false,否则返回true。 这里的一个特点就是,对象属性不存在时也返回true,所以返回值并非完全等同于删除成功与否。

var o = {a:1};
delete o.a; //返回true
var b = 2;
delete b;//返回false,ECMA规则约定:使用var和function声明的变量不可以被delete

三、哪些情况下不允许delete

上例提到的var和function声明的变量不可以被delete,但隐式声明可以被删除

function c(){return 12;}
delete c;//返回false
d = function(){return 12;}
delete d;//返回true

不能delete从原型链上继承的属性,但可以删除原型链上的属性

function Foo(){}
Foo.prototype.bar = 42;
var foo = new Foo();
delete foo.bar;           // 返回true,但并没有起作用
alert(foo.bar);           // alerts 42, 属性是继承的
delete Foo.prototype.bar; // 在原型上删除属性bar
alert(foo.bar);           // alerts "undefined", 属性已经不存在,无法被继承

四、特例

eval执行的代码中如有通过var和function声明的变量,可以被delete

eval("var a=1");
delete a;
alert(a); //报未定义错误

如果声明是在eval执行代码中的闭包内进行的,则变量不能被delete

eval("(function(){var a=1;delete a; return a;})()");//1

五、delete 数组元素

从数组中delete其元素并不会影响数组的长度

var arr = ['yuyin','suhuan','baby'];
delete arr[0];
alert(arr.length);//alert 3

被delete的键值已经不属于数组,但却还是可以被访问,其值为undefined。

var arr = ['yuyin','suhuan','baby'];
delete arr[0];
0 in arr; // false
alert(arr[0]);//undefined
arr[0] === undefined;//true

对比直接将键值赋值undefined

var arr = ['yuyin','suhuan','baby'];
arr[0] = undefined;
0 in arr; // true
alert(arr[0]);//undefined
arr[0] === undefined;//true

可以看出delete 操作只是将键值这个属性从数组中删除了,数组本身也是对象,这个情况好理解的。如果需要保留键值,可以用undefined赋值。

标签: javascript , operator
<<< EOF

Velocity China 2010 Web 性能和运维大会回顾

作者:nunumick 发布时间:21 Dec 2010 分类: front-end

本次Velocity Web性能和运维大会已经谢幕有些时时候了,7号和8号两天的分享,足以让我回杭后还一直回味和消化。

不管从规模还是话题还是其他,我也得说这是我参与过的最给力的一次前端交流盛会,没有之一。除去赞助商的废话,其他嘉宾的分享质量非常之高,两天的时间,多达二十几个Web性能相关的主题分享为11月寒冷的天气增添了不少暖意,尤其是Facebook,Google的分享,异常给力。
另外,与偶像亲密接触,与Douglas,Steve等前端大牛的合影也是给力原因之一,值得一直回味。现在,这些演讲嘉宾应该都各自回国,重新投入到各自的工作和生活了吧?
合影

回顾充实的两天,值得前端回味的主题:

WPO产业已经到来


Steve 的开场白: WPO(WEB性能优化) 产业已经到来。的确,如果网页都打不开,何谈SEO,何谈用户体验?<h3>Facebook的Ajax化、缓存和流水线</h3>
Facebook的Ajax化(Quickling)有点单页面应用的意思,结合前端缓存(PageCache)和流水线(BigPipe)技术,为页面注入了新的血液,极大优化了页面性能。<h3>静态网页资源的管理和优化</h3>
感叹于Facebook的开发工程师们为了得出静态资源优化的最佳方案,可以花大量时间制作实验田。<h3>Facebook: 一个可持续发展的高性能网站</h3>
有时候我们更应该让决策者知道速度就是网站的生命,这样才能做到“fast by default”。<h3>YouTube的前端性能改进:逐步增强与超越</h3>
Youtube优化的DNS预加载是个亮点,个人对他们的widget优化比较感兴趣,同时羡慕他们能够拿到一手详细的数据。<h3>更好地使用JavaScript</h3>
Douglas把他的书又讲了一遍,没有太多亮点。不过,他倒是给了我解决“内存溢出”的建议,这个问题困惑我很久了,谢谢他
<h3>构建Yahoo下一代Mail</h3>
模块化大力提高了页面性能和协同开发效率<h3>更快的Web站点</h3>
构建快速的网站,前端可以做什么:
1).内容越少越好
2).遵循YSlow准则
3).异步、无阻滞<h3>淘宝商品详情页面的优化实践</h3>
我们还需要依靠“组织”,不过最重要的是我们要学会创新。
<h3>另辟蹊径——腾讯web应用的优化新思路</h3>
另类预加载以及DNS优化,最后我们还得考虑到残障用户,这点必须要向Google和腾讯学习。<h3>第三方广告代码稳定性和性能优化</h3>
广告代码就应该做到无阻滞,当中也做了很多权衡,如果每家第三方广告投放商都能站在用户角度考虑问题,相信广告收入也会增长不少吧。<p>更多心得:
1).我们不缺乏技术,缺的是将技术活用的创新思想和研究精神
2).Web性能优化不是前端一家之事,与开发、运维等部门通力合作会让效果更给力
3).站在用户角度考虑问题
4).结合自身业务,找到最优方案
5).一切皆权衡
6).fast by default</p><p>回来听说BigPipe方案是蒋长浩利用休陪产假的时候研究的,想到下个月我也要开始休陪产假,能否也可以有他一样的创新呢,呵呵。不过国内的陪产假时间太短了,不给力啊!</p><p>最后再秀下Steve的签名,送给自己,继续为”make the web a fast place”而努力!
Steve的签名</p><p>PS:
大会的PPT和视频可以在官网下载。</p>

标签: velocity , wpo
<<< EOF