Actually,simplicity is not simple

用JS动态监听CSS加载

周五时有个工作时需求等CSS加载完后后再执行些JS代码,但发现使用onload在Firefox chrome下不行但IE8下却可以。

第一次发现IE也有让我省心的时候啊!

问谷大叔得知研究这问题的人还挺多的:

  • 在射雕的lab中发现有两个测试 load js css css preload,讲得挺多的,而且在其seajs中已经运用上了,拜之~~
  • 在国外一相当大的专业问答网站中找到相同问题,也有不少人给出了解答 javascript capturing load event on link。主要讲到两种方案:
    1. 使用settimeout循环判断不同浏览器中当CSS加载完或失败时的特性,射雕使用的方案也是这种,但特性有所不同;
    2. 方案挺有意思的,同时创建link、img标签并将CSS的URL同时赋于两个标签,用img标签的onerror事件做为加载监听器,但这种方案会产生两个请求,并且img标签所发出的请求会标注不支持gzip。
  • Cross Browser Stylesheet Preloading中也提供了一解决方案,但代码是基于mootools写的,最重要的一点是延时判断link标签的ownerNode或owningElement属性,没用过这两个属性,不懂!!!

继续问谷大叔找到关于ownerNode(返回节点与此相关联的样式表文件的。)以及owningElement(返回附加到元素节点上的属性)的定义。

this.link.id = this.getID(); // 创建link标签时给标签加上了ID属性
// 注意 这里的file = document.styleSheets[0]; 或 document.getElementsByTagName('link')[0].sheet;
var owner = file.ownerNode ? file.ownerNode : file.owningElement;
if(owner && owner.id == this.getID()) {
    this._onready();
    return;
}

并且看到了对link标签事件支持情况:

IE6-IE9、opera  都支持link标签的 onload  onerror事件
firefox chrome  safari 都不支持link标签的 onload  onerror事件

CSS命名的那点事

又是很久没写过东东了,今天在看张鑫旭blog中的《精简高效的CSS命名准则/方法》时,产生了不小的共鸣。

CSS的命名我使用过很多种方式:

  • 用功能名的拼音。感觉很二,也很长,写多了很快就不明白是什么了,因为我拼音也用得不多,打字一直用五笔,写多了就无法很快了解当前样式的意思。
  • 用功能名的对应英文词组组合。到是不会让自己感觉很二,但我自己的英文菜得无法言语,所以在写CSS时常常开着google的翻译网页,呵呵,不怕各位笑话。
  • 基于CSS属性命名些常用的样式。这是在我写CSS一段时间后慢慢形成的习惯,因为记忆方便,不用写个样式就去想下应该命名成什么。如果有独特需求也只需联合父层就可以进行独特需求的设置了。在我看来这种写法是将CSS属性进行最小单元封装的过程,但这样做也不是没有问题,后面会说到。

但我却从来没有总结过,惭愧啊~~

现在我接到项目一开始很是喜欢在头上写些样式,都成了我写页子的习惯了:

.cRed{color:#F00;}
.tC{text-align:center;}
.b{font-weight:700;}
.....

在写功能模块时给它一个ID,之后的样式就像

#mod .b{...}
#mod .tC{}

这样CSS不会有很多层,样式名也很短,我也不用在每次加入CSS时为想个样式名而花时间了。

这样的命名用起来很舒服,但也不是一点问题没有,如后期的维护上,需求改变时……,对面大量HTML源文件或被JS、PHP等语言引入到代码中的结构,修改它们是个痛苦的过程。

想当初CSS被疯狂提倡时的理由之一就是无需对HTML进行大规模的修改只需改个CSS的性能就能完成所要的。但这种方法进行的却是对CSS属性进行最小单元的封装,样式名称与属性名有着直接的联系,如果要进行修改,改CSS的性能就有点不妥了,让样只能让CSS看起来更加混乱。

所以使用这种方法需要有个平衡点,在定义模块结构时我不会使用这种方式,对于模块的建立我喜欢这样写:

<div id="modName" class="XXX">
    <div class="head">
        <div class="tit">
            <h3>模块名</h3>
        </div>
    </div>
    <div class="con"></div>
    <div class="floot"></div>
</div>

这里面的样式 head tit con floot在最外层都不会定义,起始定义点是#modName .head这样的,当然根据需求结构会有些不同,但基本是这样的。

所以我现写的CSS层级一般是两层,最多也就是四层。

MOSe这词就是有病

今天我一朋友问我MOSe是什么? 答不上来,难道我又落伍了?

后发现它的意思是MOSe(Mozilla,Opera, Safari enhancement)。

我晕倒,不就是非IE浏览器嘛,又整个新名词出来干什么!

2003年,加拿大设计师、CSS Zen Garden创始人Dave Shea写了一篇备受关注的文章,阐述了如何跨越那些相互竞争的拥有不同特性的浏览器进行的设计创作的新途径,他把这个途径叫做MOSe(Mozilla,Opera, Safari enhancement)。

看这意思是说通过各浏览器自身的私有方法来实现统一的样式,就我郁闷,这些东西CSS3中都定义好了,为何整出个自己的么有属性,是觉得CSS设计人员还不够累吗?

MOSe又是个旧瓶装新“酒”,多少年来CSS设计人员都是这么写的,现整出个名词干什么?给设计人员平反吗?

读Cross-Browser Inline-Block后的笔记

看到一篇很讲解inline-block的文章,相当不错,能在所有浏览器上使用,记录下。

比如有以下的HTML结构,想让其平行的显示:

<ul>
    <li>
        <img src="http://studynote.cn/blog/wp-content/themes/Asinsimple/images/logo.png" alt="简单其实不简单" />
        <h4>This is awesome</h4>
    </li>
    <li>
        <img src="http://studynote.cn/blog/wp-content/themes/Asinsimple/images/logo.png" alt="简单其实不简单" />
        <h4>This is awesome</h4>
    </li>
……
</ul>

一般说来,这种类型的布局是小菜一桩。固定宽度,固定高度,向左浮动就解决了,理想中的CSS代码如下:

li {
    width: 200px;
    min-height: 250px;
    border: 1px solid #000;
    display: inline-block;
    margin: 5px;
    vertical-align: top;
}

事实上上面的代码在 Firefox 3, Safari 3 和 opera 中的效果没有问题,就算

中的文字发生变化也能有很好的效果。但IE6、IE7、Firefox2 就没那么好了,全都乱七八糟的。 原文中介绍了如何解决这些问题,涉及到了很多CSS的知识点,其原文的HTML结构如下:

<ul>
    <li><div>
        <img src="http://studynote.cn/blog/wp-content/themes/Asinsimple/images/logo.png" alt="简单其实不简单" />
        <h4>This is awesome</h4>
    </div></li>
    <li><div>
        <img src="http://studynote.cn/blog/wp-content/themes/Asinsimple/images/logo.png" alt="简单其实不简单" />
        <h4>This is awesome</h4>
    </div></li>
……
</ul>

CSS如下:

li {
    width: 200px;
    min-height: 250px;
    border: 1px solid #000;
    display: -moz-inline-stack;
    display: inline-block;
    vertical-align: top;
    margin: 5px;
    zoom: 1;
    *display: inline;
    _height: 250px;
}

这段CSS解决了IE6、IE7、 Firefox2不支持inline-block的问题。做下笔记吧!自己的学习还是不到家啊!

  1. 使用display: -moz-inline-stack;属性解决 Firefox2 不支持inline-block的问题,但又带来了新的问题(所有FF对于所有的属性为stack(包括-moz-inline-stack)的元素,它的第一级子元素会继承该元素的宽度和高度,但是子元素的子元素不会再继承)。解决的办法是在DIV内加入个新的标签,但就我个人而言完全没有这个必要,99.9%的使用Firefox用户都是勤于更新版本的。
  2. 使用zoom:1;激发IE的 hasLayout 属性, 再加上*display:inline;之后,在 IE7 中它们就可以像 inline-block 一样显示了(其实我对这方面的了解也不多,还没有理解,所以写不出达多的文字)。还使用了display: inline;这一属性,display前面加个星号()的写法是用来区分于其它浏览器的,*display这种写法只有IE7以下的浏览器才能支持。
  3. 使用 _height: 250px; 解决IE6不支持min-height属性的问题,因为IE6 对 height 属性的不正确处理(即当内容的高度超过了容器设置的高度后,IE6会自动改变窗口的高度),使得我们可以这样使用。_height这种法写只有IE7以下的浏览器才能支持。

综上我认为比较好的写法是不考虑Firefox2的问题,

<ul>
    <li>
        <img src="http://studynote.cn/blog/wp-content/themes/Asinsimple/images/logo.png" alt="简单其实不简单" />
        <h4>This is awesome</h4>
    </li>
    <li>
        <img src="http://studynote.cn/blog/wp-content/themes/Asinsimple/images/logo.png" alt="简单其实不简单" />
        <h4>This is awesome</h4>
    </li>
……
</ul>

li {
    width: 200px;
    min-height: 250px;
    border: 1px solid #000;
    **display: inline-block;**
    vertical-align: top;
    margin: 5px;
    **zoom: 1;**
    ***display: inline;**
    _height: 250px;
}

原文地址:http://blog.mozilla.com/webdev/2009/02/20/cross-browser-inline-block/

译文地址:http://www.qianduan.net/cross-browser-inline-block.html

有些涉及到的知识点可以阅读以下文章:

区分浏览器的 hack:http://www.ejeliot.com/blog/63

IE hasLayout:http://adamghost.com/2008/12/ie-haslayout-详解/

PS:从上面可以知道想让现有浏览器都支持display:inle-block;可以这样写:

span{display: inline-block;zoom:1;*display:inline;}

CSS的优先权

优先权问题其实就是一个冲突解决的问题,当同一个元素(或内容)被CSS选择符选中时,就要按照优先权取舍不同的CSS规则,这其中涉及到的问题其实很多。

首先就是CSS规则的specificity(特殊性),CSS2.1有一套关于specificity的计算方式,用一个四位的数字串(CSS2是三位)来表示,最终specificity越高的规则越特殊,在优先级判定时也就越有优势。关于specificity的具体计算在各种情况下的数字加成有如下一般规则:style

  • 每个ID选择符(#someid),加 0,1,0,0。
  • 每个class选择符(.someclass)、每个属性选择符(形如[attr=”"]等)、每个伪类(形如:hover等)加0,0,1,0
  • 每个元素或伪元素(:firstchild)等,加0,0,0,1
  • 其他选择符包括全局选择符*,加0,0,0,0。相当于没加,不过这也是一种specificity,后面会解释。
  • 按这些规则将数字串逐位相加,就得到最终计算得的specificity,然后在比较取舍时按照从左到右的顺序逐位比较。

举一些例子吧:

[CSS]
h1 {color: red;}
/* 只有一个普通元素加成,结果是 0,0,0,1 */
body h1 {color: green;}
/* 两个普通元素加成,结果是 0,0,0,2 */
/*0,0,0,1 小于 0,0,0,2 ,后者胜出*/

h2.grape {color: purple;}
/* 一个普通元素、一个class选择符加成,结果是 0,0,1,1*/
h2 {color: silver;}
/*一个普通元素,结果是 0,0,0,1 */
/*0,0,1,1 大于 0,0,0,1 ,前者胜出*/

html > body table tr[id=”totals”] td ul > li {color: maroon;}
/* 7个普通元素、一个属性选择符、两个其他选择符(子选择符 >),结果是0,0,1,7 */
li#answer {color: navy;}
/* 一个ID选择符,一个普通选择符,结果是0,1,0,1 */
/*0,0,1,7 小于 0,1,0,1,后者胜出*/

除了specificity还有一些其他规则

  • HTML文件内的样式优先级为1,0,0,0,所以始终高于外部定义。这里文内样式指形如blah 的样式,而外部定义指经由< link>或< style>标签定义的规则。
  • 有!important声明的规则高于一切。如果!important声明冲突,则比较优先权。
  • 如果优先权一样,则按照在源码中出现的顺序决定,后来者居上。
  • 由继承而得到的样式没有specificity的计算,它低于一切其他规则(比如全局选择符*定义的规则)。
  • 关于经由@import载入的外部样式,由于@import必须出现在所有其他规则定义之前(如不是,则浏览器应该忽略之),所以按照后来居上原则,一般优先权冲突时是占下风的。

这里需要提一下IE,IE是可以识别位置错误的@import的,但无论@import在什么地方,它都认为是位于所有其他规则定义之前的,这可能会引发一些误会。

所以优先权问题虽然看起来简单,但其背后还是有蛮复杂的机制的,需要多多留意。

文章来自old9, 过不了GFW自己想办法吧!