一起乐吧

不试一下,你永远不知道你有多强大!

RSS Feed

hasLayout与BFC(Block Formatting Contexts)的深入理解

0 Comments

1.hasLayout

关于IE下的这个私有的东东,以前也研究过,这儿不多说,只说两点:
(1)它是什么

它决定了元素如何对其内容进行定位和尺寸计算,与其他元素的关系和相互作用,以及对应用还有使用者的影响。

‘Layout’ 可以被某些 CSS property(特性)不可逆的触发,而某些 HTML 元素本身就具有 layout 。

‘Layout’ 在 IE 中可以通过 hasLayout 属性来判断一个元素是否拥有 layout ,如 object.currentStyle.hasLayout 。

‘Layout’ 是 IE 浏览器渲染引擎的一个内部组成部分。在 IE 浏览器中,一个元素要么自己对自身的内容进行组织和计算大小, 要么依赖于包含块来计算尺寸和组织内容。为了协调这两种方式的矛盾,渲染引擎采用了 ‘hasLayout’ 属性,属性值可以为 true 或 false。 当一个元素的 ‘hasLayout’ 属性值为 true 时,我们说这个元素拥有了一个布局(layout),即成功触发hasLayout。

(2)它主要干什么

IE6/7以及IE8的诡异模式下有许多莫名其妙的bug,当遇到一些摸不着头脑的布局问题时,可以试着触发相关元素的hasLayout,使其为ture,你会发现,许多的问题都与这个属性有关。

下面的元素的hasLayout默认为true:

<html>, <body>
<table>, <tr>, <th>, <td>
<img>
<hr>
<input>, <button>, <select>, <textarea>, <fieldset>, <legend>
<iframe>, <embed>, <object>, <applet>
<marquee>

可触发 hasLayout 的 CSS 特性:

display: inline-block /*ALL*/
height: (除 auto 外任何值) /*仅适用IE6 7*/
width: (除 auto 外任何值) /*仅适用IE6 7*/
float: (left 或 right) /*ALL*/
position: absolute /*ALL*/
writing-mode: tb-rl /*ALL*/
zoom: (除 normal 外任意值) /*仅适用IE6 7*/

IE7 还有一些额外的属性(不完全列表)可以触发 hasLayout :

min-height: (任意值)/*以下适用IE7+*/
min-width: (任意值)
max-height: (除 none 外任意值)
max-width: (除 none 外任意值)
overflow: (除 visible 外任意值,仅用于块级元素)
overflow-x: (除 visible 外任意值,仅用于块级元素)
overflow-y: (除 visible 外任意值,仅用于块级元素)
position: fixed

IE6 以前的版本(也包括 IE6 及以后所有版本的混杂模式,其实这种混杂模式在渲染方面就相当于 IE 5.5), 通过设置任何元素的 ‘width’ 或 ‘height’(非auto)都可以触发 hasLayout ; 但在 IE6 和 IE7 的标准模式中的行内元素上却不行,设置 ‘display:inline-block’ 才可以。(个人觉得这个现在没有什么意义了,IE5.5?还是算了吧,基本找不到了)

2.BFC(Block Formatting Contexts)

非IE浏览器中和hasLayout极其相似的一个属性就是BFC(块格式化上下文)。

(1)它是什么:

BFC是 W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。

在创建了 BFC的元素中,其子元素会一个接一个地放置。垂直方向上他们的起点是一个包含块的顶部,两个相邻的元素之间的垂直距离取决于 ‘margin’ 特性。在BFC中相邻的块级元素的垂直边距会折叠(collapse)。

在BFC 中,每一个元素左外边与包含块的左边相接触(对于从右到左的格式化,右外边接触右边), 即使存在浮动也是如此(尽管一个元素的内容区域会由于浮动而压缩),除非这个元素也创建了一个新的BFC。

(2)触发方式:
float:(任何值除了none)
overflow:(任何值除了visible)
display:(table-cell/table-caption/inline-block)
position:(任何值除了static/relative)

看到了么?触发方式和hasLayout的触发方式挺像的。

3.hasLayout 和 BFC 相比较

