CSS之contain,一个连fixed定位都要看它眼色的限制属性

CSS的布局有太多种方式,元素的表现也有很多的形式。

像我们熟悉的那些:行内元素、块元素、列表元素、表格元素、绝对定位、固定定位、浮动、弹性布局、网格布局等等等等。

一个元素的具体渲染可能会受到父子元素、兄弟元素的影响。

大多数情况我们都可以通过一些手段,来解决我们遇到的布局或表现问题。

比如给一个元素赋予了浮动,那么可以通过清除浮动来消除影响,再比如通过绝对定位来调整元素的位置,也可以通过padding或margin等避免其他元素被覆盖。

但是也有那么一些情况,我们不太好处理,比如某一个元素希望相对于它的父级区域做固定定位,而不是基于整个页面,能做到吗?再比如给定一个盒容器,无论子元素怎么排序布局或者浮动,也不会影响其他相邻盒子的渲染,该怎么做到?

其实不止这些,还有很多的实际场景让我们很棘手,你是否在设计和实现方面做过平衡和妥协?

对于现在的浏览器来说,所支持的CSS功能不允许我们说:我不行,我做不到。

别的不说,今天要讲的contain就能用来解决上面的问题,它能做的事情还有很多,基于自身天然的属性,甚至能轻松提升你的性能!

contain概述

contain表明该元素要独立于页面中的其他元素,该元素中的所有内容都被局限在一个独立的区域,跟其他元素隔离开来,从而使得基于该元素的所有计算都是独立的,被限制在该DOM子树中,而不是整个页面。这样能够让页面的性能提升。

该元素构成的容器,可以控制其产生的尺寸范围、样式作用域、布局方式、绘制区域。会生成新的包含区块、新的层叠上下文、新的区块格式化上下文。这些控制手段都对应着不同的局限属性,在容器内对局限属性的修改,不会影响容器外的部分,也就不会使得页面经常重新渲染,尤其在动态修改页面元素时会带来更好的性能受益。

我们理解它的时候,不要把它想成是包含的意思,理解成它的作用,是对包含内容的一个局限,之后也会多次用到"局限"这个词。

分类

一、关键词

通过关键词,可以指定不同的局限属性,从而产生不同的局限效果。

  1. none:不应用任何局限。
  2. size:元素的尺寸无视子元素而单独计算,在行向和块向上都应用该局限。
  3. inline-size:元素的尺寸无视子元素而单独计算,只在行向上应用该局限。
  4. layout:使得该元素的布局与元素外的任何内容相互独立,互不影响。即该元素所构成的容器从页面中隔离出来,单独计算布局。
  5. style:对于容器内的某些可能影响外部属性的值,被限制在容器内,不参与整体的计算,比如计数器和引号不会参与之前或者之后的计算,会有独立的计算,对于外面来说就好像这个元素没存在过一样,或者说不知道有它的存在。
  6. paint:限制该元素的绘制区域范围,子元素的渲染永远不会出现在容器外,容器的边界限定了子元素的可见内容。例如容器在屏幕外,那么就永远不用绘制,因为其子元素也肯定在屏幕外,不像margin负值放在屏幕外那样,子元素可能延伸到屏幕内。
  7. content:相当于设置了layout、paint、style,也就是除了size之外的所有值。
  8. strict:给该元素应用所有局限规则,相当于设置size、layout、paint、style。

二、组合值

也就是上面2-6关键字的任意组合,跟顺序无关,多个值之间用空格分隔开。跟个数也无关,可以设置任意的数量。不过要注意,size和inline-size同时只能设置一个,因为它俩是冲突的。

三、全局值

全局值的作用,可以参考我在font-size那篇文章中的解释说明,它们的作用机制和原理都是一样的,这里不在重复赘述。

示例

我们来对上面所说的内容,做一些示例,来看看它们的实际工作方式。

先构建一个基本的代码,之后都以这个为基础改造和演示:

<div style="background-color: bisque;">
  我是父元素
  <div style="background-color: coral;">
    我是子元素
  </div>
</div>
<div style="background-color: lightpink;">
  我是父兄弟元素
</div>

看下现在的效果:

效果

记住这个效果,因为我们接下来就要改变contain属性,观察它所发生的变化。

  1. 通过尺寸来控制
<div style="contain: size;background-color: bisque;">
  我是父元素
  <div style="background-color: coral;">
    我是子元素
  </div>
</div>
<div style="background-color: lightpink;">
  我是父兄弟元素
</div>

给父元素加上contain:size样式:

效果

可以看到,"我是父元素"和"我是父兄弟元素"重合了,也就说,父兄弟元素的渲染,直接从父元素渲染开始的位置开始渲染的。就好像父元素不存在一样。

