Archive for the ‘前端技术’ Category

September,28th,2009

也谈 CSS Sprites

CSS Sprites 简介:通常被意译为“CSS图像拼合”或“CSS贴图定位”。CSS Sprites并不是一门新技术,目前它已经在网页开发中发展得较为成熟,阿里巴巴各子公司的网页中到处都可发现css sprites 的影子。但CSS Sprites并不是什么金科玉律,但在很多情况下,它有着一定的优势,最重要的是它可以减轻服务器的负载,提高网页加载速度。随着Web设计向着精致、巧妙的方向发展,设计师们开始考虑使用非Javascript的方 式制作鼠标滑过、悬停菜单的效果,这时CSS Sprite应运而生。

说白了,CSS Sprites其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位,background-position可以用数字能精确的定位出背景图片的位置。

当页面加载时,不是加载每个单独图片,而是一次加载整个组合图片。这是一个了不起的改进,它大大减少了HTTP请求的次数,减轻服务器压力,同时缩短了悬停加载图片所需要的时间延迟,使效果更流畅,不会停顿。
CSS Sprites应用:在这方面,淘宝网做的比较好,我就以淘宝网为例吧。
[实例一:淘宝频道页面导航]
效果图:

sprites图:

[实例二:淘宝首页]
效果图:

sprites图:

CSS Sprites优点:CSS Sprites为什么突然跑火,跟能够提升网站性能有关。显而易见,这是它的巨大优点之一。
1.利用CSS Sprites能很好地减少了网页的http请求,从而大大的提高了页面的性能,这是CSS Sprites最大的优点,也是其被广泛传播和应用的主要原因;
2.个人认为CSS Sprites能减少图片的字节,我曾经比较过多次3张图片合并成1张图片的字节总是小于这3张图片的字节总和。
CSS Sprites缺点:诚然CSS Sprites是如此的强大,但是也存在一些不可忽视的缺点。
1.在图片合并的时候,你要把多张图片有序的合理的合并成一张图片,还要留好只够的空间,防止板块内不会出现不必要的背景,否则可能会出现出现干扰图片的情况;这些还好,做痛苦的是在宽屏,高分辨率的屏幕下的自适应页面,你的图片如果不够宽,很容易出现背景断裂;
2.CSS Sprites在开发的时候比较麻烦,你要通过photoshop或其他工具测量计算每一个背景单元的精确位置,这是针线活,没什么难度,但是很繁琐;不过网上已经有高手开发出“CSS Sprites 样式生成工具”,大家可以尝试一下。
3.CSS Sprites在维护的时候比较麻烦,sprites是一般双刃剑,如果页面背景有少许改动,一般就要改这张合并的图片,无需改的地方最好不要动,这样避免改动更多的css,如果在原来的地方放不下,有只能(最好)往下加图片,这样图片的字节就增加了,因为每次的图片改动都得往这个图片删除或添加内容,显得稍微繁琐,而且重新算图片的位置(尤其是这种上千px的图)也是一件颇为不爽的事情。当然,在性能的口号下,这些都是可以克服的。
4.由于图片的位置需要固定为某个绝对数值,这就失去了诸如center之类的灵活性。
CSS Sprites总结:性能压倒一切。CSS Sprites非常值得学习和应用,特别是页面有一堆ico(图标)。总之很多时候大家要权衡一下利弊,在决定是不是应用CSS Sprites。为保持兼容性和维护性,sprites图片中的各个部分保持一定的距离是一种不错的做法。

September,28th,2009

javascript反拦截可调节弹出频率背投广告

背投广告特点:
对于背投广告的原理来说并没有什么难度,无非打开的窗口失去焦点(blur),而原来页面得到焦点(focus)。但对于流行的浏览器来说,如果非用户行为的弹出窗口(即onload时,直接window.open),会被浏览器默认拦截。
背投广告,既然被称为广告,那如何才能让广告主的钱花得实在,花得乐意呢?
我们可以增加判断,如果该弹出窗口被浏览器拦截,则只要用户点击页面(onclick)就触发window.open事件,这样一般不会拦截,浏览器会认为这是用户的默认行为。
同时,如果广告总是不断弹出,我想这是对用户的一种折磨,因此设计可调节的弹出频率,比如利用cookie控制一天只可以弹出一次就比较好。

阿里妈妈背投广告代码:

<script type="text/javascript">
//全局变量
var val_pop_w = 950;//广告页面的宽度
var val_pop_h = 90;//广告页面的高度
var val_pop_id = "mm_13250138_1917484_7967317";//广告id
var val_pop_t = 0;//广告距顶top距离
var val_pop_l = 0;//广告距左边left距离
var val_pop_day = 1;//广告频率天
var val_pop_num = 2;//广告频率次数

