浅谈css布局规则

939 阅读16分钟

浅谈css布局规则

一、布局规则的适用范围

说到规则,我们首先会明确其作用的对象是什么。就好比如说篮球规则适用于篮球比赛,那么css布局规则的适用范围在哪里呢?借此引出了视口的概念。

1.什么是视口

视口 (viewport) 代表当前可见的计算机图形区域。通常与浏览器窗口相同,但不包括浏览器的 UI, 菜单栏等——即指你正在浏览的文档的那一部分。是css布局规则作用的最大范围,也就是说视口是css布局规则下的最大容器。

2.视口的分类

布局视口 (layout viewport) 

innerHeight 和 innerWidth 所组成的区域通常被认为是布局视口 (layout viewport) 。由于布局视口是可缩放,所以其大小也是跟随缩放的比例在变化。也是真正意义上,css作用下的最大容器。

视觉视口 (visual viewport)

而视觉视口是屏幕的可视部分,不包括屏幕键盘,缩放外的区域。视觉视口要么跟布局视口相同,要么更小。

1651764721(1).jpg

1651764801(1).jpg

可视视口

另外,在上面描述的布局视口 (layout viewport)视觉视口 (visual viewport) 不是您将遇到的唯一视口。 在布局视口中完全或部分显示的任何子视口都被视为可视视口

我们通常认为宽度和高度的媒体查询是相对于浏览器窗口的宽度和高度而言的。 它们实际上是相对于视口的。

3.视口的特性

3.1.可缩放

由于视口的可缩放特点,css可以用基于视口大小的长度单位vw、vh,完成文档的自适应布局。 也可通过运用媒体查询的方式完成文档的响应式布局,媒体查询的作用对象也是视口

3.2.存在坐标系

由于存在坐标系的对应关系,所以我们可以计算指定元素的在坐标系的偏移量,通过映射关系映射到其他元素上,以产生视差的效果。

3.2.具有边界

比如我们开发移动端应用时,往往需要考虑屏幕顶部区域的刘海位置、底部区域的操作条位置等因素。

二、布局规则内的元素及其特征

块级元素与内联元素

了解完了布局规则下的最大容器 —— 视口,我们接下来就需要了解容器内可放置的元素特征了。总的来说,可以分为两种元素:块级元素内联元素,还有一种特殊的介于两者之间的元素:内联块级元素

默认的布局规则

正常布局流(即文档流)是一套在浏览器视口内放置、组织元素的系统。默认的,一个块级元素的内容宽度是其父元素的100%,其高度与其内容高度一致,呈垂直方向排布,块中可包含块级元素和内联元素。通过display:block;设置。块级元素具有外边距折叠特性内联元素的height width与内容一致,呈水平方向排布,如果包含块中没有足够的空间容纳所有框,则框可以换行,创建的行称为行框。行框的高度受该行的内联元素的高度影响。通过display:inline;设置。

在 CSS 中,所有的元素都被放置在一个个独立的元素盒子中,理解这些“盒子”的基本原理,是我们使用CSS实现准确布局、处理元素排列的关键。关于盒模型,我们待会再展开讨论。

三、布局规则的基本概念

CSS代表层叠样式表(Cascading Style Sheets) ,理解第一个词cascading很重要— cascade 的表现方式是理解CSS的关键。

1.层叠

Stylesheets cascade(样式表层叠)  — 简单的说,css规则的顺序很重要;当应用两条同级别的规则到一个元素的时候,写在后面的就是实际使用的规则;优先级越高的,就是实际使用的规则。

1.1.资源顺序

如果你有超过一条规则,而且都是相同的权重,那么最后面的规则会应用。可以理解为后面的规则覆盖前面的规则,直到最后一个开始设置样式。

1.2.优先级

    一个选择器的优先级可以说是由四个部分相加 (分量),可以认为是个十百千 — 四位数的四个位数:
  1. 千位: 如果声明在 style 的属性(内联样式)则该位得一分。这样的声明没有选择器,所以它得分总是1000。
  2. 百位: 选择器中包含ID选择器则该位得一分。
  3. 十位: 选择器中包含类选择器、属性选择器或者伪类则该位得一分。
  4. 个位:选择器中包含元素、伪元素选择器则该位得一分。 最后分值越高,优先级越高。

