读 You Don't Know CSS 笔记

一,CSS的盒子位置

CSS布局的核心在于如何将一系列HTML元素映射到一组盒子上,这些盒子被放在x-y-z坐标系里。

盒子的x和y坐标事实上是由布局方案(position scheme)决定。 而z坐标是由层叠水平(stacking level)来决定。

本篇文章主要讨论CSS2.1中引入的position scheme: normal flow,floats 和 absolute position。

Position schemes
CSS2.1 定义了三种position scheme,其包括:

  • normal flow,其包括三种formatting contexts:block,inline和relative formatting context
  • float:其与normal flow互动,其构成了现代CSS gird framework基础。
  • absolute position,其处理absoluta和fixed 元素相对于normal flow 的定位。

    position scheme 对x-axis和y-axis元素定位有重大影响。所有的元素除非通过设置float和position属性从normal中移除,默认属于normal flow。
    这里写图片描述

通过它们与normal flow 元素的交互方式能更好的理解float 和 absolute position,所以我先说明normal flow。

仔细想下,事实上layout在两方面在起作用:

  • 元素的盒子大小和对齐方式,其通常由display的属性(width,height,margin)控制
  • 一个特定父元素的子元素是如何相对于彼此放置的。

一个父元素的子元素的相对位置是通过父元素为子元素建立的formatting context 控制的,在normal flow中,可以是block formatting context,inline formatting context或者relative formatting context。

这里终于到了大名鼎鼎的BFC(block formatting context),简单来说,BFC就是normal flow中一种formatting context。所以说触发BFC这种说法根本就是错误的,更为准确的说法是建立一个新的BFC(establish a new block formatting context)。鉴于BFC的迷惑性,在CSS3中已经被改为flowing root了。
至于种种的神奇作用(比如阻止margin collapse)均需要满足一定的前提。就那margin-collapse来说,其条件是collapse-margins
@ 两者都处于同一个BFC下的block-level-box
@ 两者间不存在line boxes,clearance,padding,border
@ 都处于垂直相邻的盒子边缘

这里的第一个条件是同一个BFC下块级盒子才可能发生margin-collapse。那么假如父元素创建了新的BFC,那么父元素和子元素将不再处于同一个BFC下(子元素处于父元素新创建的新的BFC下),则可以阻止发生margin collapse。相反若子元素创建了新的BFC,那么子元素和父元素仍处于同一个BFC下,只是孙元素处于新的BFC下,所以说,父元素和子元素之间仍然发生margin collapse,其效果如下所示:


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
.parent{
    width: 100px;
    height: 100px;
    background: antiquewhite;
    margin: 10px;
}
.son{
    width: 40px;
    height: 40px;
    background: red;
    margin-top: 50px;
}
.demo2 .parent{
    overflow: hidden;
}
.demo1 .son{
    overflow: hidden;
}
</style>
<body>
    <div class='demo1'>
        <div class="parent">
            <div class="son">

            </div>
        </div>
    </div>

    <div class="demo2">
        <div class="parent">
            <div class="son">

            </div>
        </div>
    </div>

</body>
</html>

渲染效果如下:
这里写图片描述

可以看出子元素创建了新的BFC但是并不能阻止margin collapse。

CSS2.1 规范定义了formatting context如下:

normal flow 里的box属于一个formatting context,其是block或者inline,但不能同时都是。block-level盒子参与BFC(block formatting context),inline-level 盒子参与IFC(inline formatting context)

父元素根据子元素是inline-level还是block-level为其子元素建立formatting context。术语inline-level 和 block-level 用来强调display属性不为inline和block的盒子仍然可以术语这两种formatting context。例如display:table元素被认为是block-level而display:inline-table元素被认为inline-level。

一个block-level的元素定义如下:

block-level 元素是那些在文档中视觉表现为block的元素。display属性为’block’。
block-level的盒子就是参与BFC的盒子,每个block-level的元素都会生成一个block-level box。

一个inline-level 元素定义如下:

inline-level 元素是那些在源文档中不构成块状内容的元素。display为‘inline’,’inline-table’,‘inline-block’的元素师inline-level的。inline-level元素生成inline-level盒子,其参与IFC。

Anonymouse box generation

匿名盒子生成用于处理当一个父元素既含有inline-level盒子又含有block-level的情形(此时会生成匿名盒子)和当标签包含了inline-level元素与包围文本的混合,如paragraph里嵌入了em和i标签。

Anonymous block boxes

规范里给了如下例子,可得:

<div>
       some text
       <p>More text</p>
</div>

如果一个容器盒子(如上面的div生成的盒子)内部有一个block-level盒子(如上面的P标签),那么我们会强迫该容器内部会有两个block-level盒子。

规范里提供了如下的描述来阐明匿名盒子如何包裹inline-level内容
这里写图片描述

当一个inline盒子包含一个in-flow的block-level的盒子,那么inline盒子(和其同一行的祖先盒子)会被打散围绕着block-level盒子(且任何的block-level兄弟都是连续的或者被collapse whitespace 或者 out-of-flow元素分割)

Anonymous inline boxes
当一个block container 包含文本并且这些文本没有被包含在inline-level 元素里时会生成匿名内联盒子(anonymous inline boxes)。例如如下标记:

<p>Some <em> emphasized </em> text </p>

会产生两个匿名的盒子,一个包含’Some’ ,一个包含’text’。

