你不知道的 CSS 之 包含块 ! 最细讲解,一听就懂!

你不知道的 CSS 之包含块

一说到 CSS 盒模型,这是很多小伙伴耳熟能详的知识,甚至有的小伙伴还能说出 border-box 和 content-box 这两种盒模型的区别。

但是一说到 CSS 包含块,有的小伙伴就懵圈了,什么是包含块?好像从来没有听说过这玩意儿。

好吧,如果你对包含块的知识一无所知,那么系好安全带,咱们准备出发了。

包含块英语全称为containing block,实际上平时你在书写 CSS 时,大多数情况下你是感受不到它的存在,因此你不知道这个知识点也是一件很正常的事情。但是这玩意儿是确确实实存在的,在 CSS 规范中也是明确书写了的:

CSS 2

image-20220814222458695

并且,如果你不了解它的运作机制,有时就会出现一些你认为的莫名其妙的现象。

那么,这个包含块究竟说了什么内容呢?

说起来也简单,就是元素的尺寸和位置,会受它的包含块所影响。对于一些属性,例如 width, height, padding, margin,绝对定位元素的偏移值(比如 position 被设置为 absolute 或 fixed),当我们对其赋予百分比值时,这些值的计算值,就是通过元素的包含块计算得来。

来吧,少年,让我们从最简单的 case 开始看。

<body>
  <div class="container">
    <div class="item"></div>
  </div>
</body>
.container{
  width: 500px;
  height: 300px;
  background-color: skyblue;
}
.item{
  width: 50%;
  height: 50%;
  background-color: red;
}

请仔细阅读上面的代码,然后你认为 div.item 这个盒子的宽高是多少?

image-20220814223451349

相信你能够很自信的回答这个简单的问题,div.item 盒子的 width 为 250px,height 为 150px。

这个答案确实是没有问题的,但是如果我追问你是怎么得到这个答案的,我猜不了解包含块的你大概率会说,因为它的父元素 div.container 的 width 为 500px,50% 就是 250px,height 为 300px,因此 50% 就是 150px。

这个答案实际上是不准确的。正确的答案应该是,div.item 的宽高是根据它的包含块来计算的,而这里包含块的大小,正是这个元素最近的祖先块元素的内容区。

因此正如我前面所说,很多时候你都感受不到包含块的存在。

包含块分为两种,一种是根元素(HTML 元素)所在的包含块,被称之为初始包含块(initial containing block)。对于浏览器而言,初始包含块的的大小等于视口 viewport 的大小,基点在画布的原点(视口左上角)。它是作为元素绝对定位和固定定位的参照物。

另外一种是对于非根元素,对于非根元素的包含块判定就有几种不同的情况了。大致可以分为如下几种:

  • 如果元素的 positiion 是 relative 或 static ,那么包含块由离它最近的块容器(block container)的内容区域(content area)的边缘建立。

  • 如果 position 属性是 fixed,那么包含块由视口建立。

  • 如果元素使用了 absolute 定位,则包含块由它的最近的 position 的值不是 static (也就是值为fixed、absolute、relative 或 sticky)的祖先元素的内边距区的边缘组成。

前面两条实际上都还比较好理解,第三条往往是初学者容易比较忽视的,我们来看一个示例:

<body>
    <div class="container">
      <div class="item">
        <div class="item2"></div>
      </div>
    </div>
  </body>
.container {
  width: 500px;
  height: 300px;
  background-color: skyblue;
  position: relative;
}
.item {
  width: 300px;
  height: 150px;
  border: 5px solid;
  margin-left: 100px;
}
.item2 {
  width: 100px;
  height: 100px;
  background-color: red;
  position: absolute;
  left: 10px;
  top: 10px;
}

首先阅读上面的代码,然后你能在脑海里面想出其大致的样子么?或者用笔和纸画一下也行。

公布正确答案:

image-20220814233548188

怎么样?有没有和你所想象的对上?

其实原因也非常简单,根据上面的第三条规则,对于 div.item2 来讲,它的包含块应该是 div.container,而非 div.item。

如果你能把上面非根元素的包含块判定规则掌握,那么关于包含块的知识你就已经掌握 80% 了。