1.3.重要程度

有一个特殊的 CSS 可以用来覆盖所有上面所有优先级计算,不过需要很小心的使用 — !important。用于修改特定属性的值, 能够覆盖普通规则的层叠。如果想要覆盖同被!important声明的css,需要在其未添加!important声明前比其优先级更高的规则上添加!important声明。

2.继承

继承也需要在上下文中去理解 —— 一些设置在父元素上的css属性是可以被子元素继承的,有些则不能。哪些属性属于默认继承很大程度上是由常识决定的。而且可以通过元素属性控制的

  • inherit

    设置该属性会使子元素属性和父元素相同。实际上,就是 "开启继承".

  • initial

    设置属性值和浏览器默认样式相同。如果浏览器默认样式中未设置且该属性是自然继承的,那么会设置为 inherit 。

  • unset

    将属性重置为自然值,也就是如果属性是自然继承那么就是 inherit,否则和 initial一样

3.盒模型

完整的 CSS 盒模型应用于块级盒子,内联盒子只使用盒模型中定义的部分内容。模型定义了盒的每个部分 —— margin, border, padding, and content —— 合在一起就可以创建我们在页面上看到的内容。为了增加一些额外的复杂性,有一个标准的和替代(IE)的盒模型。

CSS中组成一个块级盒子需要:
  • Content box: 这个区域是用来显示内容,大小可以通过设置 width 和 height.
  • Padding box: 包围在内容区域外部的空白区域; 大小通过 padding 相关属性设置。
  • Border box: 边框盒包裹内容和内边距。大小通过 border 相关属性设置。
  • Margin box: 这是最外面的区域,是盒子和其他元素之间的空白区域。大小通过 margin 相关属性设置。

如下图:

1651975063(1).jpg

普通盒模型

在标准模型中,如果你给盒设置 width 和 height,实际设置的是content。padding 和 border 再加上设置的宽高一起决定整个盒子的大小。结果如下图:

1651975371(1).jpg

IE盒模型

盒子的大小还要加上边框和内边距。使用这个模型,所有宽度都是可见宽度,所以内容宽度是该宽度减去边框和填充部分。默认浏览器会使用标准模型。如果需要使用替代模型,您可以通过为其设置 box-sizing: border-box 来实现。普通盒模型与IE盒模型的区别,如下图:

1651975994(1).jpg

ada9ea0ce53ce5defc6e811db8d67ca.png

除此之外,我们通过对盒子display 属性的设置,比如 inline 或者 block ,来控制盒子的外部显示类型。同样盒模型还有内部显示类型,它决定了盒子内部元素是如何布局的。我们可以通过使用类似  flex 的 display 属性值来更改内部显示类型。 如果设置 display: flex,在一个元素上,外部显示类型是 block,但是内部显示类型修改为 flex。据此,我们可以按照盒子的内外部显示类型进行细分类:弹性盒模型和网格盒模型

弹性盒模型

弹性盒子是一种用于按行或按列布局元素的一维布局方法 。元素可以膨胀以填充额外的空间, 收缩以适应更小的空间。

当元素表现为 flex 框时,它们沿着两个轴来布局:

  • 主轴(main axis) 是沿着 flex 元素放置的方向延伸的轴(比如页面上的横向的行、纵向的列)。该轴的开始和结束被称为 main start 和 main end
  • 交叉轴(cross axis) 是垂直于 flex 元素放置方向的轴。该轴的开始和结束被称为 cross start 和 cross end
  • 设置了 display: flex 的父元素被称之为 flex 容器(flex container)。
  • 在 flex 容器中表现为柔性的盒子的元素被称之为 flex 项flex item)。

1.如何设置主轴方向

弹性盒子提供了 flex-direction 这样一个属性,它可以指定主轴的方向(弹性盒子子类放置的地方)— 它默认值是 row

flex-direction: row;   //按主轴方向排列
flex-direction: column;  //按交叉轴方向排列
flex-direction: row-reverse //按主轴方向反向排列
flex-direction: column-reverse //按交叉轴方向反向排列 flex 项目