这里面的奥妙通过控制台看一下,其实就很容易解开了:

效果

就是因为父元素的高度为0了。在解释之前先说明一下,行向指的是我们书写的方向,就是指的从左往右,你就可以理解成是多个行内元素排列的方向,一直往后面追加的方向。块向指的是我们折行的方向,也就是指的从上往下,你就可以理解成是多个块级元素排列的方向,一直往下追加的方向。

理解了这两个之后,我们就知道,由于size影响着这两个方向上的局限,它会变得无视子元素。因为如果没有主动设置尺寸的话,就好像子元素不存在一样,那么它就没有高度,所以兄弟元素就自然而然的顶上来了。

这时,我们改一下设置,让它只在行向上有局限:

<div style="contain: inline-size;background-color: bisque;">
  我是父元素
  <div style="background-color: coral;">
    我是子元素
  </div>
</div>
<div style="background-color: lightpink;">
  我是父兄弟元素
</div>

通过设置contain:inline-size:

效果

可以看到,效果又回来了,这是因为我们没有在块向上做局限,因此高度会自然撑开。

既然说到了这里,我们再看一下,它是如何在行向上进行局限的,构造如下代码:

<div style="contain: inline-size;display: inline-block;background-color: bisque;">
  我是父元素
  <div style="background-color: coral;">
    我是子元素
  </div>
</div>
<div style="background-color: lightpink;">
  我是父兄弟元素
</div>

设置父元素为行内块,增加display:inline-block:

效果

瞬间又变成了这样,这同样是因为,行内局限使得父元素独立计算尺寸,而我们又没手动指定,因此它的宽度为0,子元素也跟着宽度为0,所以就变成了一个字一换行。

这时即使你给子元素加上宽度,在行向上父元素也会无视你:

效果

你看我们给子元素加上100px的宽度,但是鼠标查看父元素,依然是宽度为0。

  1. 通过布局来控制

指定contain:layout,可以让该元素独立计算它的内部布局,不受外界影响,我们先将子元素设定一个固定定位:

<div style="background-color: bisque;">
  我是父元素
  <div style="position: fixed;top: 10px;background-color: coral;">
    我是子元素
  </div>
</div>
<div style="background-color: lightpink;">
  我是父兄弟元素
</div>

看下现在的效果:

效果

完全没毛病,子元素固定到页面顶部的10px位置。

现在应用一下我们的布局限制:

<div style="contain: layout;background-color: bisque;">
  我是父元素
  <div style="position: fixed;top: 10px;background-color: coral;">
    我是子元素
  </div>
</div>
<div style="background-color: lightpink;">
  我是父兄弟元素
</div>

再看下显示的效果:

效果

咦?明明是固定定位,它的位置却是相对于父元素的。这就是布局限制的作用,相当于父元素告诉页面,从现在开始,这片的布局归我管,所有的行为都向我请示,由我指挥。

同样,其他的position值,也都是基于父元素的布局限制来渲染的,这里就不做一一演示了。

其实,不光是position,只要是关于布局的,都会在此局限下生效,这里再演示一个浮动的例子:

<div style="height: 80px;padding: 5px;background-color: bisque;">
  <h2 style="margin-bottom: 7px;">我是父元素</h2>
  <p style="float: left;background-color: coral;">
    我是子元素
  </p>
</div>
<div style="height: 80px;padding: 5px;background-color: lightpink;">
  <h2>我是父兄弟元素</h2>
  <p style="background-color: coral;">
    我是父兄弟子元素
  </p>
</div>

两个父元素各包含两个子元素,其中第一个父元素的第二个子元素设置为左浮动,为了更好的演示,我把子元素改成了h2和p标签,看下现在的效果:

效果

父元素的两个子元素正常显示,但是父兄弟元素的第一个子元素里面的文字,被挤的偏移了,这是由于父元素的第二个子元素设置浮动引起的,通过控制台看下就明白了:

效果

红线是我标出来的,可以看到,父兄弟元素的h2和父元素的浮动有一丁点的重合,导致文字被推开,这就是浮动产生的影响。

我们通过布局局限,来控制浮动只发生在局限内,稍微改下代码:

<div style="contain: layout;height: 80px;padding: 5px;background-color: bisque;">
  <h2 style="margin-bottom: 7px;">我是父元素</h2>
  <p style="float: left;background-color: coral;">
    我是子元素
  </p>
</div>
<div style="height: 80px;padding: 5px;background-color: lightpink;">
  <h2>我是父兄弟元素</h2>
  <p style="background-color: coral;">
    我是父兄弟子元素
  </p>
</div>

给父元素添加了contain:layout,这是浮动就不会影响后面的布局了:

效果

