浏览器信息探测工具

今夜做了一个浏览器嗅探工具,作用为三:

  1. 用于运营同学日常帮用户处理问题时,第一时间识别浏览器信息。
  2. 用于开发时面对常用浏览器的一些模式探测。《关于浏览器模式和文本模式困惑》
  3. 针对360的浏览器提供一些识别方案 (见源码)。

工具功能还很弱小,会视需求日后升级。

地址:http://hao.360.cn/zt/browserinfo.html

以下对识别360安全浏览器做出一些说明:

由于360发展的历史比较坎坷,360安全浏览器的UA也会随之做出调整。
通常新装的360安全浏览器的user-Agent会含有关键字”360se”,同学们可以用到此特征。

但当特定的时期(如3Q大战期)或由用户勾选以下设置后

360安全浏览器的UA就不会携带“360se”了。

此时,在部分情况下,大家可以用以下代码来进行判定:

var is360se = false
try{is360se=external.twGetRunPath.toLowerCase().indexOf("360se")>-1?!0:!1}catch(e){}

若要识别360安全浏览器除了使用UA关键字或external.twGetRunPath接口外并无更有效的方式了。
其他的一些近乎奇技淫巧之艺,还请多多谨慎。

统计日志打点方案的权衡

简单的开场白:最近一段时间是经常接触前端所部署的统计代码,360导航目前所用的这款代码也是2010年某位同学写得,由于种种原因,一直想重构却始终未完成这部分工作。这篇小文简单说一下,前端发送统计日志的集中方案及其优劣。

就我所知,页面中要想发起一个http请求有如下两大阵营:

  1. DOM型选手:如利用<img/><script/>元素的src属性及其他类似方案
  2. JS型选手:利用javaScript本身的能力(当然要浏览器来支持),即使用 new Image().src 或 XHR等(是否还有其他方式 一时还没想起来)

那么接下来就针对这两大阵营来说明他们在统计日志方面的三种应用

1. <img src=”" />

如果单纯页面上写入<img/>标签,利用制定好的src去发送请求,这绝对是一个最简单的方式。此方式不依赖于JS只依赖DOM,所以只要能正常解析img标签的浏览器无论web还是wap2.0 都可以正常发送统计日志。但同样也有着缺点,那就是无法动态改变打点的URL,也就无法携带更多的信息。这样做的目的只能依靠服务端日志携带的ip,ua,refererUri,sourceUri来做统计。

该方案总结如下:

优点:不依赖JS 能满足几乎所有苛刻的客户端(浏览器)环境
缺点:不能携带动态的数据信息,也就无法做到对uv的统计,通常用于统计ip及pv
(如果在当前页【同域】或打点的http响应中【适时】通过Header的setCookie设置guid,则请求会带上cookie信息,服务端可以做去重统计出uv 但显然有太多的不适及苛刻,不为通常做法。)

2. new Image().src = “”;

这个方案应该是最普通也最朴实地,奇虎的日志发送方案就是如此。一些统计服务如CNZZ统计,量子统计,百度统计,comscore就是靠此发起请求。然而此方案有着一个致命且常犯的坑,也是多年后大家才逐渐发现得。我知道的最早起源见:

http://hi.baidu.com/meizz/blog/item/a0f4fc0ae9d8be1694ca6b05.html

这个弱点简单的描述是:IE的GC机制会导致部分请求不能发送。

以下引一些详细的解释:

垃圾回收,简单的说就是收回某些无用对象所占用的内存以供重新使用,垃圾回收机制通常有一个优先级较低的线程来维护。在java里采用有向树的方式管理内存,那些从根节点出发不可达(unreachable)的对象即被认为是垃圾回收的目标,这种方式有效避免了循环引用的问题。而COM组件(DOM)和Javascript的垃圾回收机制都是基于引用计数(犀牛书上说javascript1.1是基于引用计数的,1.2应该也是),而且在IE里,Dom对象和Javascript对象的垃圾回收又是相互分离的,所以如果这两种对象出现了循环调用就会导致垃圾回收失效,内存泄露,这是IE内存泄露最常见的一种方式。

浏览器的垃圾回收机制对这种”无主”的对象是毫不客气的回收的

参见:
JScript Memory Leaks 译文
How Do The Script Garbage Collectors Work
相关阅读:
Lua Mark-and-Sweep gc(garbage collection-垃圾收集)实现机制详解