3.1 在触发 hasLayout 的元素和创建了 BFC的元素中,浮动元素参与高度的计算.

先来看下面的代码:

<div style="width:300px;">
    <div id="container" style="background:#eee">
        <span id="span1" style="background:red">我是span行内元素</span>
        <div id="div1" style="width:150px; height:50px; background:#999">我是普通流中的块级元素</div>
        <div id="div2" style="float:left; background:yellow">我是浮动元素</div>
    </div>
</div>

根据 CSS2.1 规范第 10.6.3 部分的高度计算规则,在进行普通流中的块级非替换元素的高度计算时,浮动子元素不参与计算。

所以IE6/7下和标准浏览器下面的效果是一样的,即id为container的容器中不包含浮动的div2。

效果图如下:

IE6下面的效果

IE6下面的效果

标准浏览器下面的效果

标准浏览器下面的效果

但是当我们给id为container的容器加上触发BFC的属性之后(overflow:hidden),可以看到浮动元素参加了高度的运算:

触发BFC后标准浏览器下的效果

触发BFC后标准浏览器下的效果

IE6下面的效果

IE6下面的效果

可以预见,IE下面依然是浮动元素不参加高度的运算。
演示文件地址:
触发BFC
而触发IE下的hasLayout,同样可以得到一样的效果:

IE下触发haslayout

IE下触发haslayout

演示地址:IE下触发haslayout

通过以上的分析与实践,我们得知:

如果不触发标准浏览器下的BFC以及IE6/7下面的haslayout的话,浮动元素是不参加父元素的高度的计算的,显示效果一样,如果只触发haslayout或者BFC的话,则触发的浏览器里面浮动元素参与父元素高度的计算(即父元素包含浮动元素)。所以如果我们要让父元素包含浮动元素并且兼容所有浏览器的话,就得同时触发haslayout与BFC。

3.2 与浮动元素相邻的、触发了 hasLayout 的元素或创建了 BFC 的元素,都不能与浮动元素相互覆盖.

如果浮动元素的两侧有足够的空间放置该元素,则元素会紧邻浮动元素放置,必要时,该元素的宽度将会被压缩。否则它们可 能会定位到浮动元素的下方。

先来看下面的代码:

<div id="container" style="border:2px solid yellow; width:300px; height:150px">
    <div id="div1" style="background-color:yellow; width:100px; height:100px; float:left; filter:alpha(opacity=50); opacity: 0.5;">
        我是一个浮动元素!
    </div>
    <div id="div2" style="background-color:green;">
        我是一个紧跟浮动元素的普通块级元素!
    </div>
</div>

根据 CSS 2.1 9.5 Floats 中的描述,浮动元素会覆盖普通流中的块容器。所以,div2 应该有一部分被 div1 覆盖。

IE浏览器和标准浏览器中的效果如下图所示:

IE6下的效果

IE6下的效果

标准浏览器下的效果

标准浏览器下的效果

可以清楚的看到,效果是一样的(当然忽略IE6下的3px bug),即都是符合标准的。
但是当我们给普通块级元素加上zoom:1,即触发了IE的haslayout后,ie6/7下的块级元素会拥有布局,不再被浮动元素覆盖。如下:

ie6下触发haslayout

ie6下触发haslayout

演示地址:触发IE下的haslayout(float覆盖)
可以预见,标准浏览器下的效果不变,要想得到相同的效果,则需触发起BFC,加上overflow:hidden试试。 Read the rest of this post

Filed under css, 学习点滴

关于transform-style和perspective变换函数(3D变换)

0 Comments

Perspective:

perspective 变换函数对于 3D 变换来说至关重要。该函数会设置查看者的位置,并将可视内容映射到一个视锥上,继而投影到一个 2D 视平面上。如果不指定透视,则 Z 空间中的所有点将平铺到同一个 2D 视平面中,并且变换结果中将不存在景深概念。对于某些变换,例如下图显示的沿 Z 轴的变换,perspective 变换函数对于查看变换的效果来说必不可少。

来比较一下下面的代码中的两个div就知道perspective的用处了:

<!doctype html>
<html>
<head>
<title>perspective使用</title>
<style type="text/css">
 .one,.two{
    background:red;
    width:150px;
    height:150px;
    margin:20px;
 }
 .one{
    transform: perspective(500px) rotateY(30deg);
    -moz-transform: perspective(500px) rotateY(30deg);
    -webkit-transform: perspective(500px) rotateY(30deg);
    -o-transform: perspective(500px) rotateY(30deg);
 }
 .two{
    transform: rotateY(30deg);
    -moz-transform: rotateY(30deg);
    -webkit-transform: rotateY(30deg);
    -o-transform: rotateY(30deg);
 }
</style>
</head>
<body>
 <div class="one"></div>
 <div class="two"></div>
</body>
</html>

下面是图:

perspective

演示地址:perspective 使用

另外,你可以通过在父元素中使用 perspective 属性来便捷地向多个元素添加透视变换。perspective 属性会将透视变换应用于其所有子元素,例如:

.div{
    perspective: 1000px;
}
.div .one{
    position: absolute;
/*变形原点,该元素围绕着哪个点变形或者旋转,配合着transform属性一起用*/
    transform-origin: 0px 0px;
    transform: rotateY(30deg);
}
.div .two{
    position: absolute;
    transform-origin: 0px 0px;
    transform: rotateY(30deg);
}

backface-visibility:

backface-visibility 属性可用于隐藏内容的背面。默认情况下,背面可见,这意味着即使在翻转后,变换的内容仍然可见。但当 backface-visibility 设置为 hidden 时,旋转后内容将隐藏,因为旋转后正面将不再可见。该功能可帮助您模拟多面的对象,例如下例中使用的纸牌。通过将 backface-visibility 设置为 hidden,您可以轻松确保只有正面可见。

transform-style:

设置内嵌的元素在 3D 空间如何呈现。有两个值:flat:所有子元素在 2D 平面呈现。preserve-3d:保留3D空间。
最后,我们运用一个翻转的例子,加深一下印象:
Read the rest of this post

Filed under css, 学习点滴

CSS3中transition的学习

1 Comment

今天早上起床逛微博,看到 了一篇关于CSS3的文章链接,立马点击进来看看。链接如下:

CSS3 必须要知道的10 个顶级命令。前九个命令都是以前自己照着腾讯ISD出的那个小册子练习过的,所以没有什么新东西。但是看到最后一个关于transition(过度,变换)的介绍时,感到不熟悉,打开那个小册子找找,发现没有这个属性,怪不得这么陌生呢?所以打算自己研究一下。哎,最主要还是被它华丽的效果吸引住了啊!!

transiton属性有这几个值:
transition-property :* //指定过渡的性质,比如transition-property:backgrond 就是只指定backgound参与这个过渡
transition-duration:*//指定这个过渡的持续时间
transition-delay:* //延迟过渡时间
transition-timing-function:*//指定过渡类型,有ease | linear | ease-in | ease-out | ease-in-out | cubic-bezier

关于transition-timing-function,是动态效果实现的关键,有以下几个值:

linear //线性过度
ease-in //由慢到快
ease-out //由快到慢
ease-in-out //由慢到快在到慢

还是太枯燥,不如例子来的浅显易懂。我以本人博客的标题(一起乐吧)为演示,大家可以把鼠标放在页面顶部的“一起乐吧”查看效果,哈哈,是不是旋转起来了。当然了,你得用非IE看效果啊!!以下是实现的代码: Read the rest of this post

Filed under css, 学习点滴

用js无法获取style样式的问题解析与解决方法

0 Comments

今天在写js获取style样式的时候遇到了一个小问题,即用以下的代码获取不到id为“qqChat”div的一些样式:

function $(id){
 return documentElementById(id);
}
var qL = $("qqChat").style.left;
alert(qL);//结果为空

仔细检查代码,div框的top,left值也定义了啊,为什么就获取不到呢?随搜索之。终于发现了问题所在:

js只能修改html内部的css样式代码

在JavaScript中,通过document.getElementById(id).style.XXX可以获取到XXX的值,但意外的是这样做只能取到通过内嵌方式设置的样式值,即style属性里面设置的值。

