CSS定位机制之一:普通流

本文详细解析了CSS中的普通流(normal flow)概念及其在网页布局中的作用,包括元素如何按照HTML顺序排列,以及如何通过创建新的块格式化上下文(block formatting context)解决边距重叠等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原创。原文:http://www.swordair.com/blog/2010/08/415,转载请保留。

由于没有找到自己认为完整的关于普通流、浮动和绝对定位的中文文章,于是鼓起勇气决定自己来写篇。为此大致啃掉了CSS2.1里的 8 Box model 以及 9 Visual formatting model 。实话说,还真是看得有点头大,呵呵~

文档流,其实标准里根本就没有这个词。如果把文档流直译为英文就是 document flow ,但标准里只有另一个词,叫做普通流( normal flow ),或者称为常规流。但似乎大家更习惯文档流的称呼,因为很多中文翻译的书就是这么来的。比如《CSS Mastery》,英文原书中至始至终都只有普通流 normal flow 这一词,从来没出现过文档流 document flow 。但是中文译本“普通流”和“文档流”却是交替出现的。

什么是普通流?简单说就是元素按照其在 HTML 中的位置顺序决定排布的过程。并且这种过程遵循标准的描述。

为了从不同角度说明,我采集了一些可能冗长、具体或者晦涩的其他人给出的定义:

  • 将窗体自上而下分成一行行,并在每行中按从左至右的顺序排放元素,即为文档流。
  • Jennifer.Kyrnin@About.com: 普通流是元素在多数情况下呈现在 web 页面上的方式。所有 HTML 都在块框( block boxes,块级元素 )或者行内框( inline boxes,行内元素 )中。
  • Rainbo Design: 当浏览器开始渲染 HTML 文档,它从窗口的顶端开始,经过整个文档内容的过程中,分配元素需要的空间。除非文档的尺寸被 CSS 特别的限定,否则浏览器垂直扩展文档来容纳全部的内容。每个新的块级元素渲染为新行。行内元素则按照顺序被水平渲染直到当前行遇到了边界,然后换到下一行垂直渲染。这个过程被成为普通文档流。

可见,把流( flow )理解为流程,完全说的通。普通流即是通常情况下的元素排布和定位流程。

但其实在CSS2.1RC里,普通流的本质是三种定位机制( Positioning schemes )之一,被定义为:

引用:

Normal flow. In CSS 2.1, normal flow includes block formatting of block boxes, inline formatting of inline boxes, relative positioning of block or inline boxes, and positioning of run-in boxes.

这个过程包括了块格式化( block formatting ),行内格式化(inline formatting ),相对定位( relative positioning ),以及 run-in boxes 的定位。似乎和上面那些迥然不同,但是把这些分解开来,仍然是一致的。

另外,9.4 Normal flow下还有一段:

引用:

Boxes in the normal flow belong to a formatting context, which may be block or inline, but not both simultaneously. Block boxes participate in a block formatting context. Inline boxes participate in an inline formatting context.

这是段描述,不是定义。在普通流中的 Box(框) 属于一种 formatting context(格式化上下文) ,类型可以是 block ,或者是 inline ,但不能同时属于这两者。并且, Block boxes(块框) 在 block formatting context(块格式化上下文) 里格式化, Inline boxes(块内框) 则在 inline formatting context(行内格式化上下文) 里格式化。

我们知道,任何被渲染的元素都属于一个 box ,并且不是 block ,就是 inline 。即使是未被任何元素包裹的文本,根据不同的情况,也会属于匿名的 block boxes 或者 inline boxes。所以上面的描述,即是把所有的元素划分到对应的 formatting context 里。

 

组合上面的定义,并且姑且先把 formatting context 看做是一种范围限定,那么具体讲,普通流就是这样的过程:

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 进行相对定位,即相对于已排布的位置进行偏移。元素在其中保留原来所占用的空间。

说了一堆东西,其实就只是在说如何排布元素而已。那些都非常容易理解,除了一个概念—— formatting context 。

什么是 formatting context ? context 总是解释为上下文环境,那么格式化上下文就应该是指格式化时的前后关系。

然而对此,标准里没有更多的定义和解释。

虽然 mozilla developer center 上没有关于 inline formatting context 的资料,但是却有关于 block formatting context 的描述:一个 block formatting context 是web页面可视化CSS渲染的一个部分,是一块 block boxes 排布以及 float 元素相互作用的区域。
用自己的话简言之,那是一个作用范围。可以把它理解成是一个独立的容器,并且这个容器的里box的布局,与这个容器外的毫不相干。

