有关注前端和微博的朋友一定留意到了前一阵寒冬和玉伯关于前端面试的讨论,后来老赵和左耳朵耗子也加入其中,讨论带来了非常多的启发和思考——不久之前自己也经历了几轮面试,决心对自己的基础开始加强,正巧寒冬老师题目由浅入深,非常有代表性,有些概念自己也模糊,决心花时间把这些概念全部弄清楚,梳理一遍

寒冬的微博原文如下

面试的时候问个css的position属性能刷掉一半的人这是啥情况……其实这问题我本来打算的是可以顺着一路扯到normal flow、containing block、bfc、margin collapse,base line,writing mode,bidi,这样一路问下去的,奈何第一个问题(亲我真的只问了position有哪些取值和行为啊)就悲剧了……

并且后来寒冬后来也就这一事件写了两篇文章(《谈谈面试与面试题》, 《阿里巴巴无线前端团队》)来做了一些说明,我们就根据这些材料对知识点进行一些梳理。本文将谈到:

  • position
  • normal flow
  • containing block
  • bfc
  • margin collapse
  • writing mode
  • bidi
  • 以及各种综合和边缘情况

最困难的是当你在谈一个概念的同时不得不对其他概念有所涉及——但其实所有的概念和方案都是为了解决问题而生,我打算从最简单的布局开始,以解决复杂的布局方案为线索,逐渐引入这些概念。本文的资料来源于国外国内的通俗博客和实战经验,如果直接引用w3c的概念我感觉会有一些晦涩(重要的是我看的也很头大),但仍然会做引用。本文只是抛砖引玉,如果有不正确的地方请多多指正。

Normal Flow

我倾向把normal flow翻译为标准流。当你在一个空白的网页上插入不同的标签div, p, span等,那么这些标签形成的元素将以何种标准进行排列?那就是标准流。

谈论标准流的前提是,页面上的所有元素都没有有关布局的css(float,display,position等)进行修饰,也就是说所有的元素要么是块状元素(block),要么是行内元素(inline)

块状元素将在页面上或者包含他们的包含块(containing block)中,从左上方开始,并且是从垂直自上往下进行填充,不用担心横向,因为块级元素非常霸道,一个元素必定占一整行,即使你给它指定宽度,它所在的那一行余下的宽度也是属于它的,不会有后面的元素进来,即使后面的元素很窄能刚好插进来。而上下两个块之间的距离则根据他们的外边距和外边距的折叠规则(margin collapse)而定,这个后面会谈到。比如看下面这个例子

div { border: 1px solid black; } div div { height: 100px; } .a { margin: 20px 0; } .b { margin: 30px 0; width: 100px; } .c { margin: -50px 0 0; } 
<div>     <div class="a"></div>     <div class="b"></div>     <div class="c"></div> </div>

 

而行内元素顾名思义,则优先进行横向排列,从容器的左上开始,后面的元素一个紧挨一个的排列在这一行中,只有当位置不够了,才会被挤到下一行去,

div { width: 100px; border: 1px solid black;} span.a {background: yellow;} span.b {background: red;} span.c {background: blue;} 
<div> <span class="a" >This is an span element</span> <span class="b" >This is another span</span> <span class="c" >This is   the third span</span>     </div> 
This is an span element This is another spanThis is the third span

在标准流的状态下,如果两种元素混合在一起,那么将各自遵循各自的标准,理论上是不会有干扰的。临时想到一个问题,如果块状和行内上下相邻,并且都配备有外边距,那么外边距怎么计算?再复杂一点,行内元素所在的那一行有好几个行内元素,并且每个的外边距都不相同,那么与垂直相邻的块状元素的距离怎么算?代码如下

div { width: 100px; border: 1px solid black; margin: 20px;} span.a {margin: 10px 0 0;} span.b {margin: 20px 0 0;} span.c {margin: 30px 0 0;} 
<div class="block"></div> <span class="a">This is a span</span> <span class="b">This is b span</span> <span class="c">This is c span</span> 

这个问题还涉及另一个概念:盒子模型,如果又要展开又大了去了。在这里只说一点,行内元素的margin和padding只对它的左右元素有影响,对上下无影响,具体看下面代码