通过布局局限,我们可以把所有的关于布局的影响,都控制在容器内,这样即使容器内布局发生了改变,也完全不会影响页面其他内容,在动态页面中,如果需要频繁的修改某些元素,通过这种方式管理和设计页面,就能很有效的改善渲染的性能。

  1. 通过样式来控制

这里的样式主要是针对计数器和引号的作用域,能控制它们只在所局限的范围内单独计算,而不会影响全局的结果,就好像它们是单独拿出来作为一个独立的文档一样,看个例子:

body {
  counter-reset: my-list;
}
div > div::before {
  counter-increment: my-list;
  content: "(" counter(my-list) "):";
}
<div>
  <div>第1行</div>
  <div>第2行</div>
  <div>第3行</div>
  <div>第4行</div>
  <div>第5行</div>
  <div>第6行</div>
</div>

我们设计这样一个列表,通过自定义的计数器,设置一个前缀的显示:

效果

如果我们希望第三行独立出来,进行样式局限,不参与外部计数:

<div>
  <div>第1行</div>
  <div>第2行</div>
  <div style="contain: style;">第3行</div>
  <div>第4行</div>
  <div>第5行</div>
  <div>第6行</div>
</div>

那么它就会展现成这个样子:

效果

注意第三行的计数,已经重置为1,并且第四行从3开始,接着第二行的值继续计数。

  1. 通过绘制来控制

这个也比较厉害,就是父元素啥样就是啥样,子元素永远不会在容器外渲染:

<div style="background-color: bisque;width: 100px;height: 100px;">
  <div>
  海客谈瀛洲,烟涛微茫信难求。
  越人语天姥,云霞明灭或可睹。
  天姥连天向天横,势拔五岳掩赤城。
    </div>
</div>

有这样一个代码块,容器的宽高为100px,内容有超出部分:

效果

我们可以通过绘制局限来使容器外的内容不显示:

<div style="contain: style;background-color: bisque;width: 100px;height: 100px;">
  <div>
  海客谈瀛洲,烟涛微茫信难求。
  越人语天姥,云霞明灭或可睹。
  天姥连天向天横,势拔五岳掩赤城。
  </div>
</div>

添加contain:paint,只让绘制区域被限制在容器内部:

效果

这个跟overflow:hidden有一点区别,就是绘制局限真的就是正常绘制,只不过不绘制容器外的部分,而hidden虽然隐藏,但是依然能通过js进行滚动。

  1. 通过组合值来控制

我们也可以通过任意的值的组合来控制所需要的局限,也可以通过strict或content关键字来快速的做到这一点。这里就不再重复演示了

最后

合理的使用contain,不但能快速实现我们的需求,也能减少我们的修改量,而且会降低不理解现象的情况的出现频率,更能提升页面的性能。

尤其是布局局限,提供给了我们更多的发挥空间,而且任意的复制到其他地方,也不会对外部元素有影响。

每天一点小知识,希望能够帮助到你。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,让我来尝试回答你的问题。首先,我是ChitGPT,一个由CSDN开发的AI,很高兴为你提供帮助。关于你的问题,我可以向你介绍如何使用CSS盒子模型的相关属性、背景属性以及渐变属性制作一个播放器图标。 首先,我们可以利用CSS盒子模型的相关属性来定义播放器图标的尺寸、边框及内边距。比如: ``` .play-icon { width: 50px; height: 50px; padding: 10px; border: 2px solid black; box-sizing: border-box; } ``` 上述代码中,我们创建了一个类名为play-icon的样式规则,将其应用于一个元素上,设置了其宽度和高度都为50px,内边距为10px,边框为2px宽的黑色实线,同时通过box-sizing属性将内边距和边框包含在元素尺寸内。这样就能够创建一个宽高为50px的盒子,并设置边框和内边距。 接下来,我们可以使用CSS背景属性来为播放器图标添加图像或颜色背景。例如: ``` .play-icon { background: url('play-icon.png') no-repeat center center / contain; } ``` 上述代码中,我们设置了播放器图标的背景图片为play-icon.png,并设置了背景图片的位置为居中,同时通过contain值将背景图片缩放至适应元素大小的最大值。如果没有指定背景图片,也可以直接设置颜色背景,如下所示: ``` .play-icon { background-color: red; } ``` 这样就可以为播放器图标添加一个红色的背景色。 最后,我们可以使用CSS渐变属性来为播放器图标添加渐变效果。例如: ``` .play-icon { background: linear-gradient(to bottom, red, blue); } ``` 上述代码中,我们设置了播放器图标的背景为从上到下的线性渐变,颜色由红色到蓝色渐变。如果需要更复杂的渐变效果,可以使用其他渐变属性进行设置。 综上所述,以上就是利用CSS盒子模型的相关属性、背景属性以及渐变属性制作播放器图标的方法。希望能够对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值