//添加监听事件
function addListener(element, e, fn){
 element.addEventListener ? element.addEventListener(e, fn, false) : element.attachEvent("on" + e, fn)
}
//删除监听事件
function removeListener(element, e, fn){
 element.removeEventListener ? element.removeEventListener(e, fn, false) : element.detachEvent("on" + e, fn)
}

function openWindowBack(){
 var adPopup = window.open('', '背投广告', 'width=' + (parseInt(val_pop_w) + 1) + ',height=' + (parseInt(val_pop_h) + 1) + ', left=' + val_pop_l + ',top=' + val_pop_t);
 //设置广告页面内容
 var adhtml = "";
 var adjs = "";
 adjs += '<script type="text/javascript">';
 adjs += 'alimama_pid="' + val_pop_id + '";';
 adjs += 'alimama_titlecolor="0000FF";';
 adjs += 'alimama_descolor ="000000";';
 adjs += 'alimama_bgcolor="FFFFFF";';
 adjs += 'alimama_bordercolor="E6E6E6";';
 adjs += 'alimama_linkcolor="008000";';
 adjs += 'alimama_bottomcolor="FFFFFF";';
 adjs += 'alimama_anglesize="0";';
 adjs += 'alimama_bgpic="0";';
 adjs += 'alimama_icon="0";';
 adjs += 'alimama_sizecode="15";';
 adjs += 'alimama_width=' + val_pop_w + ';';
 adjs += 'alimama_height=' + val_pop_h + ';';
 adjs += 'alimama_type=2;';
 adjs += '<\/script><script src="http://a.alimama.cn/inf.js" type=text/javascript><\/script>';
 adhtml += '<html><body style="margin:0;padding:0px;text-align:left;">' + adjs;
 adhtml += '</body></html>';
 adPopup.document.write(adhtml);
}

var pop_back_ad = function(){
 openWindowBack();
 window.removeListener(document, 'click', arguments.callee);
}

function SetCookie(name, value, day)//三个参数,一个是cookie的名字,一个是值,一个保存天数
{
 var Days = day; //此 cookie 将被保存 1 天
 var exp = new Date(); //new Date("December 31, 9998");
 exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);
 document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString();
}
function getCookie(name)//取cookies函数
{
 var arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
 if (arr != null)
 return unescape(arr[2]);
 return null;
}
function delCookie(name)//删除cookie
{
 var exp = new Date();
 exp.setTime(exp.getTime() - 1);
 var cval = getCookie(name);
 if (cval != null)
 document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
}

function chkpopad(n, d){
 var i = 1;
 if (getCookie('popnum') == null){
 pop_back_ad();
 SetCookie("popnum", i, d);
 }
 else if (getCookie('popnum')<n){
 pop_back_ad();
 SetCookie("popnum", parseInt(getCookie('popnum')) + 1, d);
 }
}
try{
 chkpopad(val_pop_num,val_pop_day);//设置背投广告的次数和保存cookie的天数
}catch(e){
 window.addListener(document, 'click', function(){
 chkpopad(val_pop_num, val_pop_day);
 });
}
//delCookie("popnum");//删除cookie
</script>

在写的过程中遇到一个问题,就是IE和FireFox对document和window的解析不一样,刚开始我一头雾水,就请教克良同学,他老人家也是头一回遇到,google了很久,终于
在一个外国论坛上找到解决方案,但具体的原因还是不清楚。

//兼容IE和FireFox的监听事件的写法
//添加监听事件
function addListener(element, e, fn){
 element.addEventListener ? element.addEventListener(e, fn, false) : element.attachEvent("on" + e, fn)
}
//删除监听事件
function removeListener(element, e, fn){
 element.removeEventListener ? element.removeEventListener(e, fn, false) : element.detachEvent("on" + e, fn)
}
//删除监听事件:
window.removeListener(window, 'click', arguments.callee);//这种写法只有IE支持
window.removeListener(document, 'click', arguments.callee);//这种写法兼容IE和FireFox
//添加监听事件:
window.addListener(document, 'click', fn);

背投广告相关问题:
当然如果用户浏览器安装了拦截插件,那很有可能不会弹出(比如Firefox的noscript插件,就不允许任何弹出窗)。方法不是绝对的,也不是最好的,只是用最少的时间来做最效率的事情。
可以通过模拟form提交的方式来弹出窗口,穿越性(相对于一般拦截弹窗的插件)很好,不过无法设置sFeatures参数内容。
demo页面:
http://img.alimama.cn/cms/images/1256207772626.html

July,31st,2009

利用location.hash实现跨域iframe自适应高宽

页面域关系:
主页面a.html所属域A:www.taobao.com
被iframe的页面b.html所属域B:www.alimama.com,假设地址:http://www.alimama.com/b.html