.p { width: 200px; height: 50px; border: 1px solid black;} .span {margin: 20px;} 
<p> <span>this is span</span><span class="span">this is span</span><span>this is span</span><span>this is span</span><span>this is span</span> </p> 

this is span this is spanthis is span this is span this is span

本节主要参考资料:

  • Inline elements and padding
  • W3C: Normal flow
  • Webdesign:normal flow
  • Some definitions:Normal flow

BFC(Block Formatting Context)

好吧,必须承认我也是第一接触BFC的概念,很惭愧,于是疯狂的查找资料,对它概念的介绍引用阿里巴巴用户体验部的一篇文章的一段话

什么是BFC(Block Formatting Context),简单讲,它是提供了一个独立布局的环境,每个BFC都遵守同一套布局规则。例如,在同一个BFC内,盒子会一个挨着一个的排,相邻盒子的间距是由margin决定且垂直方向的margin会重叠。而float和clear float也只对同一个BFC内的元素有效。

在提BFC的同时也不得不提另一个概念,IE的haslayout属性,一旦元素的这两个属性(haslayout在IE下)被触发,他们都能给自己提供一个独立的布局环境(我的疑问在于不独立的布局环境又是什么情况?)。当元素的CSS属性设置了下列之一时,即可创建一个BFC:

那么如何触发BFC,继续引用一淘的文章:

非块级盒子的浮动元素、绝对定位元素及块级容器(比如inline-blocks,table-cells和table-captions),以及overflow属性是visible之外任意值的块级盒子,都会创建了一个BFC。即当元素CSS属性设置了下列之一时,即可创建一个BFC:

  • float:left | right
  • position:absolute | fixed
  • display: table-cell | table-caption | inline-block
  • display: table-cell | table-caption | inline-block

然后这个独立布局的规则是这样的(摘自)

  • 在创建了 BFC的元素中,其子元素会一个接一个地放置。垂直方向上他们的起点是一个包含块的顶部,两个相邻的元素之间的垂直距离取决于 ‘margin’ 特性。在BFC中相邻的块级元素的垂直边距会折叠(collapse)。
  • 在BFC 中,每一个元素左外边与包含块的左边相接触(对于从右到左的格式化,右外边接触右边), 即使存在浮动也是如此(尽管一个元素的内容区域会由于浮动而压缩),除非这个元素也创建了一个新的BFC。

上面的定义是翻译自W3C的标准。因为自己经验有限,在这里我直接举出我找到的的BFC的经典用处,希望大家能从中体会。

在所有的文章中,被列举最频繁的例子莫过于阻止文字围绕浮动元素,请看下面代码