下面的这些情况,都会创建一个新的 block formatting context:

  • 根元素
  • 浮动或绝对定位的元素
  • display 值为 inline-blocks , table-cell 或 table-caption
  • overflow 值为非 visible

虽然标准里没有提到根元素会创建新的 block formatting context ,但是mozilla提到了,并且这也解释了初始的一个上下文环境的建立。

这里有个建立( establishes )的概念,这个概念和建立容器块( containing block )的概念类似。比如,A是B父元素,当B被渲染时其位置和大小会参照一个容器块,这个容器块是由其父元素A建立的。是的,有点简单问题复杂化。虽然实质上父元素就是子元素的容器,但是过程中间却有个建立( establishes )的概念。并且这个创建的概念被应用于其他作用范围,包括 block formatting context 。

想想我们平常在做的事情。当一个父元素因为子元素浮动而导致高度为0的时候,也许我们会习惯的加上这样的规则:

overflow:hidden;zoom:1; 。

overflow:hidden 不正是创建了一个新的 block formatting context 吗?那么 zoom:1 是怎么回事?这不得不提到 IE 私有的 hasLayout ,一个和 block formatting context 行为相仿的IE特产。对于 hasLayout ,本文不做讨论。可以阅读那篇有名的 On having layout中文版old9 翻译过,但是链接似乎暂时挂掉了,所以可以看看蓝色理想上转载的版本

这就是为什么浮动元素总是容纳浮动元素的原因——浮动元素创建了新的 block formatting context,其内部的布局不在和外部有关。比如内部的浮动清除不会再影响到外部,并且内部的浮动对于外部而言也是不可见的。这也是为什么《精通CSS》会说 “应用值为 hidden 或 auto 的 overflow 属性会自动地清理任何浮动元素” 的原因。同时,这也是为什么有的时候必须用清除浮动而不是设置overflow来使父容器容纳浮动元素,因为 “设置框的overflow属性会影响它的表现”。

 

举个实际当中的常见例子,比如垂直边距叠加问题:

代码:

<html>
    <head></head>
    <body>
        <div id="A" style="background:gray;margin-top:20px;">
            <div id="B" style="margin-top:10px;">
                我有10px m-t
            </div>
        </div>
    </body>
</html>

如果在现代的浏览器里运行,那么 B 的10px上边距将会和父元素 A 的20px上边距重叠起来,从而看起来就好像 B 没有上边距一样。就像前面说的那样,同一个 block formatting context 中的垂直边界将被重叠。那么不同 block formatting context 呢?

这种情况,如果不想加边框( border:1px solid transparent; )解决的话,那么就需要 A 建立一个新的 block formatting context 将 B 包裹起来,那么 A 的上边距和 B 的上边距就毫不相干了。可以用浮动,也可以加 overflow ,这要看具体情况。

代码:

<html>
    <head></head>
    <body>
        <div id="A" style="background:gray;margin-top:20px;overflow:auto;">
            <div id="B" style="margin-top:10px;">
                我有10px m-t
            </div>
        </div>
    </body>
</html>

再一个例子,回头看下上面过程里这样的一句:除非创建一个新的 block formatting context ,否则块级元素的布局不受浮动元素的影响。

这是造成元素重叠的原因。比如下面的代码:

代码:

<html>
    <head></head>
    <body>
        <div id="A" style="background:gray;overflow:auto;">
            <div id="B" style="background:green;margin:10px 10px 0 0;float:right;">
                浮动元素m_10_10_0_0
            </div>
            <div id="C" style="background:red;">
                普通流块
            </div>
        </div>
    </body>
</html>

普通流块 C 在容器 A 里排布的时候,并不受浮动元素的影响,甚至当浮动元素 B 不存在。但是如果 C 创建了新的 block formatting context ,那么,普通流块c就会像 line box 一样受到浮动元素存在的影响而缩小。

代码:

<html>
    <head></head>
    <body>
        <div id="A" style="background:gray;overflow:auto;">
            <div id="B" style="background:green;margin:10px 10px 0 0;float:right;">
                浮动元素m_10_10_0_0
            </div>
            <div id="C" style="background:red;overflow:auto;">
                普通流块
            </div>
        </div>
    </body>
</html>

关于浮动和 block formatting context ,brunildo.org 上有一份不错的参考

