我真的了解css吗? 我这样问自己。
我的思考和这几天的学习来自于看了寒冬winter大神的这篇blog:谈谈面试与面试题 。说实话, 我边看,脑袋里面边翻篇一样的过着我的那点css知识,看完了,整个人都不好了。
我觉得不是题目有多难,而是我之前从没觉得我应该去仔细的学习和思考这些问题。于是,最近就仔细的学习了下,分析总结归纳在这,也方便以后进一步的学习和更加深刻的理解。
---------------------------------------------------------
| 1.一些自适应或垂直水平居中问题汇总;
| 2.Normal Flow
| 3.Containing Block
| 4.Margin Collapse
| 5.BFC
| 6.Baseline
| 7.Writing Mode
| 8.unicode-bidi
---------------------------------------------------------
如果你觉得自己的css水平不太过关,这里有个简洁明了的layout教程,很易学易懂,可以先学习一下:学习CSS Layout
其实我觉得上面有些关键词其实是非常息息相关的,这里只是分别理解下。
一、一些自适应或垂直水平居中问题
1.必备技能:水平居中
大家都知道哈,margin:0 auto;搞定:
1 #block{ 2 margin: 0 auto; 3 width: 100px; 4 height: 100px; 5 background-color: yellow; 6 }
不过可要看好喔,我没有float也没有absolute。然后我加了下float:left;不居中了,然后我又加了position:absolute;也不居中了。那如果我有absolute要怎么办呢:
1 #block{ 2 position: absolute; 3 width: 100px; 4 height: 100px; 5 left: 50%; 6 top: 50%; 7 margin-left: -50px; 8 margin-top: -50px; 9 background-color: yellow; 10 }
上面的代码在垂直方向上也居中了。
2.必备技能:文本垂直居中
div中的文字垂直居中于容器中:
1 css: 2 #block{ 3 font-size: 12px; 4 height: 36px; 5 line-height: 36px; 6 border: 2px #000 solid; 7 } 8 9 html: 10 <div id="block"> 11 我是文本,我要垂直居中在容器中啦! 12 </div>
若是多行的文本,这样就会有问题了。前两天看到有一个多行文本垂直居中的实现,是用display:table和display:table-cell一起来实现的,先看实现方法:
1 CSS: 2 3 #wrap{ 4 height: 400px; 5 display: table; 6 } 7 #block{ 8 vertical-align: middle; 9 display: table-cell; 10 font-size: 12px; 11 border: 2px #000 solid; 12 width: 500px; 13 }
原理是:CSS中的vertical-align属性只会对拥有valign特性的(X)HTML标签起作用。所以通过display:table;模拟<table>然后就可以使用vertical-align属性了。
display:table要用在父元素上,display:table-cell要用到子元素上,像table布局一样。
1 HTML: 2 <div id="wrap"> 3 <div id="block"> 4 <pre>我是文本,我要垂直居中在容器中啦! 5 6 </pre>我也是文本喔,我也要居中~~ 7 </div> 8 </div>
这里用<pre></pre>是为了模拟多行文本。
不过要郁闷的注意浏览器的兼容性:
3. 一个div里面两个子div,其中一个定高100px;要另一个随父元素适应高:
1 CSS: 2 #wrapper{ 3 position: relative; 4 width: 300px; 5 min-height: 500px; 6 border:2px #00f solid; 7 } 8 #fixed{ 9 width: 300px; 10 height:100px; 11 background-color: yellow 12 } 13 #fit{ 14 position: absolute; 15 background-color: pink; 16 width: 300px; 17 top: 100px; 18 bottom: 0; 19 }
绝对定位,有了top再加上bottom:0;然后它就填充了剩下的高度。
4. css3有了很好玩的东西,我觉得有了它,再也不用为各种布局烦恼了:flexbox-快速布局神器
我就尝试了一个下面这样的简单三列布局:
1 2 #wrap{ 3 display: flex; 4 flex-flow:row wrap; 5 align-items:stretch; 6 justify-content:space-around; 7 width: 100%; 8 height: 300px; 9 border: 2px #000 solid; 10 } 11 #left{ 12 flex:1 200px; 13 background-color: red; 14 } 15 #right{ 16 flex:2 360px; 17 background-color: yellow; 18 } 19 #center{ 20 flex:1 250px; 21 background-color: blue; 22 }
不过,还是老问题,浏览器的兼容性永远不像我们想的那么美好:
小结:这里我也就列出了基本的几个,在自己对布局有了些理解后,一般的类似布局应该都不会有问题,后面碰到有挑战的有趣的我再收集过来,如果有有趣的相关的问题,希望你与我分享喔。
二、Normal Flow
这里的normal flow(普通流)实际上为CSS的定位机制之一,其他两个分别是如雷贯耳的浮动和绝对定位。
那具体什么是普通流呢?普通流就是在多数情况下呈现在web页面上的方式,所有的HTML元素都在块框(block boxes,块级元素)或者行框(inline boxes,行内元素)中。
普通流就是这样的过程:
1.对于块级元素:
在对应的 block formatting context 中,块级元素按照其在HTML中的顺序,在其容器框里从左上角开始,从上到下垂直地依次分配空间、堆砌( stack ),并独占一行,边界紧贴父容器。两相邻元素间的距离由 margin 属性决定,在同一个 block formatting context 中的垂直边界将被重叠( collapse )。并且,除非创建一个新的 block formatting context ,否则块级元素的宽度不受浮动元素的影响(这就是浮动元素能盖在块级元素上面的原因)。
2.对于行内元素:
在对应的 inline formatting context 中,行内元素从容器的顶端开始,一个接一个地水平排布。水平填充、边框和边距对行内元素有效。但垂直的填充、边框和空白边不影响其高度。一个水平行中的所有 inline box 组成了名为 line box 的矩形区域。 line box 的高度始终容下所有的 inline box ,并只与行高有关。 line box 的宽度受到父容器和浮动元素存在的影响(这就是文本环绕浮动元素)。如果 line box 的宽度小于容器, line box 的水平排布就取决于 text-align 。如果 line box 的宽度大于容器,则截断 line box 并换行在新的 line box 中重新排布元素(截断处不应用 padding 和 margin 值)。如果 line box 无法截断,如单词过长或者指定不换行,则会溢出容器。
3.对这些 block box 和 inline box 进行相对定位,即相对于已排布的位置进行偏移。元素在其中保留原来所占用的空间。
这有一篇文章,作者总结的非常好:CSS定位之一:普通流
三、Containing Block
containing block(包含块),我理解就是定位参考框,与上面说的css的定位机制息息相关。元素一旦定义了定位显示(static absolute relative)便具有了包含块的性质,它所包含的定位元素都将以该包含块为坐标系进行定位和调整。
举个简单明了的小例子:如果一个div定义了position:absolute;那么他会相对于谁定位呢?他会向上寻找父元素-》父元素的父元素....直到找到一个position:relative/fixed/absolute的父元素,然后来相对于它进行对位。
包含块的建立有它的规则:
1.根元素作为初始包含块,原谅后面两句我实在翻译不来,请戳下面手册,自行理解;
2.对于position:relative和static的元素,他们的包含块是由最近的块元素祖先建立的;
3.对于position:fixed的元素,他的包含块是由视口(viewport)建立的;
4.就像上面的小例子,position:absolute的元素他的包含块由最近的不是position:static的祖先建立:
4.1 如果祖先是块级元素,containing block 由祖先的 padding edge 形成。
4.2 如果祖先是内联元素,containing block 取决于祖先的 direction 属性。
w3c包含块的定义:the definition of containing block
我觉得吧,既然简单了解了containing block的工作原理,那么我觉得css另一定位机制position相关,也必须再来一遍了,张鑫旭大神的这一系列写的蛮好,自行移步脑补:
CSS 相对|绝对(relative/absolute)定位系列(一)
CSS 相对|绝对(relative/absolute)定位系列(二)
CSS 相对|绝对(relative/absolute)定位系列(三)
CSS 相对|绝对(relative/absolute)定位系列(四)
CSS 相对|绝对(relative/absolute)定位系列(五)
四、Margin Collapse
W3C是这样定义collapsing margins 的:‘这里的折叠意味着,相邻的边距(没有非空内容,padding或border areas或clearance来分开他们)两个或两个以上的盒子(可以是相邻或嵌套)相结合,形成一个单一的边缘’。简单来说,就是:
1.垂直的两个正margin重合,会得到两者中较大的margin,margin较小的元素的margin值就会被collapsed为0;
2.如果有一个margin为负值,那么正负相加得到最后的值;
3.如果两个margin都是负的,那么绝对值较大的负值会被应用。
但是下面这些情况就不会发生margin collapse:
n.1 浮动元素;
n.2 position:absolute的元素;
n.3 inline-block元素;
n.4 元素的overflow值设为其他不是可见的值的时候,他不与他的子元素发生margin collapse;
n.5 被cleared的元素,他的top margin不与他父元素的bottom margin重叠;
n.6 根元素不发生重叠;
定义理解起来总是有点别扭,看些实例就好了,可以移步这里:Collapsing margins
五、BFC
什么是bfc呢,上面理解normal flow的时候总在说那个block formatting context,其实这就是bfc。就是说: 浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容创建新的BFC(块级格式上下文)。
通俗点理解,我觉得他就是块框和行框的渲染上下文。
我们可以理解为一个箱子(实际上是看不见摸不着的),箱子里面物品的摆放是不受外界的影响的。转换为BFC的理解则是:BFC中的元素的布局是不受外界的影响(我们往往利用这个特性来消除浮动元素对其非浮动的兄弟元素和其子元素带来的影响。)并且在一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。
仔细读过这个 CSS定位之一:普通流 应该就会理解了bfc到底是什么。normal flow中块框和行框的表现还有margin collapse都跟他息息相关。
这里有较为容易理解的相关描述:深入理解BFC
六、Baseline
说到baseline我所想到的就是小学时候用的英语本上的四线三格,想着这个应该就更好理解了。我觉得baseline某种意义上是为完美主义者准备的:
我觉得去实现这种效果,最重要的是理解line-height,大多时候我们只知道:line-height 属性设置行间的距离(行高)。
但我觉得应该了解再稍微多一点:
1. 该属性会影响行框的布局。在应用到一个块级元素时,它定义了该元素中基线之间的最小距离而不是最大距离。
2. line-height 与 font-size 的计算值之差(在 CSS 中成为“行间距”)分为两半,分别加到一个文本行内容的顶部和底部。可以包含这些内容的最小框就是行框。
然后我们再去探究上图的baseline是如何实现的(你需要足够的耐心来读完它):CSS基线之道
七、Writing Mode
css中的writing mode(书写模式)取决于writing-mode、direction和text-orientation这些属性。它仅适用于<text>元素,并被< tspan >,< TREF >,<altglyph >,和< textpath >子元素忽略。
MDN上是这样说的:MDN writing-mode 手册属性后面有例,可以自己尝试,便于理解。
中文参考手册:书写模式(writing-mode)
八、unicode-bidi
说实话,在这之前我真的不知道unicode-bidi是什么。好滴吧,他其实是用来设置文本的方向来的。
用它的时候我觉得有必要弄清楚direction属性,direction是用来检索或设置文本流的方向。
---->当指定一个内联元素的unicode-bidi属性为normal时,direction属性不影响bidi重排序,即direction设置不生效。
手册上说的蛮全,但是我理解的有限,于是我便自己写了写试试:
unicode-bidi:bidi-override
unicode-bidi: embed;
总结:我觉得这里 有些大多是定义相关的,手册多读读多想想,理解了他们的工作机制就好了。我也要放在这里,自己常来读,反复思考。也要时常提醒自己不要眼高手低,遇到问题养成仔细学习的习惯,be patient...