第十九课:盒子模型

css的盒子模型是一个前端工程师必须知道的知识点。一个元素,它的盒子模型是:margin(边界)+border(边框)+padding(填充)+content(内容)。其中除了content,其余三个都有上下左右4个方向,好比:margin-left,padding-left,border-left。一个元素它还有背景颜色和背景图片。当你设置一个元素的背景颜色时,它的背景颜色会延伸到border(你能够经过把border设置为transparent看到)。背景图片会在背景颜色之上,也就是覆盖背景颜色,也会延伸到border。border在背景颜色和背景图像之上,覆盖它们。css

当前存在两种盒模型,IE在怪异模式下的盒模型是:width = content + padding +border,咱们称之为border-box。而标准浏览器的盒模型:width = content,咱们称之为content-box。从设计与计算的角度,尤为是百分比设置宽高时,IE的盒子模型更为合理。所以W3C后来搞了一个box-sizing的CSS3属性,这个属性能够改变元素的盒模型,它接收三个值,content-box(W3C的盒模型),border-box(IE的盒模型),padding-box(width = content+padding)。html

 咱们经过jQuery来取元素的width时,使用的是content-box,也就是content的宽。通常咱们可使用window.getComputedStyle精确取到元素的宽,但若是元素display为none,或者元素的祖先display为none,又或者元素脱离了DOM树,此方法是获取不到的,旧版本IE的ele.currentStyle.width也差很少。当元素不在DOM树中时,它的offsetWidth为0。opera的可能小于0.可是咱们不能把这个offsetWidth<=0做为元素隐藏(display:none)的充分条件,由于用户可能设置元素的width:0(而且padding和border也为0),这样元素的offsetWidth也为0,可是它不是隐藏的。其实offsetWidth = width + padding + border(无论哪一种盒模型)。前端

窗口的宽度:node

若是你只须要支持标准浏览器和IE以及以上版本,可使用window.innerWidth来获取窗口的宽度。手机端就可使用这种方法。那若是要兼容IE6-IE8,咱们可使用document.documentElement.clientWidth,这个属性用于取得元素的可视区的尺寸,不包括滚动条和被隐藏的部分。document.documentElement是html元素,它是包含整个浏览器窗口的可视元素。远古时代的浏览器把body当作html元素,html元素时隐藏的,因此你会看到一些代码document.documentElement.clientWidth || document.body.clientWidth,可是远古时代的浏览器就不用支持了,所以要得到窗口的宽,兼容模式就是:windowWidth = document.documentElement.clientWidth。若是在手机端,就这样使用:windowWidth  = window.innerWidth。数组

页面的宽度:浏览器

页面的宽度,咱们称为文档的宽度,一旦出现滚动条,咱们就要考虑加上被隐藏的部分。安全

由于兼容性问题,咱们只有一种方法来获取pageWidth = Math.max(document.documentElement.scrollWidth,document.documentElement.offsetWidth,document.documentElement.clientWidth,document.body.scrollWidth,document.body.offsetWidth);取他们中的最大值,做为页面的宽度,这个方法兼容全部浏览器。前端工程师

判断浏览器是在标准模式下仍是在怪异模式下,经过document.compatMode === "BackCompat"(怪异模式,border-box),"CSS1Compat"(标准模式,content-box)并发

元素的显隐:app

这里只讲display。咱们对元素进行display:none隐藏,display:block,显示。可是像thead,tbody,tr等具备特定默认display值的元素,它们一旦设置了display:block,表格立刻奔溃。

display的值:block(块元素),none,inline(内联元素),inherit(继承),run-in(填充),table(表格)等。

要想取得元素的默认display属性,咱们须要在iframe沙箱中去取。

iframe沙箱的意思是:

iFrame因安全问题而臭名昭著,这主要是由于iFrame经常被用于嵌入第三方内容,然后者则可能会执行某些恶意操做。沙箱经过限制被嵌入内容所容许的操做而提高iFrame的安全性,这种方式将沙箱内容与父页面进行了分离,所以限制了被嵌入内容的权限,不过这并不意味着用户再也不须要检测数据以防止潜在的攻击。

沙箱化本地对象的概念,即在全局名称空间外部安全加强的本地 JavaScript 。JavaScript 最强大、但也可能最危险的特性之一是使用自定义方法和属性加强全局对象的能力。