2.内容换行

当你在布局中使用定宽或者定高的时候,可能会出现问题即处于容器中的 弹性盒子子元素会溢出,破坏了布局。可以启用换行。

flex-wrap: wrap

flex-direction 和 flex-wrap — 的缩写 flex-flow

flex-flow: row wrap;

3.flex项的动态尺寸

flex: 1 200px; //1表示flex项所占父容器的比例,200px表示该flex项的最小值

flex 是一个可以指定最多三个不同值的缩写属性

  • 第一个就是上面所讨论过的无单位比例。可以单独指定全写 flex-grow 属性的值。
  • 第二个无单位比例 — flex-shrink — 一般用于溢出容器的 flex 项。这指定了从每个 flex 项中取出多少溢出量,以阻止它们溢出它们的容器。 这是一个相当高级的弹性盒子功能,我们不会在本文中进一步说明。
  • 第三个是上面讨论的最小值。可以单独指定全写 flex-basis 属性的值。

我们应该尽量使用缩写,以减少代码的冗余。

网格盒模型

CSS网格是一个用于web的二维布局系统。网格是由一系列水平及垂直的线构成的一种布局模式。一个网格通常具有许多的列(column)行(row) ,以及行与行、列与列之间的间隙,这个间隙一般被称为沟槽(gutter)

首先,将容器的display属性设置为grid来定义一个网络。与弹性盒子一样,将父容器改为网格布局后,他的直接子项会变为网格项。

1.定义网格行列属性

grid-template-columns: 100px 100px; //定义两列每列100px的宽度
grid-template-columns: 2fr 1fr 1fr; //定义三列,fr单位表示可以空间的比例
grid-template-rows100px 100px  //定义两行,每行高100px

//重复函数的使用
grid-template-columns: repeat(3, 1fr); //repeat函数的值3,表明了后续列宽的配置要重复的次数
grid-template-columns: repeat(22fr 1fr) // 结果 2fr 1fr 2fr 1fr

2.网格间隙

grid-gap: 20px;

3.显式网格与隐式网格

我们要来理解一下显式网格和隐式网格。显式网格是我们用grid-template-columns 或 grid-template-rows 属性创建的。而隐式网格则是当有内容被放到网格外时才会生成的。显式网格与隐式网格的关系与弹性盒子的main和cross轴的关系有些类似。

简单来说,隐式网格就是为了放显式网格放不下的元素,浏览器根据已经定义的显式网格自动生成的网格部分。

grid-auto-rows: 100px;

//补充:定义最小最大值函数
grid-auto-rows: minmax(100px, auto);

4.自动使用多列填充

某些情况下,我们需要让网格自动创建很多列来填满整个容器。通过设置grid-template-columns属性,我们可以实现这个效果,不过这一次我们会用到repeat函数中的一个关键字auto-fill来替代确定的重复次数。

 grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));

使用auto-fill可以自动创建多列来填满整个容器。

注意:弹性盒子和网格盒子。默认的外部显示类型都是block的前提下产生的

四、布局规则的演变

了解完了布局规则的作用范围、作用对象和一些基本概念。接下来,我们将谈论规则的演变历程,从规则的产生开始,一步步探讨css发展历程,让我们对规则的理解更加具体。

首先我们浏览器最开始的主要功能是提供给计算机用户,浏览一些纯文字文档的便利。于是,我们最开始时,css规则居于需求出发便出现正常文档流的布局规则。

正常文档流

注:同上面第二小节默认规则的描述。此处不再展开。

随着用户的需要,光浏览纯文字文档是不够的,慢慢出现了以图文形式的文档,图片布局的出现,给规则添加了一些新要素。接着定位浮动的规则就会形成。

定位(position)

静态定位static

正常文档流下,默认的定位方式。topbottomleft, 和 right对其不生效

下图表示position:static是文档流默认的定位方式: 1651982361.jpg

相对定位relative

保留原文档流位置,结合topbottomleft, 和 right 来精确指定要将定位元素移动到的位置

下面两张图片便是比较static和relative的区别,static是文档流中默认的定位方式。

1651982161(1).jpg

1651982222(1).jpg

绝对定位absolute