说了这么多了,其实概念仍然可以很简单。普通流仅仅只是一种定位的机制。而flow本身在标准里也可以作为一个动词,就如同按顺序一个个的拿出HTML元素然后放到页面上一般。只是要注意一下 formatting context 的概念,特别是 block formatting context ,因为其影响更大(包括边距重叠、浮动清除、元素重叠等)。

写到这里也就差不多了,由于水平所限,如文中有不当之处,请指点下,非常感谢。谢谢阅读

资源下载链接为: https://pan.quark.cn/s/abbae039bf2a 无锡平芯微半导体科技有限公司生产的A1SHB三极管(全称PW2301A)是一款P沟道增强型MOSFET,具备低内阻、高重复雪崩耐受能力以及高效电源切换设计等优势。其技术规格如下:最大漏源电压(VDS)为-20V,最大连续漏极电流(ID)为-3A,可在此条件下稳定工作;栅源电压(VGS)最大值为±12V,能承受正反向电压;脉冲漏极电流(IDM)可达-10A,适合处理短暂高电流脉冲;最大功率耗散(PD)为1W,可防止器件过热。A1SHB采用3引脚SOT23-3封装,小型化设计利于空间受限的应用场景。热特性方面,结到环境的热阻(RθJA)为125℃/W,即每增加1W功率损耗,结温上升125℃,提示设计电路时需考虑散热。 A1SHB的电气性能出色,开关特性优异。开关测试电路及波形图(图1、图2)展示了不同条件下的开关性能,包括开关上升时间(tr)、下降时间(tf)、开启时间(ton)和关闭时间(toff),这些参数对评估MOSFET在高频开关应用中的效率至关重要。图4呈现了漏极电流(ID)与漏源电压(VDS)的关系,图5描绘了输出特性曲线,反映不同栅源电压下漏极电流的变化。图6至图10进一步揭示性能特征:转移特性(图7)显示栅极电压(Vgs)对漏极电流的影响;漏源开态电阻(RDS(ON))随Vgs变化的曲线(图8、图9)展现不同控制电压下的阻抗;图10可能涉及电容特性,对开关操作的响应速度和稳定性有重要影响。 A1SHB三极管(PW2301A)是高性能P沟道MOSFET,适用于低内阻、高效率电源切换及其他多种应用。用户在设计电路时,需充分考虑其电气参数、封装尺寸及热管理,以确保器件的可靠性和长期稳定性。无锡平芯微半导体科技有限公司提供的技术支持和代理商服务,可为用户在产品选型和应用过程中提供有
资源下载链接为: https://pan.quark.cn/s/9648a1f24758 在 JavaScript 中实现点击展开与隐藏效果是一种非常实用的交互设计,它能够有效提升用户界面的动态性和用户体验。本文将详细阐述如何通过 JavaScript 实现这种功能,并提供一个完整的代码示例。为了实现这一功能,我们需要掌握基础的 HTML 和 CSS 知识,以便构建基本的页面结构和样式。 在这个示例中,我们有一个按钮和一个提示框(prompt)。默认情况下,提示框是隐藏的。当用户点击按钮时,提示框会显示出来;再次点击按钮时,提示框则会隐藏。以下是 HTML 部分的代码: 接下来是 CSS 部分。我们通过设置提示框的 display 属性为 none 来实现默认隐藏的效果: 最后,我们使用 JavaScript 来处理点击事件。我们利用事件监听机制,监听按钮的点击事件,并通过动态改变提示框的 display 属性来实现展开和隐藏的效果。以下是 JavaScript 部分的代码: 为了进一步增强用户体验,我们还添加了一个关闭按钮(closePrompt),用户可以通过点击该按钮来关闭提示框。以下是关闭按钮的 JavaScript 实现: 通过以上代码,我们就完成了点击展开隐藏效果的实现。这个简单的交互可以通过添加 CSS 动画效果(如渐显渐隐等)来进一步提升用户体验。此外,这个基本原理还可以扩展到其他类似的交互场景,例如折叠面板、下拉菜单等。 总结来说,JavaScript 实现点击展开隐藏效果主要涉及 HTML 元素的布局、CSS 的样式控制以及 JavaScript 的事件处理。通过监听点击事件并动态改变元素的样式,可以实现丰富的交互功能。在实际开发中,可以结合现代前端框架(如 React 或 Vue 等),将这些交互封装成组件,从而提高代码的复用性和维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值