实际上对于非根元素来讲,包含块还有一种可能,那就是如果 position 属性是 absolute 或 fixed,包含块也可能是由满足以下条件的最近父级元素的内边距区的边缘组成的:

  • transform 或 perspective 的值不是 none

  • will-change 的值是 transform 或 perspective

  • filter 的值不是 none 或 will-change 的值是 filter(只在 Firefox 下生效).

  • contain 的值是 paint (例如: contain: paint;)

我们还是来看一个示例:

<body>
  <div class="container">
    <div class="item">
      <div class="item2"></div>
    </div>
  </div>
</body>
.container {
  width: 500px;
  height: 300px;
  background-color: skyblue;
  position: relative;
}
.item {
  width: 300px;
  height: 150px;
  border: 5px solid;
  margin-left: 100px;
  transform: rotate(0deg); /* 新增代码 */
}
.item2 {
  width: 100px;
  height: 100px;
  background-color: red;
  position: absolute;
  left: 10px;
  top: 10px;
}

我们对于上面的代码只新增了一条声明,那就是 transform: rotate(0deg),此时的渲染效果却发生了改变,如下图所示:

image-20220814234347149

可以看到,此时对于 div.item2 来讲,包含块就变成了 div.item。

好了,到这里,关于包含块的知识就基本讲完了。

我们再把 CSS 规范中所举的例子来看一下。

<html>
  <head>
    <title>Illustration of containing blocks</title>
  </head>
  <body id="body">
    <div id="div1">
      <p id="p1">This is text in the first paragraph...</p>
      <p id="p2">
        This is text
        <em id="em1">
          in the
          <strong id="strong1">second</strong>
          paragraph.
        </em>
      </p>
    </div>
  </body>
</html>

上面是一段简单的 HTML 代码,在没有添加任何 CSS 代码的情况下,你能说出各自的包含块么?

对应的结果如下:

元素包含块
htmlinitial C.B. (UA-dependent)
bodyhtml
div1body
p1div1
p2div1
em1p2
strong1p2

首先 HTML 作为根元素,对应的包含块就是前面我们所说的初始包含块,而对于 body 而言,这是一个 static 定位的元素,因此该元素的包含块参照第一条为 html,以此类推 div1、p1、p2 以及 em1 的包含块也都是它们的父元素。

不过 strong1 比较例外,它的包含块确实 p2,而非 em1。为什么会这样?建议你再把非根元素的第一条规则读一下:

  • 如果元素的 positiion 是 relative 或 static ,那么包含块由离它最近的块容器(block container)的内容区域(content area)的边缘建立。

没错,因为 em1 不是块容器,而包含块是离它最近的块容器的内容区域,所以是 p2。

接下来添加如下的 CSS:

#div1 { 
  position: absolute; 
  left: 50px; top: 50px 
}

上面的代码我们对 div1 进行了定位,那么此时的包含块会发生变化么?你可以先在自己思考一下。

答案如下:

元素包含块
htmlinitial C.B. (UA-dependent)
bodyhtml
div1initial C.B. (UA-dependent)
p1div1
p2div1
em1p2
strong1p2

可以看到,这里 div1 的包含块就发生了变化,变为了初始包含块。这里你可以参考前文中的这两句话:

  • 初始包含块(initial containing block)。对于浏览器而言,初始包含块的的大小等于视口 viewport 的大小,基点在画布的原点(视口左上角)。它是作为元素绝对定位和固定定位的参照物。

  • 如果元素使用了 absolute 定位,则包含块由它的最近的 position 的值不是 static (也就是值为fixed、absolute、relative 或 sticky)的祖先元素的内边距区的边缘组成。

是不是一下子就理解了。没错,因为我们对 div1 进行了定位,因此它会应用非根元素包含块计算规则的第三条规则,寻找离它最近的 position 的值不是 static 的祖先元素,不过显然 body 的定位方式为 static,因此 div1 的包含块最终就变成了初始包含块。

接下来我们继续修改我们的 CSS:

#div1 { 
  position: absolute; 
  left: 50px; 
  top: 50px 
}
#em1  { 
  position: absolute; 
  left: 100px; 
  top: 100px 
}

这里我们对 em1 同样进行了 absolute 绝对定位,你想一想会有什么样的变化?