匿名盒子生成非常重要,因为其决定了该为在normal flow中包含的block 和 inline-level 的元素生成何种 formatting context 。
在平常我们经常遇到HTML布局里的一个父元素既含有block-level也含有inline-level内容。匿名盒子生成可以保证如果任何block-level被混入inline-level的兄弟元素时,那么inline-level盒子会被包裹进一个匿名block-level容器内,这也意味着它们将被视为block-level元素相对于其他盒子布局。

Normal flow positioning

在normal flow中,一个父元素内的子盒子是按照formatting context布局的。normal flow中的两个formatting context大致对应于垂直排列和水平排列。

Normal flow: block formatting

规范为BFC下如何布局提供了很好的说明

在block formatting context中,盒子一个接一个,从上向下垂直排列。两个相邻的盒子之间的距离由margin属性决定。相邻block-level盒子的垂直margin可能会发生重叠。在block formatting context下,每个盒子的左外边缘触碰到container block的左边缘(对于right-to-left formatting context, 右边缘相邻)。这甚至适用于存在floats的情形。

最重要的两个结论是在BFC下盒子是垂直排列的,而且每个盒子的左边缘会触碰到container box的左边缘(即使在float存在的情况下)

下面的代码可以演示:

.float {
  float: left;
}
.foo {
  padding-top: 10px;
}
.bar {
  width: 30%;
}
.baz {
  width: 40%;
}
<div class="container violet">
  <div class="float red">float</div>
  <div class="foo blue">foo</div>
  <div class="bar green">bar</div>
  <div class="baz orange">baz</div>
</div>

这里写图片描述

上面的例子中

  • 每个block盒子都在container box的左外边缘。
  • 即使存在float也不会影响其在左外边缘的位置,除了会造成文本的偏移
  • foo对应的block box(没有明确的设置宽度)宽度设置为容器宽度
  • 另外两个设置宽度的盒子,从左外边缘扩展
  • 另外两个盒子并没有在一行,即使其能够塞进一行

Normal flow: inline formatting

IFC相当复杂,因为其设计到将内容拆分为line boxes。

在IFC中,盒子在container box 里被一个接一个,自上而下的水平放置。水平的margin,borders,和padding散布在这些box之间。

这些盒子可以以不同的方式垂直放置:其底部和顶部可能是对齐的。包含这些盒子的方形区域构成了一行即行框(line box)

line box的宽度由container box的宽度和是否存在float决定。

简单来说,在IFC中盒子是水平相邻放置的。line box是按需来生成的。那么它的宽度通常是包含块的高度(减去float)而且其高度足够包含其内部所有的盒子。

Horizontal alignment within line boxes: text-align

text-align属性控制inline-box如何在line-box内对齐。

text-align:left 左对齐;text-align:right 右对齐。

注意到其仅适用于当line box含有空余空间的情形,而且你不能直接控制inline-leve box 在line box中如何摆放,标准规定:

当inline-level box的宽度小于所在line box的宽度时,其在line box的水平分布取决于‘text-align’属性。如果该属性的值为‘justify’,那么UA(user agent)可以伸展为inline boxes内的空格和文本。

换句话说,text-align属性仅在inline content的内容已经分布在line boxes之后才加以应用

一块文本就是一组line boxes。’left’,’right’和’center’指明了inline-level盒子在line box 中时如何对齐的,其对齐是相对于line box而非viewport。

Vertical alignment within line boxes:vertical-align

下面两个属性控制line box的垂直对齐

vertical-align:默认值为baseline,控制盒子的垂直对齐,仅适用于inline(和table-cell)盒子。
line-height默认值为normal,规定了用于计算line box height的height。

vertical-align 控制了line box内inline boxes的垂直对齐方式,而非line box自身的对齐方式。为了理解inline box是如何定位的,你需要首先理解line box和inline box的高度是如何计算的。

line box的高度受以下两个因素影响:

  • 其包含的inline box 的高度
  • 其包含的inline box的对齐方式

    inline box(非替换元素)的高度按下面方式决定

‘height’ 属性并不其起作用,内容区的高度是基于font的,但是规范没有规定是如何基于font的。UA可以例如使用em-box。
inline垂直的padding,border,margin与inline box的line height的计算有关。但是当计算line-box的高度时只有line-height起作用。
正如你从规范所见,inline box的height 由 ‘font’ 和 ‘line-height’。特别的是,每个font都必须定义一个baseline,一个text-top和一个text-bottom位置。inline box内容区域的高度等于font的高度乘以line-height的属性值。
对于一个非替换的inline元素,’line-height’规定了用于计算 line box高度的height。

总结来说inline box有如下属性:

  • font size : 决定了字体的大小。
  • line height : 决定了inline box 的高度。
  • baseline:其由font确定。

Normal flow: relative positioning

既然我们已经讨论完bfc和ifc了,接下来可以讨论最后一个normal flow 布局 relative positioning了。

Relative positioning被认为是normal flow布局的一部分,因为其与normal flow没有太大差异。

relative:盒子的位置完全基于normal flow计算,然后对盒子进行偏移。’position:relative’的属性对于table-row-group,table-header-group,table-footer-group,table-row,table-column-group,table-column,table-cell,和table-caption元素是未定义的。

注:我发现理解relative positioning的最好方式是从渲染的角度考虑,我们发现’position:relative’属性几乎能和其他所有布局方式同时配合使用,而不会发生冲突,而position:absolute和float却不行(这两者实际发生冲突),原因在于position:relative的作用是发生在paint阶段,而其他布局则是发生在layout阶段。position:relative是在layout阶段完成后,在paint阶段进行偏移。(这只是一种理解方式很可能有错误)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值