实现效果:
A域名下的页面a.html中通过iframe嵌入B域名下的页面b.html,由于b.html的宽度和高度是不可预知而且会变化的,所以需要a.html中的iframe自适应大小.

问题本质:
js对跨域iframe访问问题,因为要控制a.html中iframe的高度和宽度就必须首先读取得到b.html的大小,A、B不属于同一个域,浏览器为了安全性考虑,使js跨域访问受限,读取不到b.html的高度和宽度.

解决方案:
引入代理代理页面c.html与a.html所属相同域A,c.html是A域下提供好的中间代理页面,假设c.html的地址:www.taobao.com/c.html,它负责读取location.hash里面的width和height的值,然后设置与它同域下的a.html中的iframe的宽度和高度.

代码如下:

a.html代码

首先a.html中通过iframe引入了b.html
<iframe id=”b_iframe” height=”0″ width=”0″ src=”http://www.alimama.com/b.html” frameborder=”no” border=”0px” marginwidth=”0″ marginheight=”0″ scrolling=”no” allowtransparency=”yes” ></iframe>

b.html代码

<iframe id=”c_iframe”  height=”0″ width=”0″  src=”http://www.taobao.com/c.html” style=”display:none” ></iframe>
<script type=”text/javascript”>
var b_width = Math.max(document.body.scrollWidth,document.body.clientWidth);
var b_height = Math.max(document.body.scrollHeight,document.body.clientHeight);
var c_iframe = document.getElementById(”c_iframe”);
c_iframe.src = c_iframe.src+”#”+b_width+”|”+b_height; //http://www.taobao.com/c.html#width|height”
}
</script>
<!–js读取b.html的宽和高,把读取到的宽和高设置到和a.html在同一个域的中间代理页面车c.html的src的hash里面–>

c.html代码