没错,聪明的你大概应该知道,em1 的包含块不再是 p2,而变成了 div1,而 strong1 的包含块也不再是 p2 了,而是变成了 em1。

如下表所示:

元素包含块
htmlinitial C.B. (UA-dependent)
bodyhtml
div1initial C.B. (UA-dependent)
p1div1
p2div1
em1div1(因为定位了,参阅非根元素包含块确定规则的第三条)
strong1em1(因为 em1 变为了块容器,参阅非根元素包含块确定规则的第一条)

好了,这就是 CSS 规范中所举的例子。如果你全都能看明白,以后你还能跟别人说你是看过这一块知识对应的 CSS 规范的人。

另外,关于包含块的知识,在 MDN 上除了解说了什么是包含块以外,也举出了很多简单易懂的示例。

具体你可以移步到:布局和包含块 - CSS:层叠样式表 | MDN

好了,这就是有关包含块的所有内容了,你学会了么?-)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/287875.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(切图笔记)layui表格单元格添加超链接 以及传参方法 亲测可用 附代码

layui在切图网日常的工作中常常用到&#xff0c;特别是它的layer弹窗&#xff0c;基本可以满足网站切图时候遇到的绝大多数弹窗的情况&#xff0c;参数比较丰富 灵活&#xff0c;是不可多得的网页插件之一&#xff0c;我见很多人说layui过时了&#xff0c;这是相比于vue正流行的…

具有不规则结果的常规 PyTorch 张量函数

一、说明 深度学习从业者应注意的常用 PyTorch 张量函数的例外情况。你是不是也和上面的人一样呢&#xff1f;如果是&#xff0c;那么本文可能会帮助您在使用 PyTorch 构建深度学习模型时发现一些常见错误。 我在下面提到了 5 个最常用的 PyTorch 函数及其小示例以及它们无法按…

阿里云服务器8080端口怎么打开?在安全组中设置

阿里云服务器8080端口开放在安全组中放行&#xff0c;Tomcat默认使用8080端口&#xff0c;8080端口也用于www代理服务&#xff0c;阿腾云atengyun.com以8080端口为例来详细说下阿里云服务器8080端口开启教程教程&#xff1a; 阿里云服务器8080端口开启教程 阿里云服务器8080端…

Codeforces Good Bye 2023 A~E

A.2023(思维) 题意&#xff1a; 有一个序列 A a 1 , a 2 , . . . , a n k A a_1, a_2, ..., a_{n k} Aa1​,a2​,...,ank​&#xff0c;且这个序列满足 ∏ i 1 n k a i 2023 \prod\limits_{i 1}^{n k}a_i 2023 i1∏nk​ai​2023&#xff0c;而这个序列中的 k k k个…

[Flutter]WindowsOS上运行遇到的问题总结

[Flutter]WindowsOS上运行遇到的问题总结 写在开头 Flutter项目已能在移动端完美使用后&#xff0c;想看看在桌面端等使用情况 基于Flutter3.0后已支持Windows/MacOS等桌面端&#xff0c;不过具体的系统&#xff0c;还需要看下官方文档解释。 这里抛出文档地址&#xff0c;可…

solidity显示以太坊美元价格

看过以太坊白皮书的都知道&#xff0c;以太坊比较比特币而言所提升的地方中&#xff0c;我认为最重要的一点就是能够访问外部的数据&#xff0c;这一点在赌博、金融领域应用会很广泛&#xff0c;但是区块链是一个确定的系统&#xff0c;包括里面的所有数值包括交易ID等都是确定…

教师行业的行业现状

teacher行业现状&#xff0c;近年来呈现出许多新的变化。作为一名从事教育行业多年的教师&#xff0c;深感这个行业的日新月异。今天&#xff0c;就让我来为大家揭秘一下&#xff0c;这个行业究竟有着怎样的现状吧&#xff01; 需求持续增长随着不断发展&#xff0c;家长们对孩…

【计算机毕业设计】SSM实现的在线农产品商城

项目介绍 本项目分为前后台&#xff0c;且有普通用户与管理员两种角色。 用户角色包含以下功能&#xff1a; 用户登录,查看首页,按分类查看商品,查看新闻资讯,查看关于我们,查看商品详情,加入购物车,查看我的订单,提交订单,添加收获地址,支付订单等功能。 管理员角色包含以…