当然,这个缺点是有合适方案解决得。

就是将生成的图片对象挂接至window对象上,如

window.log["xxx"] = new Image();

如果踩到坑此坑,那么随着页面业务的复杂,可能会少统计15%左右的有效数据。

该方案总结如下:

优点: 能自由的改变打点URL,方便携带各类信息如点击坐标 点击元素,guid等,这样一来也可以统计UV。
缺点: 依赖JS,要注意在IE中GC机制的影响。

3. 动态插入script标签

这样的打点方式并不多见,我也只是在艾瑞的统计代码中这样见过。方法就不多描述了,原理就是动态生成一个script标签插入DOM树中。
不过这里要提一下此方案的坑,其实就是在head节点下动态插入script常见的坑了。

head.appendChild(s);//<span style="color: #ff0000;">若是这样的方式插入子节点 就有危险喔</span>

这样的方式在IE6某些版的部分页面(如存在BASE节点)会导致请求可能无法完整发送。解决方案就是采用

head.insertBefore( s, head.firstChild );

这样的方式,将原有的向后追加改为向前插入,这也是业内普遍给出的解决方案。
最早发现此问题是在 Jquery1.4.2的bugFix中 注释有如下

// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
// This arises when a base node is used (#2709 and #4378).

BUG案例见:http://bugs.jquery.com/ticket/2709http://bugs.jquery.com/ticket/4378

该方案总结如下:

优点: 同方案2 (虽能避免GC的坑,但本身又隐含着另一个坑,并无太大优势)
缺点: 依赖JS,依赖DOM,要注意在IE6中动态插入DOM的方式。

三种方案总结下来 发现方案三是最不靠谱得,依赖的条件又多,不说占用资源如何,最重要是也同样带来隐患,并无明显优势。

所以一般我们给出的统计日志打点方案最佳实践如下:

<script>
window.log["pv"] = new Image();
window.log["pv"].src= ".....";
</script>
<noscript><img src="..." /></noscript>
上面是方案1和2的结合,当JS不被支持的时候依然可以降级为使用标签的方式(通常用于统计IP及PV了)。
PS. 这些仅是示范代码,具体怎么用 你懂得。

本次小文到此结束,如后续想到其他,再来补上,晚安!

win7+chromium16因transition而导致的页面闪动

近一个月,在使用360极速浏览器 打开新标签页 ,载入360导航,当鼠标滑动一会儿后会突然发现页面有刷新迹象。这种现象约是在上月360极速版内核升级至chrome16后出现得。在忙碌完去年12月的360导航种种变化后,进入2012年的今天,终于有心思去找找这个诡异的问题了。(我本机环境是win7+360极速chromium16 其他环境未跟测)

我试图重现了这种状况,发现每次用全新的标签打开导航后,鼠标滑过顶部的皮肤选择区时,立刻会出现页面闪动。F12打开开发人员工具,在NETWORK选项卡中并未发现“刷新”带来的页面请求,可见这样的闪动不是“刷新”。这样的页面闪动像是在对页面重绘。一开始我以为是特定事件导致得,后来发现在鼠标滑过笑话前的刷新按钮时,也会出现这种现象。经过剥离DEMO测试,可以断定,是由以下css代码造成得。

-webkit-transition:all .2s ease-in;

本能的将“chrome transition”作为关键字去问度娘,立刻找到了淘宝UED最近的文章:

《Chrome渲染Transition时页面闪动Bug》

粗看了一眼,发现遇见的是同样的问题。在360前端群中吼了一声,屈屈说最近有啊的rank也有遇见,并写了如下一文。

《webkit里会出现突然闪一下的问题》

由此两篇文章可以看到大家发现问题的思路及解决方案:

方案一:

-webkit-backface-visibility: hidden;
//不适用于background
//适用于"淘宝"及"有啊"中border形成的小箭头 可见适合元素属性的图形化

(设置进行转换的元素的背面在面对用户时是否可见:隐藏)

方案二:

-webkit-transform:translate3d(0,0,0);
//或
-webkit-transform-style: preserve-3d;
//这两个方式达成了同样的目的 就是指定旗下所有嵌套元素以3D方式进行渲染

(设置内嵌的元素在 3D 空间如何呈现:保留 3D )

关于backface的理解rank已经做了足够的demo页。但是结论“在用position:absulote+zindex!=0时用transform会偶尔出现页面会闪的现象,确实是chrome的一个bug。” 是不完全准确得,我的demo页在chromium16中只要使用transition就复现这种BUG。