<script type=”text/javascript”>
var b_iframe = window.parent.parent.document.getElementById(”b_iframe”);
var hash_url = window.location.hash;
var hash_width = hash_url.split(”#”)[1].split(”|”)[0]+”px”;
var hash_height = hash_url.split(”#”)[1].split(”|”)[1]+”px”;
b_iframe.style.width = hash_width;
b_iframe.style.height = hash_height;
</script>
a.html中的iframe就可以自适应为b.html的宽和高了.

其他一些类似js跨域操作问题也可以按这个思路去解决

July,2nd,2009

window.location.hash的应用及浏览器的支持测试

location是javascript里边管理地址栏的内置对象,比如location.href就管理页面的url,用location.href=url就可以直接将页面重定向url。而location.hash则可以用来获取或设置页面的标签值。比如http://ued.alimama.com#admin的location.hash=”#admin”,利用这个属性值可以实现很多效果。

case one:锚点触发iframe的url更换
html代码:

<dl id=”tbk_help_list”>
<dt>==成为淘宝客==</dt>
<dd><a href=”#faq_1_1″>什么是淘宝客推广?什么是淘宝客?</a></dd>
<dd><a href=”#faq_1_2″ id=”aaaa”>如何注册成为淘宝客?</a></dd>
<dt>==获取推广代码==</dt>
<dd><a href=”#faq_1_5″>获取单件商品推广代码</a></dd>
<dd><a href=”#faq_1_6″>获取一类商品推广代码</a></dd>
<dd><a href=”#faq_1_7″>获取推广组推广代码</a></dd>
<dd><a href=”#faq_1_8″>获取店铺推广代码</a></dd>
</dl>
<iframe src=”faq_1_1.html” frameborder=”0″ allowtransparency=”yes” scrolling=”auto” width=”700px” id=”contentFrame” name=”contentFrame” height=”600px”></iframe>

javascript代码:

<script type=”text/javascript” src=”http://static.alimama.com/js/mootools.js”></script>
<script type=”text/javascript”>
//锚点触发iframe的url更换
var help_dd_a = $(”tbk_help_list”).getElements(”a”);
function geturl(hs){
var hash = hs ? hs : window.location.hash;
if(hash && hash.length >2){
hash = hash.substr(1);
}
var url = hash + “.html”;
window.frames['contentFrame'].location  = url;
}
help_dd_a.each(function(el){
el.addEvent(”click”,function(){
var str = this.href.substr(this.href.lastIndexOf(”#”));
geturl(str);
});
});
</script>

案例截图,图1-1:hashdemo
case two:各种浏览器对window.location.hash的“前进”、“后退”功能是否支持
说明:通过hash调整地址栏的地址,使得浏览器里边的“前进”、“后退”按钮能正常使用(实质上欺骗了浏览器)。然后再根据hash值的不同来显示不同的面板(用户可以收藏对应的面板了),这就使得Ajax页面的浏览趋于传统化了,但是,是否所有浏览器都支持hash的“前进”、“后退”功能呢?
测试说明:点击图1-1中左栏目菜单,看地址栏的变化和iframe的url的变化来判断浏览器是否支持hash的“前进”、“后退”功能。

浏览器 iframe的url是否改变 地址栏hash值是否改变 是否支持
Mozilla Firefox3.0 改变 改变 支持
Google Chrome2.0 改变 改变 支持
IE6 改变 不改变 不支持
IE7 改变 不改变 不支持
IE8 改变 改变 支持

ps:文中“所有浏览器”指列入测试范围的浏览器
结果:除ie6及以下浏览器、ie7不支持外,其他浏览器都支持hash的“前进”、“后退”功能,同时看客们也发现所有浏览器iframe的url都改变了,那是因为所有浏览器都支持iframe的url缓存,这与hash的缓存不是一个概念,所以排除iframe的url的数据干扰。

May,31st,2009

CSS清除浮动常用方法小结

说明:使用xhtml+css布局经常性地会使用到float,很多邪门的事儿都有可能是浮动在作怪,那么清除浮动就是必须要做的,而且随时性地对父级元素清除浮动的做法也被认为是书写CSS的良好习惯之一。


常用的清除浮动的方法有以下三种:

此为未清除浮动源代码,运行代码无法查看到父级元素浅黄色背景。

<style type=”text/css”>
<!–
*{margin:0;padding:0;}
body{font:36px bold; color:#F00; text-align:center;}
#layout{background:#FF9;}
#left{float:left;width:20%;height:200px;background:#DDD;line-height:200px;}
#right{float:right;width:30%;height:80px;background:#DDD;line-height:80px;}
–>
</style>
<div id=”layout”>
<div id=”left”>Left</div>
<div id=”right”>Right</div>
</div>

未清除浮动前如图所示:

未清除浮动图片


三种清除浮动方法如下:


1、使用空标签清除浮动。
我用了很久的一种方法,空标签可以是div标签,也可以是P标签。我习惯用<P>,够简短,也有很多人用<hr>,只是需要另外为其清除边框,但理论上可以是任何标签。这种方式是在需要清除浮动的父级元素内部的所有浮动元素后添加这样一个标签清除浮动,并为其定义CSS代码:clear:both。此方法的弊端在于增加了无意义的结构元素。

ps:<br clear=”all”/>也可以实现效果,但不清楚使用哪个比较好。呵呵

<style type=”text/css”>
<!–
*{margin:0;padding:0;}
body{font:36px bold; color:#F00; text-align:center;}
#layout{background:#FF9;}
#left{float:left;width:20%;height:200px;background:#DDD;line-height:200px;}
#right{float:right;width:30%;height:80px;background:#DDD;line-height:80px;}
.clr{clear:both;}
–>
</style>
<div id=”layout”>
<div id=”left”>Left</div>
<div id=”right”>Right</div>
<p class=”clr”> </p>
</div>


2、使用overflow属性。
此方法有效地解决了通过空标签元素清除浮动而不得不增加无意代码的弊端。使用该方法是只需在需要清除浮动的元素中定义CSS属性:overflow:auto,即可!overflow:auto;是让高度自适应, zoom:1;是为了兼容IE6,也可以用height:1%;的方式来解决,注意,zoom不符合W3C标准.

<style type=”text/css”>
<!–
*{margin:0;padding:0;}
body{font:36px bold; color:#F00; text-align:center;}
#layout{background:#FF9;overflow:auto;zoom:1;}
#left{float:left;width:20%;height:200px;background:#DDD;line-height:200px;}
#right{float:right;width:30%;height:80px;background:#DDD;line-height:80px;}
–>
</style>
<div id=”layout”>
<div id=”left”>Left</div>
<div id=”right”>Right</div>
</div>


3、使用after伪对象清除浮动。
after伪对象非IE浏览器支持,所以并不影响到IE/WIN浏览器。具体写法可参照以下示例。使用中需注意以下几点。一、该方法中必须为需要清除浮动元素的伪对象中设置height:0,否则该元素会比实际高出若干像素;二、content属性是必须的,但其值可以为空,蓝色理想讨论该方法的时候content属性的值设为”.”,但我发现为空亦是可以的。

<style type=”text/css”>
<!–
*{margin:0;padding:0;}
body{font:36px bold; color:#F00; text-align:center;}
#layout{background:#FF9;}
#layout:after{display:block;clear:both;content:”";visibility:hidden;height:0;}
#left{float:left;width:20%;height:200px;background:#DDD;line-height:200px;}
#right{float:right;width:30%;height:80px;background:#DDD;line-height:80px;}
–>
</style>
<div id=”layout”>
<div id=”left”>Left</div>
<div id=”right”>Right</div>
</div>

清除浮动后如图所示:

清楚浮动后的图片

此三种方法各有利弊,使用时应择优选择,多次实践发现,第三种方法更为可取,既不用添加多余无意义的标签,又实用有效 。