原来是我把样式写到了head中。但是一般不把样式写成行内样式的,所以得找到解决的办法。随继续寻找之。功夫不负有心人,终于找到了解决方法:

如果是ie,问题很好解决,只要把style改成currentStyle即可。即:

function $(id){
 return documentElementById(id);
}
var qL = $("qqChat").currentStyle.left;
alert(qL);//结果有值

而在firefox下,则采用另外一种方式:

function $(id){
 return documentElementById(id);
}
var qL = document.defaultView.getComputedStyle($("qqChat"),null)
var qLL = qL.left;
alert(qLL);//结果有值

综合IE和Firefox之后解决办法如下:

function $(id)
{
 return document.getElementById(id);
}
function checkStyle(o){
 if(o.currentStyle){
  var cur = o.currentStyle;
}else{
  var cur =  document.defaultView.getComputedStyle(o, null);
}
  return cur;
}
var one = checkStyle($("qqChat"));
alert(one.left);//有值
Filed under javascript

Javascript——浅析注册事件(转)

0 Comments

这篇文章浅显易懂,所以转来,加深一下注册事件。

转自:cssrain

首先是最常规的方法:


<script type="text/javascript">// <![CDATA[
  function test(){   alert("test"); }
// ]]></script>

当某一天,我们知道JavaScript要跟HTML结构实现分离后,就会改了一种写法:


<script type="text/javascript">// <![CDATA[
function test(){
  alert("test");
}
window.onload = function(){
    document.getElementById("para").onclick = test;
}
// ]]></script>

当我们工作越来越久后,有时候我们需要对某个元素绑定多个相同的事件类型:


<script type="text/javascript">// <![CDATA[
function test(){
  alert("test");
}

function pig(){
  alert("pig");
}

window.onload = function(){
     document.getElementById("para").onclick = test;
     document.getElementById("para").onclick = pig;
}
// ]]></script>

Read the rest of this post

最近在“干”它

0 Comments

半个月没有更新博客了,那么我在干什么呢?呵呵,请看下图:

javascript高级程序设计  html5高级程序设计

javascript高级程序设计 html5高级程序设计

 

是的,你没有看错!我在学习!图片中的前两本书是在图书馆借的,当时发现它们的时候有点不相信自己的眼睛,我没有想到一个农业类大学竟然有这样的书,所以果断拿下。下面的这本我就不多说了,为了它,我这段时间只有勒紧裤腰带,吃馒头喝稀饭了!哈哈!但是我的精神食粮是慢慢的啊!!

jQuery优化的若干技巧(二)

1 Comment

1.优化事件中的冒泡现象:

什么是冒泡现象呢?简单点说,就是当触发一个元素的事件后,其外围元素的事件也会被触发,实质就是事件执行中的顺序。这么说好像有点空洞,那么我们看一个例子吧。

<!DOCTYPE html>
<html>
<head>
    <title>事件中的冒泡现象</title>
    <script type="text/javascript"
            src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js">
    </script>
    <style type="text/css">
           body{
             font-size:13px
          }
           .clsShow{
             border:#ccc 1px solid;
             background-color:#eee;
             margin-top:15px;
             padding:5px;
             width:220px;
             line-height:1.8em;
             display:none
         }
           .btn {
             border:#666 1px solid;
             padding:2px;width:50px;
        }
    </style>
    <script type="text/javascript">
        $(function() {
            var intN = 0; //记录执行次数
            $("body,div,#btnShow").click(function(event) {//点击事件
                intN++; //次数累加
                $(".clsShow")
                .show()//显示
                .html("您好,欢迎来到jQuery世界!")//设置内容
                .append("<div>执行次数 <b>" + intN + "</b> </div>"); //追加文本
            })
        })
    </script>
</head>
<body>
    <div>
        <input id="btnShow" type="button" value="点击" class="btn" />
    </div>
    <div class="clsShow"></div>
</body>
</html>

演示地址:事件中的冒泡现象。我们可以看到,当单击了按钮时,事件在冒泡过程中先后执行了元素<div>和元素<body>中的事件,因此,即使单击了一次按钮,却共有3次事件的执行过程。为了避免这种现象的发生,我们可以使用stopPropagation()方法来停止事件中的冒泡现象。
演示地址:阻止事件中的冒泡现象

