七月, 2009


28
七 09

标准模式中的 IE 6&7 width 100% bug

在 web app 项目中经常遇到这个 bug,国外称之为100% ≠ 100% bug,又分为两种:

  1. div 的宽度 100% ≠ 100% (IE 6&7)需求:
    1. 标准模式
    2. #container 局部滚动
    3. #asie 固定宽度
    4. #content 自适应宽度

    再复杂一点还会要求两列等高,可参考 http://www.99css.com/?p=40

    HTML

    <div id="container">
        <div id="wrapper">
            <div id="content">
                <h2>Content</h2>
            </div>
        </div>
        <div id="aside">
            <h2>Aside</h2>
        </div>
    </div>

    当然,别忘了 DTD 声明,因为这个只存在于标准模式

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    用之前介绍的HTML5 写法亦可:

    <!DOCTYPE html>

    CSS

    /*简单重置*/
    body, div, h2{margin:0;padding:0;}
    /*设置颜色,方便区分*/
    #container{background:yellow;}
    #content{background:#FF8539;}
    #aside{background:#B9CAFF;}
    /*去除html默认滚动条*/
    html{overflow-y:hidden;}
    /*关键布局代码*/
    #container{height:300px;overflow:auto;}
    #wrapper{float:left;width:100%;margin-left:-200px;}
    #content{margin-left:200px;}
    #aside{float:right;width:200px;}

    #content, #aside{height:200px;}时,即高度未超出#container时一切正常

    #content, #aside{height:400px;}时,出现纵向滚动条

    正常显示效果如下:

    IE 6&7 中 bug 出现:

    原因:IE 6&7 滚动条的宽度未算在 100% 中,理想的状况是:#container 的宽度(100%) + #container 滚动条的宽度
    = body 的 100%,W3C对此的定义:

    In the case of a scrollbar being placed on an edge of the element’s box,
    it should be inserted between the inner border edge and the outer padding
    edge. Any space taken up by the scrollbars should be taken out of (subtracted
    from the dimensions of) the containing block formed by the element with
    the scrollbars.

    Internet Explorer 100% Width Bug》中给出了思路:

    element_selector {
    width: expression(this.parentNode.offsetHeight >
    this.parentNode.scrollHeight ? '100%' :
    parseInt(this.parentNode.offsetWidth - XX) + 'px');
    }

    其中 XX 是滚动条的宽度,在 Windows XP 主题下是 17px,Windows 经典主题下稍微小一点,在其他第三方系统主题下有可能是不确定宽度。

    根据下图,简单改进一下即可

    解决方法

    #wrapper{#width:expression(this.parentNode.offsetHeight > this.parentNode.scrollHeight ? '100%' : parseInt(this.parentNode.clientWidth) + 'px');}

    当然,写在 js 中亦可,不过要注意不要漏掉 window 的 riseze 事件,另外,window 的 resize 事件在 IE 中有执行多次的
    bug

  2. body 的宽度 100% ≠ 100% (仅 IE6)通常表现为 iframe 出现纵向滚动条时同时出现横向滚动条,简单粗暴的使用body{overflow-x:hidden;}是不负责任的,有时会截断要显示的内容第一个页面(父页面)
    <iframe frameborder="0" height="300" scrolling="auto" src="iframe.html" width="500">

    第二个页面(iframe)

    HTML

    <div></div>

    CSS

    body, div{margin:0;padding:0;}
    div{background-color:yellow;height:500px;}

    正常效果

    IE6

    解决方法(原理同上)

    body{_width:expression(this.parentNode.offsetHeight > this.parentNode.scrollHeight ? '100%' : parseInt(this.parentNode.clientWidth) + 'px');}

24
七 09

[翻译] gzip 压缩原理

译注:本打算翻译这篇文章的,搜了一下已经有人翻译过了,不过网站失效,通过快照获取了部分内容,在此基础之上进行了一些修改,感谢 bloglei

译注:以上是 youtube 视频,请翻墙观看(文中图片调用自 picasa,若显示不了也要翻墙)

浏览器请求有无 gzip 压缩的高级预览

服务器未 gzip:

浏览器:

  • 连接服务器并请求页面。
  • 通知服务器,浏览器支持 gzip “Accept-Encoding: gzip”。

服务器:

  • 不支持 gzip。忽略 gzip 请求。发送未压缩的页面。

浏览器:

  • 接收页面。
  • 显示页面。

服务器 gzip:

浏览器:

  • 连接服务器。
  • 通知服务器,浏览器支持 gzip “Accept-Encoding: gzip”。

服务器:

  • 收到 gzip 支持通知。
  • 发送 gzip 编码过的页面,并设置响应头“Content-Encoding: gzip”。