.item {width: 200px; height: 150px; border: 1px solid black;} .pic{width:80px;height:80px;margin:10px;background-color:#acdae5;float:left;} 
<div class="item">   <div class="pic">picture</div>   <p class="text">   测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试  </p> </div> 
picture

测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试

此时我们要做一个重要的决定!就是阻止文字围绕左侧的浮动块——那就开启右侧文字的BFC属性,用overflow:hidden

.item {width: 200px; height: 150px; border: 1px solid black;} .pic{width:80px;height:80px;margin:10px;background-color:#acdae5;float:left;} .text {overflow: hidden;} 
picture

测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试

用法二:创建了 BFC的元素中,浮动元素参与高度的计算,这个方法也可以用于消除因为子元素浮动引起的折叠

.header {border: 1px solid black;} .logo {width: 50px; height: 50px; background: blue; float: left;} 
<div class="header">    <div class="logo"></div> </div>

 

这是一个很常见的问题,在网站有一个标题区域header,其中有一个logo,并且设置logo向左浮动。但问题是一旦logo向左浮动,它的包含块因为float的一些特性(后面介绍),自动折叠了起来

那么就设置包含块的BFC的属性吧,照上面可以使用overflow属性

.header {border: 1px solid black; overflow:hidden;}

 

于是成功了,并且此时当计算header的高度时,将把子元素的float元素的高度计算进来。其实解决这一类的问题应该算是清除浮动。这一类解决方案已经非常成熟了,并且一个好的方案知识点的信息量还是比较大的,可以好好介绍一下。

用处三:创建了 BFC的元素不会与它们的子元素发生外边距折叠

外边距折叠规则中有一条是,当赤裸裸的子元素(没有padding,border)与赤裸裸的父元素(还是没有padding,border)进行接触时,他们的外边距会按一定的规则进行折叠。比如

div {margin:30px 0; background: yellow;} p {margin: 20px 0; background: blue;} 
<div>    <p></p> </div> 

This is text

看到上面因为父元素与子元素的外边距发生了折叠,父元素已经完全和子元素重合。如果元素是赤裸裸但又不想和父元素发生外边距折叠怎么办,那就给父元素设置BFC!

div {margin:30px 0; background: yellow; overflow: hidden;} 

This is text

以上是三个基本用处的介绍,至少我个人对BFC还不是很理解,比如拥有不同布局的元素究竟应该如何在BFC的元素中排列等。希望有经验的同学指点一下。

参考文章

  • CSS布局中一个简单的应用BFC的例子
  • hasLayout && Block Formatting Contexts
  • 更加直观地了解hasLayout和BFC
  • How does the CSS Block Formatting Context work?

上面的文章几乎都拿BFC与haslayout属性进行对比,上面的第二篇把异同之处都整理了出来。如果是页面布局方向的同学可以深入阅读。

Position: relative

Position有四种可选值,static,relative,absolute,fixed。当你不对元素做任何position属性时,默认即为static,注意此时你无法对元素的z-index值进行设置,只有当你把position设置为出static以外的值时,z-index才生效。所以最保险的作法是设置相对定位。

CSS2.1中元素是根据三种的位置方案(positioning modes or schemes)被布局的,分别是标准流(normal flow), 浮动(float)和绝对定位(absolute position)

相对定位虽然被改动了position值,但是仍然遵循标准流的规则。CSS中难点之一在于,如何根据当前元素的位置属性判断出相邻,或者后代的位置属性,而判断出当前元素的位置属性并不难。

你可以这么理解,相对定位的元素仍然处于标准流中,只要你没有设置偏移值(top, left, right, buttom);如果你设置了偏移值,那么元素就会相对于你在标准流中的位置,依照值进行偏移。但你周围的元素会以为你还在标准流中,有一种灵魂出窍的感觉。见代码

div { width: 200px; height: 40px; border: 1px solid black; position: relative; } .a {background: yellow; } .b {background: blue; } 
<div class="a"></div> <div class="b"></div> <div></div> 

以上是正常情况,而下面将演示非正常情况,我将给前两个容器添加相偏移

.a {background: yellow; top: 10px; left: 10px;} .b {background: blue; top: 10px; left: 10px;} 

注意到虽然前两个元素虽然发生了移动,但是第三个元素并没有收到影响,并且前两个元素的移动都是根据自己的相对位移。如果这三个盒子还存在外边距的话,那么外边距的折叠效果仍然是与标准流保持一致的。

再留意上面的一个细节,这三个容器我都没有设置z-index,你也可以通过firebug之类的工具查看到它们的z-index是auto;但却出现了有叠加的情况。

元素z轴上的层叠关系不仅仅可以通过z-index这个属性来硬性规定。还可以根据浮动,负外边距,定位属性等隐式属性的隐士式体现。就上面的例子而言,当然是有position为relative的元素的优先级比static高,而同样都是relative,在代码中后书写的元素优先级又比先书写的优先级高。

z-index不在这次讲课之列,有兴趣的同学可以参考下列文章:

  • The Z-Index CSS Property: A Comprehensive Look
  • Z-Index And The CSS Stack: Which Element Displays First?
  • Appendix E. Elaborate description of Stacking Contexts

留意一个边界情况,如果偏移量有矛盾怎么办,比如

.a {   left: 10px;   right: 10px; } 

记住这样一个原则,在矛盾的情况下left的优先级要比right高,top的优先级要比bottom高,即使right书写在left后面。这一原则在绝对定位和相对于视窗定位时仍然成立。

Position: absolute

绝对定位与相对定位虽然只差一个字,但差别多了去了。首先绝对定位元素已经彻底脱离了标准流,有一种跳出三界外,不在五行中的感觉,所以它的偏移量不是相对于标准流进行偏移的,而是相对于距离它最近的position不为static的祖先元素

什么是距离它最近的position不为static的祖先元素?看下面例子

div { border: 1px solid black; } .outer { width: 120px; height: 120px; position: relative;} .inner { width: 80px; height: 80px; margin: 20px 0 0 20px;} .item { width: 50px; height: 50px; background: red;     position: absolute;     left: 0;    top: 0; } 
<div class="outer">     <div class="inner">         <div class="item"></div>     </div> </div>

 

红色方块有两个父元素,为什么它绝对定位到离他更远的父元素?因为它的祖父元素(离它更远的那位)的position属性不为static,而它的父元素为static。如果想让它相对于父元素绝对定位怎么办,那就给父元素设置position不为static就行。

.inner { width: 80px; height: 80px; margin: 20px 0 0 20px; position:relative;}

再次强调,绝对定位就是相对于1.离它最近的父元素;2.并且这个最近父元素position值为非static。。如果元素所有的祖先元素都是static怎么办?那就相对于浏览器窗口了。

还有一个在w3c中特别注明的情况,如果父元素是行内元素怎么办?行内元素不可怕,可怕的是这个行内元素还形成了多行。看下面这个例子(你需要手动把浏览器变窄,把下面的行内元素变为多行):

.wrap { position:relative; border: 10px solid black; padding: 10px;line-height: 65px; } .item { background: blue; position: absolute; right: 5px;bottom: 5px;}  
<span class="wrap">     test test test test test test test test test test test test test test test test test test test test test test test test test test test     <span class="item">This is span</span> </span> 

test test test test test test test test test test test test test test test test test test test test test test test test test test testThis is span

我让另一个蓝色行内元素相对于它父元素(同样也是行内元素)进行绝对定位,定位在右下角。

注意此时多行元素的“右”是有两个不同的值,一个是第一行的右,一个是第二行的右,并且第二行的右比第一行的右还要短,那此时相对的“右”应该是哪一个右?如图所示,当然是最后一行的。

当行内元素形成多行并且左右侧不对齐时(形成了许多的line boxes),相对于它绝对定位的元素参考的区域是,以第一行inline box的左边和上边为边界(这里的边界是内容边界,content edge而非padding edge),和最后一行inline box的右边和下边为边界的矩形区域。即使中间有某几行的右侧与最后一行没有对齐,仍然以最后一行为准。所以有了上面的结果。

上面提到了一个edge概念,在盒子模型中有content edge,padding edge,border edge,margin edge。content edge内容边距指内容(content)与内边距(padding)的交界处,或者说包围内容区域的一圈边缘,另外三个同理。

于是这里我们不得不还要考虑一个问题:比如当我指定绝对定位的left偏移量时,这个量是从这个元素的哪一个边缘到相对元素的哪一个边缘?记住了,是从该元素的外边距边缘(margin edge)到相对元素的内边距边缘(padding edge)。也就是说在绝对定位中,外边距仍然是工作中的,BTW在相对定位中也是。

阿里巴巴UED有一篇文章是关于使用absolute的一个tip,可以加深对absolute的理解: 《overflow:hidden真的失效了吗》

Position: fixed

在W3C中把fixed视为absolute的一种情况,这个值可以一句话就带过了。绝对定位不是把某个祖先元素作为参考对象吗?那fixed也是把某个祖先元素视为参考对象,只不过这个参考对象是唯一的,那就是浏览器。注意,IE6中的position是没有fixed属性的

参考文章

  • Absolute Positioning
  • absolute-positioning
  • CSS Positioning

Containing Block

大部分时候一个元素的尺寸和位置并非是由它自己决定的(比如当它没有硬性规定长宽的时候),而是要参考它所在的那个容器,或者是它需要参考的元素容器。这个容器就叫做containing block,包含块。

包含块(containing block)的定义是我觉得w3c文档中写的最通俗易懂的,大致谈了四点:

  • 根元素(我不理解为什么没有明确指出是body或html)的包含块被称为初始包含块(initial containing block),这个包含块指的是浏览器视口(viewport),就是浏览器的窗口大小。
  • 对position为relative或static的元素来说,包含块指1.最近的;2.块级祖先元素;3.内容边缘(content edge) 所形成的区域(这一条从正面来说比较好理解,但是我还没有找到这样的一个反例)
  • position为fixed的元素,包含块就是视口
  • 如果元素是绝对定位,包含块除了要满足具有出static之外的定位属性意外,还要分一下两种情况:
    • 当满足情况的祖先元素是行内元素时,包含块应该是上一节绝对定位中最后描述的,行内元素多行时,当右侧参差不齐时形成区域的规则。在CSS2.1中,如果行内元素被分为许多行,那么包含块为undefined
    • 如果不是行内元素,包含块即是那个祖先元素内边距边缘所形成的区域。
  • 最后,如果该元素都不满足上述任何条件,那么包含块即是指“初始包含块”

参考文章

  • Containing Block
  • Definition of "containing block"
  • overflow:hidden真的失效了吗

Margin Collapse

关于外边距折叠,我觉得需要了解两点

  • 什么情况下会折叠
  • 什么情况下不会折叠

关于什么情况下会折叠,还要分三种情况

相邻元素的折叠:当两个或多个元素垂直排列时(标准流中),相邻的两个外边距会重合为一个外边距。这个重合外边距的值为那两个外边距的较大值;如果为一正一负的话,则为两个的和值;如果两个都是负外边距的话,最终值为负的更厉害的那个,这个就不举例了,应该很容易理解吧。

子元素与父元素之间的折叠:在之前那个BFC中提到过这个例子,当父元素与子元素赤裸裸的接触时(都没有内边距,边框;外边距的直接接触),那么父元素的外边距会与子元素的外边距产生折叠;如何组织这个折叠?触发父元素的BFC属性;具体实例的代码在那一节也都涉及到了

自己的上边距与下边距折叠:这个就有点奇葩了,当你有一个容器,设置了上下外边距,但是content area为空,那么自己的上外边距和下外边距会进行折叠!如果此时两个外边距正好一正一负,并且刚好抵消,那么你就看不到这个盒子了!

此时再如果盒子的上方来一个赤裸裸的接触,那么又触发外边距折叠,合体了!上代码

div {margin: 20px 0;} p {margin: 30px 0;} 
<div></div> <p></p> 

注意上面的空白处,用浏览器工具查看一下代码,那就是效果,因为没有任何内容,所以看起来什么都没有……

那么什么情况下不会折叠?

  • 浮动元素
  • 绝对定位元素
  • display:inline-block元素
  • 触发BFC的元素
  • 被清除浮动的元素(cleared)
  • 根(root)元素

参考资料

  • 《CSS Mastery Advanced Web Standards Solutions Second Edition 》
  • Collapsing Margins

写了这么多感觉把,感觉已经很累了,展现拉的太长了!先最后还剩三个关于书写排版的概念,这三个就真的没有接触过了,要花一段时间消化。最后还有重头戏,关于float,以及关于float和display和position的叠加。

转至:http://www.cnblogs.com/hh54188/archive/2013/05/18/3085433.html

转载于:https://www.cnblogs.com/xiaohong/p/4200934.html

转答寒冬的面试题(1)相关推荐

  1. 答寒冬的面试题(1)

    本文也发表在我另一篇独立博客qingbob.com:  <答寒冬的面试题1> 有关注前端和微博的朋友一定留意到了前一阵寒冬和玉伯关于前端面试的讨论,后来老赵和左耳朵耗子也加入其中,讨论带来 ...

  2. 答寒冬winter面试题

    前几天在微博上看到@winter寒冬老师的发的几道题,挺有意思, 答来看看.也是对自己最近实习所学的东西做下梳理. 以下是题目:   谈谈你对CSS布局的理解 讲讲输入完网址按下回车,到看到网页这个过 ...

  3. 快问快答JS面向对象面试题

    1.说说你对闭包的理解 使用闭包主要是为了设计私有的方法和变量.闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露.在js中,函数即闭包,只有函数才 ...

  4. 2017计算机应用+简答,2017计算机应用基础试题及答案

    2017计算机应用基础试题及答案 三.双项选择题(每小题1分,共5分) 1.计算机的存储系统一般指( ) A.ROM B.内存(主存) C.RAM D.外存(辅存) E.控制器 2.微型计算机采用总线 ...

  5. 90% 的人都会答错的面试题 == 和 equals 的区别

    == 和 equals 的区别是什么? == 解读 对于基本类型和引用类型,== 的作用效果是不同的,如下所示: 基本类型:比较的是值是否相同: 引用类型:比较的是引用是否相同: 代码示例: Stri ...

  6. 答出多少面试题能吃上饭?

    一.基础     1.Java都有哪些数据类型?基本数据类型有哪些?分别占多少字节?多少位?引用数据类型又有哪些?         基本数据类型:byte(1).short(2).int(4).lon ...

  7. 年终盘点 | 2019年Java面试题汇总篇(附答案)

    作者 | 老王 来源 | Java中文社群「微信公众号」 在这岁月更替辞旧迎新的时刻,老王盘点了一下自己 2019 年发布的所有文章,意外的发现关于「Java面试」的主题文章,竟然发布了 52 篇,几 ...

  8. 【吐血整理】年度盘点 | 2019年Java面试题汇总篇——附答案

    在这岁月更替辞旧迎新的时刻,老王盘点了一下自己 2019 年发布的所有文章,意外的发现关于「Java面试」的主题文章,竟然发布了 52 篇,几乎是全年每周一篇面试文章的节奏,当然其中有不少的面试题来源 ...

  9. 2018Java面试题及答案【面试必看】

    4.&和&&的差别 答:?&是位运算符,表示按位与运算,&&是逻辑运算符,表示逻辑与(and) 5.Collection 和 Collections的差 ...

最新文章

  1. RGB转YUV 各种库的性能比较
  2. cuda 编 程(10) cuda 并行加速时间对比
  3. Linux深入理解Socket异常
  4. java魔法堂_Java魔法堂:调用外部程序
  5. snmp自动化安装脚本
  6. Windows下搭建ESP-IDF开发环境,适合ESP32/S2/C3/S3系列模组二次开发
  7. ssis 循环导入数据_使用集成服务(SSIS)包从Amazon S3 SSIS存储桶导入数据
  8. cnn 回归 坐标 特征图_RCNN, Fast R-CNN 与 Faster RCNN理解及改进方法
  9. docker学习笔记一:基本安装和设置容器静态ip
  10. 激活golang编辑器
  11. SSH三大框架的工作原理及流程
  12. 工业互联网标识解析与标识服务机构服务能力成熟度等级评估管理平台【需求规格说明书/用户手册】
  13. 2021非常全的接口测试面试题及参考答案
  14. 【开源】爬取QQ空间说说及简易数据分析
  15. AppBarLayoutCoordinatorLayoutBehavior
  16. linux有root权限留后门,linux下获取root权限后安装后门程序rootkit
  17. Mycat安装与配置详解
  18. mysql 设置 0、1 用什么数据类型_不断精炼核心知识点,终于能把MySQL讲懂了
  19. 底层之旅——Android显示驱动(framebuffer)的分析
  20. 网络分析——路径分析

热门文章

  1. java ora 00911_ORA-00911错误
  2. python unit test_python 中unittest单元测试为什么addTest没用。
  3. c语言运算符类型转换,C语言中强制类型转换运算符的独特作用
  4. blob的真实地址怎么获得_使用Python抓取m3u8加密视频 续:获得index.m3u8 地址
  5. Hive中实现有序,有序concat拼接,有序集合,hive方法操作命令,与自带方法列表
  6. latex 小于_一份菜鸡的Latex课堂作业works--(ii)
  7. 高性能mysql 第六章_第六章 查询性能优化
  8. python和php可以一起用吗_Apache同时支持PHP和Python的配置方法
  9. 如何设置定时器每天执行一次_游戏活动的自动循环——定时器管理
  10. STM32中常用的C语言知识点,开始复习!