AntDB设计之CheckPoint——引言与功能简述

1.引言 数据库服务能力提升是一项系统性的工程&#xff0c;在不同的应用场景下&#xff0c;用户对于数据库各项能力的关注点也不同&#xff0c;如&#xff1a;读写延迟、吞吐量、扩展性、可靠性、可用性等等。国内不少数据库系统通过系统架构优化、硬件设备升级等方式&#xf…

工程项目管理软件哪个好用?这款顶级软件别错过!

“随着市场竞争加剧、产品利润走薄、用户响应要求提高、产品更新迭代加快等各项因素的变化&#xff0c;项目管理开始成为越来越多企业的管理方式。项目管理的核心目标是在规定时间和预算内&#xff0c;完成事先确定的范围内的工作&#xff0c;同时达到质量要求。” 你所在公司…

架构师使用的8种重要生命周期图

什么是生命周期? 百度给出的定义是:生命周期就是指一个对象的生老病死。 生命周期的概念应用很广泛,特别是在政治、经济、环境、技术、社会等诸多领域经常出现,其基本涵义可以通俗地理解为"从摇篮到坟墓"的整个过程。对于某个产品而言,它的生命周期其实是指产…

【hyperledger-fabric】部署和安装

简介 对hyperledger-fabric进行安装&#xff0c;话不多说&#xff0c;直接开干。但是需要申明一点&#xff0c;也就是本文章全程是开着加速器进行的资源操作&#xff0c;所以对于没有开加速器的情况可能会由于网络原因导致下载资源失败。 资料提供 1.官方部署文档在此&#…

mfc100u.dll文件丢失,有五种不同解决方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“找不到mfc100u.dll文件”。那么&#xff0c;mfc100u.dll文件到底是什么&#xff1f;为什么会出现丢失的情况&#xff1f;本文将详细介绍mfc100u.dll文件的作用以及丢失的原因&#xff0c;并…

软件测试入门(知识汇总)

1、黑盒测试、白盒测试、灰盒测试 1.1 黑盒测试 黑盒测试又叫功能测试、数据驱动测试 或 基于需求规格说明书的功能测试。该类测试注重于测试软件的功能性需求。 采用这种测试方法&#xff0c;测试工程师把测试对象看作一个黑盒子&#xff0c;完全不考虑程序内部的逻辑结构和…

【多线程与高并发 四】CAS、Unsafe 及 JUC 原子类详解

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是若明天不见&#xff0c;BAT的Java高级开发工程师&#xff0c;CSDN博客专家&#xff0c;后端领域优质创作者 &#x1f4d5;系列专栏&#xff1a;多线程及高并发系列 &#x1f4d5;其他专栏&#xff1a;微服务框架系列、…

每日一题 2487. 从链表中移除节点(中等,回溯)

显然只要从后往前遍历链表&#xff0c;设 t 为当前的最大值&#xff0c;只要在遍历过程中比 t 小的节点都删除&#xff0c;大于等于 t 的则更新 t 为新的节点 通过递归回溯的方法可以很简单地实现从后往前遍历链表 # Definition for singly-linked list. # class ListNode: # …

Qt第一个UI程序设计

在第一个Qt程序的基础上我对ui界面进行设计&#xff0c;点击设计按钮 然后 拖动Label按钮输入想要输入的语句。 运行结果如下图。

【LMM 008】Instruction Tuning with GPT-4

论文标题&#xff1a;Instruction Tuning with GPT-4 论文作者&#xff1a;Baolin Peng, Chunyuan Li, Pengcheng He, Michel Galley, Jianfeng Gao 作者单位&#xff1a;Microsoft Research 论文原文&#xff1a;https://arxiv.org/abs/2304.03277 论文出处&#xff1a;– 论文…

海外服务器2核2G/4G/8G和4核8G配置16M公网带宽优惠价格表

腾讯云海外服务器租用优惠价格表&#xff0c;2核2G10M带宽、2核4G12M、2核8G14M、4核8G16M配置可选&#xff0c;可以选择Linux操作系统或Linux系统&#xff0c;相比较Linux服务器价格要更优惠一些&#xff0c;腾讯云服务器网txyfwq.com分享腾讯云国外服务器租用配置报价&#x…