浏览器:

  • 接收页面。
  • 根据响应头“Content-Encoding: gzip” 解码 gzip 编码过的页面。
  • 显示页面。

如何进行 gzip 压缩

简单的说,gzip 压缩是在一个文本文件中找出类似的字符串,并临时替换他们,使整个文件变小。这种形式的压缩对 web 来说特别适合,因为 HTML 和 CSS文件通常包含大量的重复字符串,例如空格,标签,及样式定义。

例子

在这个例子中,我将用一小段代码演示 gzip 压缩中用相同的标签跟不同的标签的对比。

在第一段代码中,我用了5个标题标签。

未压缩: 69 bytes

压缩后: 85 bytes (译注:某天77问我怎么压缩后比压缩前还大?我回来后看了下原文并测试了一下,事实如此,并非翻译错)

<h1>One</h1><h2>Two</h2><h3>Three</h3><h4>Four</h4><h5>Five</h5>

把标题标签改为相同的 div 标签,源代码增大了 10 bytes,但是压缩后,它缩小到 66 bytes,比先前的源代码片段还小!

未压缩: 79字节

压缩后: 66 字节

<div>One</div><div>Two</div><div>Three</div><div>Four</div><div>Five</div>

许多开发者可能依此只使用 div 和 span 标签而使页面更大程度的压缩。在多数情况下当然无可非议,但必须注意到正确的语义化标记对可访问性(accessibility)来说非常重要,而且使页面更容易阅读。即便如此,可以使用此方法做一些优化,这取决于你,开发者来决定哪些是合适的。

延伸阅读


13
七 09

[翻译]纯 CSS 无 Hack 跨浏览器的多列等高

纯 CSS 打造多列等高并不像想象中那么容易。本文着重讲述多列布局出现的问题,之后提供一个在所有浏览器都正常工作的简单解决方案。这个方法 100% 无 CSS hack,无图片,无 javascript,甚至可以用在最严格编码的网站上。

多列等高的问题

上例中有包含不同内容的 3 列,可以看出存在的问题是列的背景色随着其包含内容的高度而自适应展开。这是我们要解决的问题。如何使所有的列等高?或具体的说,如何使所有列的高度等于最高列的高度?这很棘手,因为我们不清楚每列将会多高,哪一列是最高的。不能简单的给所有列一个固定的高度,如果内容很少将会导致页面底部有大片空白;如果内容太多则会在文字显示完全前关闭。两种情形都不妥。实际上,内容的长度是动态的,所以每列的高度也是动态的。必须意识到Web 上没有固定的东东,乡民们有不同的屏幕分辨率,浏览器中的文字也可能被设置为任意大小,所有这些都会影响内容的高度。

分离列内容与其背景色

解决等高问题的第一步是把能分离的破开。方法是每列用两个 div 替代原来的一个。第一个 div 用来放内容,另一个用来作背景色。分离使我们可以单独控制这些额外的元素,之后用更有效的方法把它们放在一起。答案呼之欲出。

浮动的容器的高度始终取决于其浮动的内容(高度)

这是本文多列等高方法的核心。 使一个 div 的高度等于最高列高度的唯一方法是这个 div 包含所有的列。换句话说,通过把所有的列放在一个容器中,容器的高度就是最高列的高度。这是个非常有用的结构。

3列 HTML div 结构

上例中 3 个内容列在一个 div 容器中。

<div id="container1">
    <div id="col1">Column 1</div>
    <div id="col2">Column 2</div>
    <div id="col3">Column 3</div>
</div>

3 列 CSS

下面是使 div 容器等高于最高列的 CSS。

#container1 {
    float:left;
    width:100%;
}
#col1 {
    float:left;
    width:30%;
    background:red;
}
#col2 {
    float:left;
    width:40%;
    background:yellow;
}
#col3 {
    float:left;
    width:30%;
    background:green;
}

为了让这一结构在所有浏览器中正确工作,容器 div 必须浮动(左或右),同时每一个内容列的 div 也要浮动,哪种方式并不重要。浮动内容 div 的进程使它们在页面中排列在一条水平线上。浮动容器使其自适应到最高列的高度。如果不浮动容器,内容
div 将会从容器底部溢出,容器不会拥有正确的高度。事实上在此例中,容器不浮动的话其最终高度为0。

增加额外嵌套的容器

下一步是增加额外的容器,它们彼此嵌套。我们需要容器的数量等于列的数量:3。这 3 个容器用作各列的背景。请注意,我们去除了原始列的背景色,并将其加至容器上。

3列 HTML div 结构

两个额外的容器加至下面的 HTML 中。

