更新

  1. window.getComputedStyle(node,pseudo)[property]不能取:visited的值,这里的“pseudo”应该是”Pseudo-Element(伪元素)”而不是“伪类”。

起因

mozilla发布了firefox4 beta 1,更新了一些CSS属性,不知道你有没有注意到其中有一条关于:visited伪类的更新,为了保护用户的隐私,限制绝了绝大多数的css样式应用到:visited元素上,这其中就包含了一些我们常用于访问过链接的CSS属性,比如backgroundborder-colorfont。比如我的博客,对访问过的链接,就会用content属性生成一个勾,提示读者这个链接他已经访问过了。我尝试了几个常用的CSS属性,只有color依然有效。

既然color仍然有效,不知道mozilla这样做有什么意义?在这个越来越注重可用性的时代,不考虑:visited样式绝不是一个好的做法,说句题外话,各位设计师们应该在设计中考虑更多的css伪类样式,而不局限于:hover,按下一个按钮、表单获得焦点这些动作没有反馈是一件令人沮丧的事。言归正传,限制那么多的CSS属性运用于:visited将大大降低设计师的创作空间。访问后变色本身又是一个不受大多数人喜欢的标识方法,a,a:visited{color:XXX;}是绝大多数网站的做法。只能用两个字形容我的现在的心情:“我操”。

如何窥探

我没有去查这个隐私问题到底是怎么发生的,我的猜测就是用脚本去遍历链接,判断它的:visited样式有没有生效,生效了就说明访问过了。这里原理类似我的这篇文章:Browser Detector With CSS真想问问mozilla为什么不从js下刀呢,为什么不去限制window.getComputedStyle(node,pseudo)[property]:visited的值?IE知道这事笑了,“哈哈,我不支持用js取伪类样式!”。[1]基本代码如下,请忽视转换色值的函数:

[Demo]用firefox4看看是不是只有颜色生效了? [Demo]看看你访问过哪里?


a:visited{color:#f00;}

var Color = {
    "toHex" : function(rgb){
        var a = rgb.replace(/rgb\(|\)/g,"").split(","),
              hex = "";
        for (var i = 0;i < 3;i++){
            var b = parseInt(a[i]).toString(16);
            hex += (b.length === 1)?"0"+b:b;
        }
        return "#" + hex;
    },
    "toComplate" : function(hex){
        if (hex.length === 4){
            var hex = hex.toLowerCase(),
                  newHex = "";
            for (var i = 0;i < 3;i++){
                var a = hex.substring(i+1,i+2);
                newHex += a + a;
            }
            return "#" + newHex;
        }else{
            return hex;
        }
    }
};
function getColor(node,property){
    if(node.currentStyle){
        return Color.toComplate(node.currentStyle[property]);
    }
    if(window.getComputedStyle){
        return Color.toHex(window.getComputedStyle(node,null)[property]);
    }
}
var links = document.getElementsByTagName("a");
for(var i = 0,j = links.length;i<j;i++){
    var color = getColor(links[i],"color");
    if(color === "#ff0000"){
        alert("你访问过:"+links[i].firstChild.nodeValue);
    }
}