由锚点失效引发的hasLayout探究

最近在项目中遇到了一些与锚点相关的问题,由此引出hasLayout的一系列概念和方法,在此记录下来与大家一起分享。

一、锚点的相关问题


1.html map定位的名字问题。


<div id="top">
    <img src="img/20120417/top.jpg" alt="80后游戏" width="950" height="710" border="0" usemap="#map1" />
    <map id="map1" name="map1">
    <area coords="222,176,19"  shape="circle" href="#bk01" title="超级玛丽"></area>
    <area coords="335,185,19"  shape="circle" href="#bk02" title="三国志"></area>
    <area coords="443,163,19"  shape="circle" href="#bk03" title="魂斗罗"></area>
    </map>
</div>

大部分浏览器都支持map的name属性,而webkit内核的浏览器,如chrome和safari,不认识name,必须使用id,否则定位锚点消失。所以这里id和name都用。


2.锚点的hasLayout问题。


一般情况我们做页内导航都习惯用a标签,或者对图片采用map热点定位。然后设定一些锚点用于页面内部内容区块的快速定位,方便浏览者查找。为此需要html中添加代码<a name="abc"></a>或<a id="abc"></a>,这样锚点就设好了。
不管是以a标签链接做导航,还是采用map area定位,其在IE6下锚点都可能存在bug,具体行为就是点击后没有跳转,无法定位。

个人认为这是IE6的Layout没有被触发,这里就需要手动添加CSS代码去激发hasLayout,这里是经过本人测试的几种办法,也是一些最常用的方法:
方法1.由于a是内联元素,所以要使用宽高去触发,必须将其先转化为块级元素。
.jumpAnchor{
    width:0;
    display:block;
}

或者
.jumpAnchor{
    height:0;
    display:inline-block;
}

还有一个方法,就是直接在锚点所在a标签里添加文字或图片内容,让内容去撑开,自动去激发hasLayout。如<a id='anchor' name='anchor'>激发haslayout,我来撑开</a>,
方法2.使用zoom:1;来触发,这个方法的副作用少,不用为此写许多兼容各浏览器的hack。这是目前为止最常用、最安全、最节约成本的激发方式。在个别复杂的情况下,可以搭配使用position:relative;来达到触发hasLayout的目的。

3.锚点本身使用id与name属性的区别。

1)二者的适用范围不同。目标元素的id和name都可以作为锚点,蛋name属性本身具有局限性,而id属性适用于任何类型的目标元素。这里列出name属性适用的几个标签元素:a, map, applet, form, frame, iframe, img
2)二者定位的准确性不同。某些情况下用id存在定位偏移,而name可以准确定位。虽然有解决id定位偏移的方法,但是如果仅仅是作为锚点,建议尽量使用name属性。
3)name属性可以重复而id不可重复,经测试重复的name和独立的id都会定位到第一个,但是为了养成良好的编码习惯,应该避免这样的写法,保持id和name属性值的唯一性。
此外,还需要注意,尽量对这两个属性使用小写字母。虽然html本身不区分大小写,但是对于锚点,在IE下不区分大小写,大写小写是一样的属性值,而在火狐Firefox、谷歌Chrome下大小写就属于两个不同的属性值了。

其实,我们在项目实践中,都经历过形形色色的hasLayout问题。而这些问题又有绝大部分是IE这个大魔头引出的,主要是IE6和IE7。比如设置border边框显示边框断开,设置背景色不能正确显示,3px文本慢移,双边距,躲躲猫(peek-a-boo)。这些都是IE下面因此而生的bug。
插一句,IE6下面3px文本慢移出现的条件是:如果边框框邻近某浮动元素,则边框和浮动边缘之间会出现3px的间隙。在内容清除浮动之前,此间隙不会消失,内容框朝着浮动相反的方向“慢移”三个像素。而当左对齐文本邻近右浮动时,可能难以看到此间隙,但它确实存在,而且它可能导致紧密的布局中出现“浮动下降”。解决“3px文本慢移”的常用方法是:给浮动的盒子添加一个margin-right:-3px;(与浮动方向反方向)。

二、IE下hasLayout布局的触发机制

言归正转,为此,我们要认识hasLayout,了解它,然后才能更好的针对问题找出解决办法。

首先,我们要了解Layout与hasLayout属性是什么?
Layout,意为“布局”,是IE/Windows下的特有概念,它决定了元素如何对其内容进行定位和尺寸计算,与其他元素的关系和相互作用,以及对应用还有使用者的影响。hasLayout为只读属性,对本身不具有Layout的元素,如果其Layout被动触发后是不可逆的。
hasLayout,是IE渲染引擎的一个内部组成部分。在IE中,一个元素计算大小和组织内容,要么对自身的内容进行计算大小和组织内容,要么依赖于父元素来计算尺寸和组织内容。为了调节这两个不同的概念,渲染引擎采用了hasLayout的属性,属性值可以为true或false。当一个元素的 hasLayout属性值为true时,我们说这个元素有一个布局(Layout)。