<!DOCTYPE html>
<html>
<head>
<meta charset="gbk"/>
<title>Hao360_demo</title>
<style>
.joke{ width:150px;height:22px;line-height:20px;overflow:hidden; }
.joke a{color:#333;display:block; }
.joke .refresh{ margin-top:4px;width:12px;height:12px;overflow:hidden;cursor:pointer;background:url("http://p1.qhimg.com/d/icon/index_icon_111116.png") no-repeat 0 -121px; }
.joke .refresh{ -webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;-o-transition:all .2s ease-in;transition:all .2s ease-in; }
.joke .refresh:hover{ -moz-transform:rotateY(180deg);-webkit-transform:rotateY(180deg);-o-transform:rotateY(180deg);transform:rotateY(180deg); }
</style>
<script charset="utf-8" src="http://s0.qhimg.com/lib/jquery/162.js"></script>
</head>
<body>
<div class="joke" id="headJoke">
<a class="refresh" title="换一条"></a>
</div>
</body>
</html>

我对transform-type的设定及transformation Functions相互影响的原理及更多细节还不甚清楚,这里仅给出W3C规范的解释:

http://www.w3.org/TR/css3-3d-transforms/#transform-functions

方案一 经测试不适用于对background设定的图形或背景色

方案二 风险在于其元素下所有嵌套的元素都会做3D渲染,会影响文本和其他元素样式定义。

对于导航而言 目前的形式还是用方案二合适。至于可能遇见问题的你,请自行判定。

毕竟这是chromium的一个BUG,在未来的版本应该会修复。

BUG已有同学提:http://code.google.com/p/chromium/issues/detail?id=108025

希望尽快改善吧。此一役,我发现有时间该去深挖掘跟进transform和transition的背后了。至少。。我可以跟进 transform的坐标系定义了

 

png32在ie6中的透明化

关于png24与png32

PNG图片格式现在包含三种类型:
1.PNG8
2.PNG24
3.PNG32

如果你经常使用Photoshop,那你这里就会问了:到底PNG32是个什么东西。基本上PNG32就是PNG24,但是附带了全alpha通道。就是说每个像素上不仅存储了24位真色彩信息还存储了8位的alpha通道信息,就如同GIF能存储透明和不透明信息一样。当我们把图片放到不太搭配的背景上的时候,透明PNG图片的边缘会显示得更加平滑。

当然,我也知道你的想法,“但是Photoshop也能生成带透明通道的PNG图片!”我也知道,它只是表面上这么说是PNG24,让我也产生困惑了。

作为一个伤感的Fireworks倡导者,我只使用PNG32支持附带alpha通道的真色彩图片。不管怎样,如果你习惯使用Photoshop,你就应该知道,Photoshop在“存储为WEB格式”中只提供PNG8和PNG24两种PNG格式。

我敢肯定你经常会勾选“支持透明”选项,以获得带有透明度的PNG图片,但是这样你就获取了一张PNG32图片。Photoshop只是觉得把PNG32这个名称给隐藏掉了。奇怪吧?……

原文链接

结论:我们常说的PNG24,一般都为PS输出,就是PNG32。

现实中的问题

IE6下PNG8显示为如同GIF图片一样的无变量的透明(例如,来源),PNG32则在原本显示透明背景的地方显示成了灰色(如下图所示)。

使用AlphaImageLoader修复

IE6(及更老版本的IE)提供了一个针对PNG图片显示的解决方案,通过其私有CSS滤镜。
以下代码可使PNG图片在浏览器中正常显示:

#some-element {
background: url(image.png);
_background: none;
_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='image.png', sizingMethod='crop');
}

部分场景下我们也可这么用
仍然使用<img/>做前景图展现。使用hack对IE6做降级处理,使其背景图使用滤镜,前景图透明度为0

<div style="
width:400px;height:32px;
_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='logo.png', sizingMethod="image");
">
<img style="
_filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);
" src="logo.png" width="400" height="32"/>
</div>

AlphaImageLoader的中文说明

在对象容器边界内,在对象的背景和内容之间显示一张图片。并提供对此图片的剪切和改变尺寸的操作。
如果载入的是PNG(Portable Network Graphics)格式,则0%-100%的透明度也被提供。

语法:

filter : progid:DXImageTransform.Microsoft.AlphaImageLoader ( enabled=bEnabled , sizingMethod=sSize , src=sURL )

enabled: 可选项。布尔值(Boolean) true/false。设置或检索滤镜是否激活。
true:默认值。滤镜激活。
false:滤镜被禁止。

sizingMethod: 可选项。字符串(String)。设置或检索滤镜作用的对象的图片在对象容器边界内的显示方式。
crop:剪切图片以适应对象尺寸。
image:默认值。增大或减小对象的尺寸边界以适应图片的尺寸。
scale:缩放图片以适应对象的尺寸边界。

src: 必选项。字符串(String)。使用绝对或相对 url 地址指定背景图像。假如忽略此参数,滤镜将不会作用。

src 参数,路径相对于web页,即使filter是被定义在特定的css文件中,故建议使用绝对路径

msdn:http://msdn.microsoft.com/en-us/library/ms532969.aspx

一些不常见的问题

  • 浏览器假死
  • 使用更多的内存
    前两条可见此处
  • 部分系统中IE6不支持滤镜 背景图将不被展现(原因还不明)

一些小技巧

  • 背景图做到持久缓存
  • 可优先预加载背景图片

使用VML

使用VML是另一种在IE中使PNG32透明的方法,它解决了几个问题:Alpha透明,性能和背景重复。可惜的是,它使用了非标准标签(也可用JavaScript来生成,如果你希望你的初始标签清爽)和私有CSS。这里有一个如何实现它的例子。

例如,你有一个 的DIV,你需要用VML的 :rect (或 :shape) 和 :fill 标签来把包含它,如:

<v:rect>
  <v:fill type=”tile” src=”alphatest.png”>
    <div>&nbsp;</div>
  </v:fill>
</v:rect>

某些标签之前,你还需要声明VML命名空间:

<xml:namespace ns=”urn:schemas-microsoft-com:vml” prefix=”v” />

而在你的样式表,你需要:

v\:rect  {
  behavior:url(#default#VML);
  width: 100px;
  height: 100px;
  display: block;
}

v\:fill  {
  behavior:url(#default#VML);
}

由“event.layerX and event.layerY”说起

 

最近常常在chrome16(360EE5.1)的控制台看到这样的警告

event.layerX and event.layerY are broken and deprecated in WebKit. They will be removed from the engine in the near future.

看着不爽,但这样明白的提示并非不可理解。诱因也是jQuery1.7发布后告知过得

event.layerX and event.layerY: We have removed these non-standard properties in version 1.7. Although we normally would have gone through a deprecation notice period for these, Chrome version 16 generates a flood of console warning messages on the page. Because of this, we decided to remove them immediately. On platforms that still support these properties, they are available through event.originalEvent.layerX and event.originalEvent.layerY.

event.layerX event.layerY 是mozilla特有的,得到鼠标事件发生地相对源元素的偏移,通常是相对于整个document,除非是发生在绝对或相对定位的元素中,则返回相对于该元素的左上方偏移。

W3C规范中是不存在这样的属性,只有clientX/clientY和screenX/screenY是在规范内得(DOM-Level-2-Events)。

  1.  clientX clientY 事件触发时鼠标相对于当前可视窗口的x坐标和y坐标
  2. screenX screenY 事件触发时鼠标相对于屏幕的x坐标和y坐标
  3. pageX pageY 事件触发时鼠标在整个document的x坐标和y坐标
  4. offsetX offsetY 发生事件的地点在触发事件元素的坐标系统中的 x 坐标和 y 坐标
  5. layerX layerY 发生事件的地点在事件源元素的坐标系统中的x坐标和y坐标

下面是一份广为流传的支持表单

IE Firefox Opera Chrome Safari
clientX / clientY Y Y Y Y Y
pageX / pageY N Y Y Y Y
offsetX / offsetY Y N Y Y Y
layerX / layerY N Y N Y Y
screenX / screenY Y Y Y Y Y

显然layerXY即将在chrome17或之后的版本中退出舞台。
关于这些七七八八的坐标如何使用,有时间再来篇实践吧!

好吧,我也WP了

没有什么好说得,还是WP了吧。

这样格式也是好统一得。

不过总是觉得WP好重,尤其在海外的VPS ,延时就让人觉得更囧了。

默认的theme,整个页面显然还需要WPO,一步步来吧。

var irideas = {domain:"irideas.com"};