在元素的绑定事件的过程中,还有一个方法target(),通过该方法可以获取触发事件的元素。如果是多个元素触发同一个事件,可以借助target()方法,获取这些元素的父级元素,并将事件绑定到父级元素,通过冒泡现象,扩展到子级元素中,这样将会比把事件绑定到每个子级元素执行的效果更优化。
看下面的html代码:

<form id="form1">
        <fieldset id="frame" style="width:200px">
          <legend>输入信息</legend>
          <div>姓名:<input id="Text1" type="text"/></div>
          <div>性别:<input id="Text2" type="text" /></div>
          <div>年龄:<input id="Text3" type="text" /></div>
        </fieldset>
    </form>

我们可以通过以下的jQuery代码来使每个文本框获取焦点时改变原有的样式,

$(function() {
            $("#frame").bind("click", function(e) {
                $objChild = $(e.target);//捕捉触发事件的元素
                $objChild.addClass("txt");//增加子元素的样式
            })
        })

其实质就是通过e.target获取触发事件的元素,并将事件绑定到父级元素上面,通过冒泡现象,传递给各个子元素,使子元素也被同样的事件所绑定。下面的代码可以实现同样的效果,只是需要遍历所有的input元素,逐个绑定,效率肯定慢了。

$(function(){
             $("#fram input").bind("click",function(e){
               $(this).addClass("txt");
              })
})

完整的代码和演示地址:事件中的target方法优化冒泡现象

2.使用data()方法缓存数据
这个方法大家可以查看手册了解。

3.使用子查询优化选择器性能
如果要查找一个元素,而这个元素被众多别的元素所包含或嵌套在其中,这是如果直接使用find()方法进行查找,性能会比较低。我们可以先查找最外层的元素,保存起来,再查找更近一层的元素,进行保存,最后在最接近的层中,使用find()方法。比如下面两段jquery代码的对比:

$(function() {
            var $divF = $("#divFrame");//保存最外层对象
            var $ulF = $divF.find(".ulFrame");//在外层对象中查找
            var $li0 = $ulF.find(".li0");
            var $spn = $li0.find("span");//在最近一层中查找
            var $li1 = $ulF.find(".li1");
            var strTmp = "最终数据:" //初始化显示内容
            strTmp += "<br>" + $spn.html(); //获取内容
            strTmp += "<br>" + $li1.html(); //获取内容
            $("#divTip").append(strTmp); //显示在页面中
        })

 

$(function() {
            $spn = $("div ul li span");
            $li1 = $("div ul .li1");
            var strTmp = "最终数据:" //初始化显示内容
            strTmp += "<br>" + $spn.html(); //获取内容
            strTmp += "<br>" + $li1.html(); //获取内容
            $("#divTip").append(strTmp); //显示在页面中
        })

第二种的代码没有缓存,性能低,对选择器的开销大。
4.减少对DOM元素的直接操作
DOM操作的原理:现在内存中创建DOM结构,然后,更新现有的DOM结构。如果直接对DOM进行操作,性能是很低的,我们可以在操作前完善大部分的DOM操作,最后通过一次直接操作,更新DOM结构。
比较下面的两段代码:

        $(function() {
            //定义数组
            var arrList = ["list0", "list1", "list2", "list3", "list4", "list5"];
            var strList = ""; //初始化字符
            $.each(arrList, function(index) {
                //遍历后累加数组元素
                strList += ("<li>" + arrList[index] + "</li>");
            })
            //一次性完成DOM元素的增加
            $("#ulFram").append(strList);
        })

 

     $(function() {
            //定义数组
            var arrList = ["list0", "list1", "list2", "list3", "list4", "list5"];
            var strList = ""; //初始化字符
            $.each(arrList, function(index) {
                //遍历后累加数组元素
               $("#ulFram").append("<li>" + arrList[index] + "</li>");
            })
        })

后面的方法每遍历一次,都直接对DOM元素进行操作,效率很低。
我现在学习到的就是以上几种了,肯定还有其他的,欢迎大家一起交流!

Filed under 学习点滴
第 1 页,共 9 页123456789