据不完全统计,默认具有haslyout的HTML标签元素有:<table>、<td>、<body>、<img>、<hr>、<input>、<select>、<textarea>、<button>、<iframe>、<embed>、<object> <applet>、<marquee>、< html>、< tr>、< th>、<fieldset>、< frameset>、<frame> 等。
当网页在IE中有异常表现时,可以首先通过尝试激发haslayout来确定是否为当前容器的Layout没有被激发造成。
接着,我们看如何来激发元素的hasLayout属性。以下是“寂寞贱客”
1、通过设置CSS能够获得的haslayout的属性有:display: inline-block;、height: (任何值除了auto);、float: (left或right);、position: absolute;、 width: (任何值除了auto);、writing-mode: tb-rl;、zoom: (除normal外任意值);、 min-height: (任意值);、 max-height: (除none外任意值);、min-width: (任意值);、max-width: (除none外任意值);、overflow: (除visible外任意值);、overflow-x: (除visible外任意值);、overflow-y: (除visible外任意值);、 position: fixed;(未完全统计)。
2、对于内联元素(默认即为内联的元素,如span,或display:inline; 的元素),width和height只在IE5.x下和IE6或更新版本的quirks模式下触发hasLayout。而对于IE6,如果浏览器运行于标准兼容模式(具有Doctype的模式)下,内联元素会忽略width或height属性,所以设置width或height不能在此种情况下令该元素具有layout。
3、zoom总是可以触发hasLayout,但是在IE5.0中不支持。
4、对IE6及更早版本来说,常用的方法被称为霍莉破解(Holly hack),即设定这个元素的height:1%;。需要注意的是,当这个元素的overflow属性为visible时,这个方法就失效了。曾经流行使用这种方法的时候,还没有出现IE7,而height属性在IE6下其实是按照"min-height"来解析的,所以只要对IE6进行hack,"* html{height:1%}"就可以触发hasLayout,同时又不产生副作用。后来出现的IE7仍然存在很多hasLayout的问题,但IE7已经能够正确识别height属性了,“height:1%”的方法已经不再适用了。
5、对IE7来说,最好的方法是设置元素的最小高度为0px(min-height0;)。

三、IE6下PNG24/PNG32不透明的解决方法


说完了锚点和hasLayout,还有一个常见的问题。我们知道在所有浏览器下都可以支持透明的png8图片,但是有时候是出于清晰度的要求,有时候是为了去除杂边(当然,杂边的消除方式,可以采用ps中添加与背景色一致的杂色而达到目的,不过某些情况下这好像不太现实,比如背景色不是纯色的时候),我们不得不选用位数更高的透明图片,常用的png-24和png-32的。


方法一:定义CSS样式,给某元素应用这个样式后,其透明png背景图片就实现透明了。(注意CSS background背景图片的路径写法与_filter路径写法的区别,_filter属性路径是相对于html文件的位置。)
.toTop a{
    height:165px;
    width:216px;
    background:url("../img/20120417/gototop.png") no-repeat scroll 0 0 transparent;
    position:fixed;
    top:70%;
    right:1%;
    _position:absolute;
    _top:expression(documentElement.scrollTop + 350 + "px");
    cursor:pointer;
    opacity:0.8;
    _background: none; /*针对IE6*/
    _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=noscale, src="img/20120417/gototop.png");/*针对IE6*/
    /*可以省略部分属性为_filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/20120417/gototop.png'); */
}



相关的讲解:
style="filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/test.png')"

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

enabled : 可选项。布尔值(Boolean)。设置或检索滤镜是否激活。 其中true : 默认值,滤镜激活。false : 滤镜被禁止。
sizingMethod : 可选项。字符串(String)。设置或检索滤镜作用的对象的图片在对象容器边界内的显示方式。
属性值:
crop : 剪切图片以适应对象尺寸。
image : 默认值。增大或减小对象的尺寸边界以适应图片的尺寸。
scale : 缩放图片以适应对象的尺寸边界。

src : 必选项。字符串(String)。使用绝对或相对 url 地址指定背景图像。假如忽略此参数,滤镜将不会作用。
属性值:
Enabled : 可读写。布尔值(Boolean)。参阅 enabled 属性。
sizingMethod : 可读写。字符串(String)。参阅 sizingMethod 属性。
src : 可读写。字符串(String)。参阅 src 属性。

说明:
在对象容器边界内,在对象的背景和内容之间显示一张图片。并提供对此图片的剪切和改变尺寸的操作。如果载入的是PNG(Portable Network Graphics)格式,则0%-100%的透明度也被提供。
PNG(Portable Network Graphics)格式的图片的透明度不妨碍你选择文本。也就是说,你可以选择显示在PNG(Portable Network Graphics)格式的图片完全透明区域后面的内容。