<div id="container3">
    <div id="container2">
        <div id="container1">
            <div id="col1">Column 1</div>
            <div id="col2">Column 2</div>
            <div id="col3">Column 3</div>
        </div>
    </div>
</div>

3 列 CSS

所有元素左浮动,容器宽度设为100%,使他们占满页面的宽度。背景色从内容 div 移除并加至容器上。

#container3 {
    float:left;
    width:100%;
    background:green;
}
#container2 {
    float:left;
    width:100%;
    background:yellow;
}
#container1 {
    float:left;
    width:100%;
    background:red;
}
#col1 {
    float:left;
    width:30%;
}
#col2 {
    float:left;
    width:40%;
}
#col3 {
    float:left;
    width:30%;
}

用相对定位移动容器

现在用相对定位把容器移至新的位置。移动后 div 如下图所示。即等高列背景容器的层叠和位置。为了显示右侧的绿色列 container2 向左移了30%,为了显示中间的黄色列container1 向左移动了40%,与此同时红色部分依然可见作为左侧列。

相对定位的 CSS

下面是添加了相对定位的CSS。

#container3 {
    float:left;
    width:100%;
    background:green;
}
#container2 {
    float:left;
    width:100%;
    background:yellow;
    position:relative;
    right:30%;
}
#container1 {
    float:left;
    width:100%;
    background:red;
    position:relative;
    right:40%;
}
#col1 {
    float:left;
    width:30%;
}
#col2 {
    float:left;
    width:40%;
}
#col3 {
    float:left;
    width:30%;
}

将每列的内容移回

下一步是把每列的内容移回到页面上,使之排列在下面的背景色上。再次使用简单的相对定位来完成它。

最后在最外面的容器 container3 上添加overflow:hidden,砍去超出容器的部分。

相对定位的 CSS

下面是增加了相对定位和溢出的 CSS 规则。请注意 container3 上额外的position:relative; 这是为了解决一个
IE bug ,阻止overflow:hidden;工作。

#container3 {
    float:left;
    width:100%;
    background:green;
    overflow:hidden;
    position:relative;
}
#container2 {
    float:left;
    width:100%;
    background:yellow;
    position:relative;
    right:30%;
}
#container1 {
    float:left;
    width:100%;
    background:red;
    position:relative;
    right:40%;
}
#col1 {
    float:left;
    width:30%;
    position:relative;
    left:70%;
}
#col2 {
    float:left;
    width:40%;
    position:relative;
    left:70%;
}
#col3 {
    float:left;
    width:30%;
    position:relative;
    left:70%;
}

对列增加 padding

最后还需对列增加 padding,这样每列边缘的文字不至于显得拥挤。如果我们增加 padding,一些浏览器中可能正常显示,但不是所有。IE 错误的盒模型,导致其估算拥有padding 的元素宽度异常。一个 200px 宽 20px padding 的 box 在 IE 中被视为 200px 宽,在其他浏览器中则为正确的 240px。padding应该加在元素的宽度上。凸微软!

不过不用担心…我们可以用完全不依赖于 padding 的方法来解决这个问题。相反,我们把列弄窄一点(列宽减去两侧的 padding),之后用相对定位把它们移至正确的位置。在我们的例子中我们用了2% 的 padding,则 30% 的列将减至 26%,40% 的列减至 36%。用相对定位移回列时需谨记,现在列变窄了,所以当它们一起像最初那样左浮动时,每一个需要比上一个移动更远的距离。

完整的CSS

为了使布局保持在小宽度我在每个内容列增加了overflow:hidden; 这将切去超出列宽的东东,并阻止其干扰其他布局。重申一下,这只是IE 的问题,其他所有浏览器会保持正确的布局,不管列内是虾米。如果你真想这样做,可以用 IE 条件注释只对 IE 写规则。

#container3 {
    float:left;
    width:100%;
    background:green;
    overflow:hidden;
    position:relative;
}
#container2 {
    float:left;
    width:100%;
    background:yellow;
    position:relative;
    right:30%;
}
#container1 {
    float:left;
    width:100%;
    background:red;
    position:relative;
    right:40%;
}
#col1 {
    float:left;
    width:26%;
    position:relative;
    left:72%;
    overflow:hidden;
}
#col2 {
    float:left;
    width:36%;
    position:relative;
    left:76%;
    overflow:hidden;
}
#col3 {
    float:left;
    width:26%;
    position:relative;
    left:80%;
    overflow:hidden;
}

好了,就是这样。我希望这篇文章对你有用。可以自己弄一下 CSS 看一下它是如何工作的。你可以搞很多列,只要容器和内容列的数目相等。不要忘记看看我的 demo:2列 3列4列,以及5列