绝对定位的元素不再存在于正常文档布局流中。定位元素应该位于从“包含元素”做锚点,结合topbottomleft, 和 right来精确布局。

哪个元素是绝对定位元素的“包含元素“?这取决于绝对定位元素的父元素的position属性。

通过为包含绝对定位元素的元素设置position: relative;可以定位上下文,指定绝对定位元素的布局起始锚点。

如果所有的父元素都没有显式地定义position属性,那么所有的父元素默认情况下position属性都是static。结果,绝对定位元素会被包含在初始块容器中。这个初始块容器有着和浏览器视口一样的尺寸,并且html元素也被包含在这个容器里面。简单来说,绝对定位元素会被放在html元素的外面,并且根据浏览器视口来定位。

z-index

我们在定位上下文中不止有一个定位的元素时,出现元素层叠时,我们可以使用z-index属性来更改元素堆叠顺序。 默认情况下,定位的元素都具有z-index为auto,实际上为0。

z-index: 1;
z-index: 10; //数值越大,在容器内堆叠顺序越上。
z-index: -1; //数值可以为负数,表示在容器内堆叠越靠下。

下图表示,由于父级元素设置了relative定位,所以绝对定位元素是居于父元素为锚点定位:

1651984282(1).jpg

1651984325(1).jpg

固定定位fixed

这与绝对定位的工作方式完全相同,只有一个主要区别:绝对定位固定元素是相对于html元素或其最近的定位祖先,而固定定位固定元素则是相对于浏览器视口本身。

下图正要表示的是固定定位:

1651984034(1).jpg

粘性定位sticky

还有一个可用的位置值称为 position: sticky,比起其他位置值要新一些。它基本上是相对位置和固定位置的混合体,它允许被定位的元素表现得像相对定位一样,直到它滚动到某个阈值点(例如,从视口顶部起10像素)为止,此后它就变得固定了。

  position: sticky;  //表示元素初始时,按照相对定位布局。当滚动到该元素时,开启固定定位方式布局
  top: 0;
  left: 0;

如下图,设置了sticky定位: 1651985203(1).jpg

1651985319(1).jpg

随着定位的出现和不断丰富,我们使用css布局的手段也会越来越多。不再只限于作用于原本的图文布局

接下来,我们简单描述一下float的概念

浮动(float)

最初,引入float属性是为了能让 web 开发人员实现简单的布局,包括在一列文本中浮动的图像,文字环绕在它的左边或右边。

但 Web 开发人员很快意识到,任何东西都可以浮动,而不仅仅是图像,所以浮动的使用范围扩大了。

float常被应用在图文环绕、首次下沉、设置多列布局上。

在弹性盒子等概念还没出现之前,我们经常使用float的规则进行多列的布局

跨过了图文布局和多列布局的应用,我们出现了关于块格式化上下文的概念。

块格式化上下文(BFC)

块格式化上下文(Block Formatting Context,BFC)  是 Web 页面的可视 CSS 渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。

简单来说,BFC重新格式化了块盒子。BFC内容块有以下特点:

BFC的特性

  • 阻止父元素高度塌陷

    浮动脱离了文档流,如果浮动的元素比原来的父元素高的话,浮动元素会穿出原父元素的边界。而为父元素创建BFC,阻止父元素高度塌陷,BFC刚好能解决这一类问题。

  • 排除外部浮动

    正常文档流中建立的 BFC 不得与外部的任何浮动的外边距重叠。

  • 阻止外边距重叠

    BFC内容块与其他元素之间不会出现外边距重叠。

创建BFC的方式

1651988216(1).jpg

BFC的出现解决了清除浮动、重新格式化上下文等问题,带来了更多关于多栏布局的应用。

弹性布局

同上讨论的弹性盒子,此处不再展开。

网格布局

同上讨论的网格盒子,此处不再展开。

接着随着对多栏布局的需要,css出现关于弹性布局网格布局等等这些规则。为页面布局提供了更丰富多样的手段,在应用上也越来越简便。

以上这些正是css布局规则的发展历程,规则从简单开始,慢慢为了迎合布局的需要,而变得丰富多样。

文章内容引自MDN

developer.mozilla.org/zh-CN/docs/…