方法二:此方法针对直接插入html中的图片。对该图片定义css样式。注意,要准备一个透明的小图片transparent.gif,不要太大否则太大太多影响页面加载性能。此例子中是必须放在和html相同目录下。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>IE6下背景不透明解决办法</title>
<style type="text/css">
.fixpng img {
azimuth: expression(
this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "', sizingMethod='image')",
this.src = "transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "', sizingMethod='crop')",
this.runtimeStyle.backgroundImage = "none")),this.pngSet=true);
}

</style>
</head>

<body>
<div class="fixpng">
<img src="1.png" width="10" height="10" border="0"/>
<img src="2.png" width="20" height="20" border="0" />
<img src="3.png" width="30" height="30" border="0" />
</div>
</body>
</html>


方法三:使用DD_belatedPNG插件,它不仅支持img,还支持backgrond-position与background-repeat.这是优于其他插件的功能.同时DD_belatedPNG还支持a:hover属性。
使用方法

1.下载DD_belatedPNG插件.下载地址http://dillerdesign.com/experiment/DD_belatedPNG/#download
2.在网页html中引用,如下:
<!--[if IE 6]>
 <script type="text/javascript" src="js/DD_belatedPNG_0.0.8a-min.js" ></script>
 <script type="text/javascript">
     DD_belatedPNG.fix('#define,background');
 </script>
<![endif]-->


说明:DD_belatedPNG.fix('CSS选择器, 应用类型');函数 DD_belatedPNG.fix() , 括号内参数分别为应用PNG的CSS选择器(支持ID选择器、类选择器)和应用类型(支持img和background两种)。
多个选择器多种类型的函数,可以连写为类似如 DD_belatedPNG.fix('#idname, .classname, .nav a:hover, img,background');

还有两种网络上的方法,未经测试,写在下面备用。

方法四:本方法也只对直接插入的图片有效,对背景图无效。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>IE6下png背景不透明解决办法</title>
<script language="JavaScript">
function correctPNG() // correctly handle PNG transparency in Win IE 5.5 & 6.
{
    var arVersion = navigator.appVersion.split("MSIE")
    var version = parseFloat(arVersion[1])
    if ((version >= 5.5) && (document.body.filters))
    {
       for(var j=0; j<document.images.length; j++)
       {
          var img = document.images[j]
          var imgName = img.src.toUpperCase()
          if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
          {
             var imgID = (img.id) ? "id='" + img.id + "' " : ""
             var imgClass = (img.className) ? "class='" + img.className + "' " : ""
             var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' "
             var imgStyle = "display:inline-block;" + img.style.cssText
             if (img.align == "left") imgStyle = "float:left;" + imgStyle
             if (img.align == "right") imgStyle = "float:right;" + imgStyle
             if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle
             var strNewHTML = "<span " + imgID + imgClass + imgTitle
             + " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
             + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
             + "(src=\'" + img.src + "\', sizingMethod='scale');\"></span>"
             img.outerHTML = strNewHTML
             j = j-1
          }
       }
    }    
}
window.attachEvent("onload", correctPNG);
</script>
<style type="text/css">
<!--
body {
background-color: #9999CC;
}
-->
</style>
</head>

<body>
<img src="1.png" width="10" height="10" border="0"/>
<img src="2.png" width="20" height="20" border="0" />
<img src="3.png" width="30" height="30" border="0" />
</body>
</html>     


方法五:纯js实现方法。
<script type="text/javascript">
// 修复 IE 下 PNG 图片不能透明显示的问题
function fixPNG(myImage) {
var arVersion = navigator.appVersion.split("MSIE");
var version = parseFloat(arVersion[1]);
if ((version >= 5.5) && (version < 7) && (document.body.filters))
{
     var imgID = (myImage.id) ? "id='" + myImage.id + "' " : "";
     var imgClass = (myImage.className) ? "class='" + myImage.className + "' " : "";
     var imgTitle = (myImage.title) ? "title='" + myImage.title   + "' " : "title='" + myImage.alt + "' ";
     var imgStyle = "display:inline-block;" + myImage.style.cssText;
     var strNewHTML = "<span " + imgID + imgClass + imgTitle

   + " style=\"" + "width:" + myImage.width

   + "px; height:" + myImage.height

   + "px;" + imgStyle + ";"

   + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"

   + "(src=\'" + myImage.src + "\', sizingMethod='scale');\"></span>";
     myImage.outerHTML = strNewHTML;
} }

window.onload=function(){
         document.getElementById("top").style.height=screen.height/5+"px";
        
}//
</script>



引用方法如下:
<img src="logo.png" width="" height="" border="0" onload="fixPNG(this)" />

更多相关文章请参考《 你必须知道--IE中的hasLayout 》http://blog.csdn.net/rhinemetal/article/details/6233277
《 最新让IE6支持PNG24背景透明最佳解决方法》http://hi.baidu.com/lzc10086/blog/item/ad38d32f645e82704ec22616.html
《 IE6下png背景不透明问题的综合拓展》http://apps.hi.baidu.com/share/detail/34680089

你可能感兴趣的:(html,IE,filter,layout,border)