JavaScript 支持经过 prototype 属性直接访问 ArrayStringFufunction、甚至 Object 自己这类全局对象。若是您想添加一个 contains 方法到本地 Array,只须要在 Array.prototype 上定义一个contains 函数。本地 JavaScript 对象上的原型加强是一个有吸引力和影响力的想法。可是在实践中,在修改本地全局对象时出现了很严重的问题。幸运的是,沙箱化本地对象 — 以将它们从全局空间中隔离出来的方法加强本地对象 — 提供了一个安全的选择。沙箱化本地对象的概念能够追溯到 2006 年 Dean Edwards 发表的两篇文章 “使用 <iframe> 沙箱化 JavaScript” 和 “如何将 JavaScript 数组对象划分子类”。他提供了一个巧妙的增长本地对象问题的解决方案,并建议使用一个 iframe 来复制和加强 Array,而不影响全局空间。

var iframe = document.createElement("iframe");

iframe.style.display = "none";

document.body.appendChild(iframe);

frames[frames.length - 1].document.write(   "<script>parent.Array2 = Array;<\/script>");

尽管它并非一个完美的解决方案,Edwards 的方法激发你们对这个问题的探讨。随着一个新的 JavaScript 的框架 FuseJS 的问世,John-David Dalton 决定使用沙箱化本地对象概念做为他新项目的核心。目的是建立一个稳定的、跨浏览器的沙箱系统做为框架的基础,将沙箱概念扩展到 Array(以前尝试的焦点)以外的其余本地对象。在 2010 年 9 月,他将这个核心代码分离出来做为一个独立的开源项目,称为 Fusebox,并发布了一系列截屏视图来介绍该项目。

3 个独立的技术被用来建立这个沙箱,实现目标:

  • ActiveXObject('htmlfile') 用于 Internet Explorer。
  • Object['__proto__'] 用于 Gecko 和 WebKit 浏览器。
  • Iframes 用于 Opera。

这个截屏视图系列深刻介绍了这个沙箱环境建立的技术细节。本文只关注结果Fusebox 的实例化使您能够根据需求操做Fusebox.Array,而不触及全局 Array

var fb = Fusebox();

fb.Array.prototype.contains = function(q){    

  for ( var i = 0, len = this.length; i < len; i++ ) {

     if ( this[i] === q ) { return true; }

  }

   return false;

}

console.log(fb.Array(1,2,3,4,5).contains(4));   >>>true

console.log(typeof Array.prototype.contains);    >>>false

Fusebox.Array 表现得像一个真正数组。

元素的坐标:

元素的坐标就是指其top和left值。元素的style样式具备left,top的属性。可是必须定位了(fixed,relative,absolute),元素的left和top的样式才会有做用,否则就跟没设置是同样的。

元素节点还有一个offsetTop和offsetLeft属性,它们是相对于offsetParent距离,是只读属性,node.offsetLeft,元素没定位,也能够取到。

所以咱们能够经过此属性得到此元素的页面的坐标:

function offset(node){

  var left = node.offsetLeft,

    top = node.offsetTop;

  while(node = node.offsetParent){

    left+= node.offsetLeft;

    top+= node.offsetTop;

  } 

  return {left:left,top:top}

}

此外,相对于可视区的坐标也很实用,好比,让弹出框居中对齐。咱们可使用getBoundingClientRect方法,此方法已是W3C的标准了。此方法返回页面中某个元素(border-box,也就是border是界线)的左,上,右,下分别相对浏览器视窗的位置。它返回一个对象,该对象有4个属性,left,top,bottom,right,标准浏览器下可能会多出width和height这两个属性,这里的width = content+padding+border。这里的left和top跟css的理解同样,可是bottom和right跟css不同,right是指元素的右边界线与窗口最左边的距离(不是窗口最右边),bottom是指元素下边界线与窗口最上面的距离(不是窗口最下面)。咱们经过它也能够很方便的求出元素相对于页面的距离:

var left = this.getBoundingClientRect().left  +  document.documentElement.scrollLeft;

var top = this.getBoundingClientRect().top +  document.documentElement.scrollTop;

将它相对于窗口的距离+滚动距离=页面的距离。可是这里计算了两次浏览器的边框(以上两个操做都会算上浏览器边框),须要减去document.documentElement.clientLeft。

(IE的一些版本会自动为HTML元素,也就是document.documentElement添加2px的border,须要去掉)

offsetParent的定义,在W3C上有详细的说明,可是实际的浏览器没有按照它规定的实现。这里咱们按照jQuery实现的方法来定义。jQuery认为元素的offsetParent的position必须为relative或absolute,不然继续往上寻找,没有就返回html。另外jQuery认为position:fixed的元素也有offsetParent,就是当前可视区(通常为window)。

元素的滚动条的坐标

读取元素的滚动坐标时,标准浏览器使用window对象的pageXOffset,pageYOffset这组属性。IE直接使用元素的scrollLeft和scrollTop属性。

设置时,咱们只要用window对象的scrollTo方法,里面传入滚动的坐标就好了。

 

 

 

加油!

相关文章
相关标签/搜索