深入理解CSS | 青训营

41 阅读17分钟

CSS

CSS (Cascading Style Sheets) 是一种用于描述网页样式和外观的样式表语言。它与HTML结合使用,通过选择器和属性来定义网页元素的样式。

1、CSS的工作原理

  1. 收集和解析CSS:浏览器首先会收集和加载所有的CSS文件,并对其进行解析。它会将CSS代码转换为浏览器能够理解和使用的内部数据结构,这被称为CSS对象模型(CSSOM)。
  2. 匹配元素和样式规则:浏览器根据HTML文档和CSSOM确定哪些元素需要应用CSS样式。对每个元素来说,浏览器会匹配所有与之相关的CSS样式规则。
  3. 计算样式:浏览器根据元素匹配的样式规则和优先级对其样式进行计算。这包括继承的样式、层叠的样式和显式指定的样式。
  4. 构建渲染树:浏览器根据HTML文档的内容和已计算的样式,构建一颗渲染树(Render Tree)。渲染树是由需要显示的元素及其样式组成的树状结构。
  5. 布局:在布局阶段,浏览器确定每个元素在屏幕上的位置和尺寸。这是通过计算元素的盒模型布局属性(宽度、高度、边距等)来实现的。
  6. 绘制:在绘制阶段,浏览器使用渲染树和布局信息将每个元素转换为实际的像素,以在屏幕上呈现。这包括将颜色、文本和图像等内容绘制到屏幕。
  7. 栅格化和合成:在现代浏览器中,栅格化和合成阶段用于优化性能。浏览器将绘制的结果分割成小的图块,并对其进行栅格化和合成,以提高渲染性能和动画流畅度。

2、CSS选择器

常用的CSS选择器:

  1. 元素选择器(Element Selector):通过HTML元素类型来选择元素。例如,p选择所有<p>元素。示例如下:
<p>这是一个段落。</p>
p {
  color: red;
}

/* 上述代码将选择页面中所有 `<p>` 元素,并将它们的文本颜色设置为红色。 */
  1. 类选择器(Class Selector):通过元素的类名选择元素。类名以.开头。例如,.my-class选择所有拥有my-class类的元素。示例如下:
<p class="my-class">类选择器</p>
.my-class {
  color: green;
}

/* 上述代码将选择具有 `my-classt` 类名的所有元素,并将它们的文本颜色设置为绿色。 */
  1. ID选择器(ID Selector):通过元素的ID选择元素。ID以#开头。例如,#my-id选择具有my-id ID的元素。示例如下:
<p id="my-id">ID选择器</p>
.my-id {
  color: blue;
}

/* 上述代码将选择具有 `my-id` ID属性值的元素,并将它们的文本颜色设置为蓝色。 */
  1. 属性选择器(Attribute Selector):根据元素的属性选择元素。例如,[type="text"]选择具有type属性且值为text的元素。示例如下:
<input type="text" name="username">
<input type="text" name="password">
input[type="text"] {
  border: 1px solid black;
}

/* 上述代码将选择具有 `type="text"` 属性的 `<input>` 元素,并给它们添加黑色的边框。 */
  1. 后代选择器(Descendant Selector):选择元素的后代元素。例如,div p选择所有<div>元素内的所有<p>元素。示例如下:
<div>
  <p>这是一个段落。</p>
</div>
div p {
  font-style: italic;
}

/* 上述代码将选择 `<div>` 元素下的所有 `<p>` 元素,并将它们的字体样式设置为斜体。 */
  1. 直接子元素选择器(Child Selector):选择元素的直接子元素。例如,ul > li选择所有直接作为<ul>子元素的<li>元素。示例如下:
<ul>
  <li>项目 1
    <ul>
      <li>分项 1</li>
      <li>分项 2</li>
    </ul>
  </li>
  <li>项目 2</li>
</ul>
ul > li {
  font-weight: bold;
}

/* 上述代码将选择 `<ul>` 元素下的直接子元素 `<li>`,并将它们的字体加粗。 */
  1. 兄弟选择器(Sibling Selector):选择与指定元素具有相同父元素的元素。例如,h1 + p选择紧接在<h1>元素后的<p>元素。示例如下:
<h1>标题 1</h1>
<p>段落 1</p>
<p>段落 2</p>
<h1>标题 2</h1>
<p>段落 3</p>
h1 + p {
  color: blue;
}

/* 上述示例中,选择器 `h1 + p` 选择紧接在 `<h1>` 元素后面的 `<p>` 元素,并将其文本颜色设置为蓝色。因此,“段落 1” 的文本颜色将被设置为蓝色。 */
  1. 伪类选择器(Pseudo-class Selector):选择元素的特殊状态或位置。例如,a:hover选择鼠标悬停在<a>链接上的元素。示例如下:
<a href="#">点击</a>
a:hover {
  color: red;
}

/* 上述代码将选择鼠标悬停在 `<a>` 元素上时的状态,并将文本颜色设置为红色。 */
  1. 伪元素选择器(Pseudo-element Selector):选择元素的特殊部分。例如,p::first-line选择<p>元素的第一行。示例如下:
<p>这是一个段落。</p>
p::before {
  content: "Before ";
  font-weight: bold;
}

/* 在上述示例中,伪元素选择器 `p::before` 会在 `<p>` 元素内容之前插入文字 "Before ",并将其文本设置为加粗。因此,显示的文本将变成 “Before This is a paragraph.”。 */

2、选择器优先级

  • CSS选择器的优先级是用于确定哪些样式规则将应用于一个元素。当多个选择器都匹配同一个元素时,优先级决定了哪个规则的样式将被应用。

    CSS选择器的优先级从高到低,可以按照以下规则进行确定:

    1. 内联样式:使用HTML元素的style属性设置的样式具有最高的优先级。
    2. ID选择器:通过元素的id属性进行选择的样式具有较高的优先级。
    3. 类选择器、属性选择器和伪类选择器:这些选择器通过元素的类、属性或伪类进行选择,并具有较低的优先级。
    4. 元素选择器和伪元素选择器:这些选择器通过元素的标签名或伪元素进行选择,并具有最低的优先级。
  • CSS选择器的特异度(specificity)用于确定选择器的优先级。特异度是一个权重值,用于判断当多个选择器同时适用于一个元素时,哪个选择器的样式规则将被应用。

    CSS选择器的特异度可以按照以下规则进行计算:

    1. 内联样式拥有最高的特异度,特异度值为1,0,0。
    2. 对于每个ID选择器,特异度值增加0,1,0。
    3. 对于每个类选择器、属性选择器或伪类选择器,特异度值每个增加0,0,1。
    4. 对于每个元素选择器或伪元素选择器,特异度值每个增加0,0,0,1。

    特异度值是按顺序排列的,例如0,1,0表示有一个ID选择器,没有类选择器、属性选择器和伪类选择器,也没有元素选择器和伪元素选择器。

    在比较特异度时,按照从左到右的顺序进行比较,较大的特异度值具有更高的优先级。如果特异度值在某个位置相同,则比较下一个位置的值。

3、CSS选择器的继承

CSS选择器的继承是一种机制,用于确定在父元素中定义的样式是否应该应用于其子元素。

在CSS中,一些属性可以通过继承被子元素继承并应用。这意味着如果父元素定义了某些属性的样式规则,这些属性的样式规则将自动应用于其子元素,除非子元素显式地定义了相同属性的样式。

以下是一些常见的CSS属性可以继承的例子:

  1. 字体相关属性:例如font-family、font-size、font-weight等属性可以继承给子元素。
  2. 文本相关属性:例如color、text-align、line-height等属性可以继承给子元素。
  3. 链接相关属性:例如a标签的颜色和文本装饰(text-decoration)属性可以继承给其子元素。

示例如下:

<style>
  .parent {
    font-family: Arial, sans-serif;
    color: red;
  }
</style>

<div class="parent">
  <p>这是一个段落</p>
  <a href="#">这是一个链接</a>
</div>

在上面的例子中,p元素和a元素都将继承父元素的字体样式和颜色样式,因为这些属性是可以继承的。但是,需要注意的是,如果子元素定义了自己的样式规则,父元素的继承样式可能会被子元素的样式覆盖。

需要注意的是,并非所有的CSS属性都可以继承。像background、border、margin等属性大部分不会被子元素继承。此外,继承的行为也可以通过CSS的inherit关键字进行控制。

CSS选择器的显式继承

在CSS中,可以使用inherit关键字来让子元素显式继承父元素的样式。这意味着子元素将直接应用父元素的相应属性值,而不考虑其他样式规则的影响。

示例如下:

<style>
  .parent {
    font-family: Arial, sans-serif;
    color: red;
  }
  
  .child {
    font-family: inherit;
    color: inherit;
  }
</style>

<div class="parent">
  <p class="child">This is some text.</p>
</div>

在上面的示例中,.parent类定义了字体样式和颜色样式,并在子元素的.child类中使用inherit关键字明确指定了这些属性的继承。因此,.child元素将继承.parent元素的字体和颜色样式,所以文本将使用Arial字体并显示为红色。

4、CSS的求值过程

CSS的求值过程是指浏览器在解析和应用CSS样式规则时的步骤和顺序。

下面是CSS的求值过程的一般步骤:

  1. 收集CSS样式规则:浏览器首先收集和加载所有的CSS文件,包括外部CSS文件和内部样式。这些样式规则会被解析并保存供后续的应用。
  2. 构建CSS对象模型(CSSOM):浏览器根据收集到的样式规则构建CSS对象模型。CSSOM是一种将CSS样式规则表示为树结构的模型,它描述了HTML文档中每个元素的样式信息。
  3. 匹配选择器:当浏览器解析HTML文档时,它会匹配CSS样式规则中的选择器与文档中的元素进行匹配。只有匹配成功的元素才会应用对应的样式规则。
  4. 计算特异度:对于匹配的样式规则,浏览器会根据选择器的特异度(specificity)确定优先级顺序。选择器的特异度是由其各个组成部分的权重值所组成,较高特异度的规则将覆盖较低特异度的规则。
  5. 解决样式冲突:如果多个样式规则具有相同的特异度,或者具有!important标志,浏览器会解决样式冲突,通常取最后定义的样式规则。
  6. 应用样式规则:根据特异度和解决样式冲突的结果,浏览器将计算出每个元素应用的最终样式,并将其应用于文档中的相应元素。
  7. 处理继承:如果某个样式属性被定义为可继承的,并且父元素具有该属性的样式规则,浏览器会将该样式属性继承给子元素。
  8. 对页面进行渲染:浏览器根据计算得到的最终样式对页面进行渲染,将元素的尺寸、位置、颜色等信息应用到页面布局中。

5、布局

在网页开发中,CSS(层叠样式表)是常用的布局技术之一。使用CSS可以通过设置元素的位置、宽度、高度、浮动、定位等属性来实现布局。CSS提供了多种布局方法,如流动布局、网格布局和弹性布局等等。

CSS布局相关技术:

  1. 流式布局(Flow Layout):流动布局是默认的布局方式,元素按照其在文档流中的顺序从上到下、从左到右进行排列。可以使用CSS的盒模型、浮动和清除浮动等属性来控制元素在流动布局中的位置和大小。

    在CSS中,实现流式布局通常涉及以下几个方面:

    • 百分比设置元素尺寸:通过设置元素的宽度和高度为百分比值,相对于其父容器的尺寸来定义元素的大小。例如:
    .container {
      width: 100%; /* 宽度占据父容器的100% */
    }
    
    .box {
      width: 50%; /* 宽度占据父容器宽度的50% */
      height: 300px;
    }
    
    • 相对定位和浮动:使用相对定位(relative positioning)和浮动(float)来调整元素的位置,使得元素在不同屏幕尺寸下能够适应布局变化。
    .box {
      width: 50%;
      height: 300px;
      float: left; /* 元素向左浮动,使其在同一行显示 */
    }
    
    • 媒体查询(Media Queries):通过使用媒体查询,可以根据不同的屏幕尺寸应用不同的CSS规则,从而在不同的设备上提供不同的布局样式。这样,可以根据屏幕宽度来调整页面的布局。
    /* 媒体查询:当屏幕宽度小于768px时,应用以下CSS规则 */
    @media screen and (max-width: 768px) {
      .box {
        width: 100%; /* 宽度占据父容器的100% */
        float: none; /* 取消浮动,使其垂直排列 */
      }
    }
    
  2. 弹性布局(Flexbox):是一种CSS布局技术,也称为Flexbox布局,通过使用display: flex将父元素设置为弹性容器,子元素可以在主轴和交叉轴上进行自适应的布局。弹性布局使得元素的对齐、间距和尺寸调整变得简单。

    Flexbox布局涉及到两个主要概念:Flex容器(Flex Container)和Flex项目(Flex Items)。、

    1. Flex容器:将一组元素包裹在一个容器中,并通过设置容器的CSS属性来启用Flexbox布局。容器的属性定义了子元素在主轴(main axis)和交叉轴(cross axis)上的排列方式。
    .container {
      display: flex; /* 声明容器使用Flex布局 */
      flex-direction: row; /* 子元素水平排列,默认值为row */
      justify-content: space-between; /* 子元素在主轴上等间距分布 */
      align-items: center; /* 子元素在交叉轴上居中对齐 */
    }
    
    1. Flex项目:Flex容器内的每个子元素称为Flex项目。这些项目根据容器的设置自动调整其尺寸和位置。
    .item { 
        flex: 1; /* 定义子元素的伸缩比例,决定子元素在可用空间内占据的比例 */ 
        margin: 10px; /* 子元素之间的外边距 */ 
    }
    

    Flexbox布局的主要特点包括:

    • 自适应伸缩:Flex项目可以根据容器的可用空间自动伸缩调整,使得子元素在不同屏幕尺寸下能够灵活适应。
    • 灵活的排列:可以在主轴和交叉轴上定义不同的对齐方式和间距,以实现各种布局要求。
    • 一维布局:Flexbox是一种一维布局模型,适用于行或列的排列,适用于导航菜单、页眉、页脚等布局。
    • 适应性:灵活适应不同设备和屏幕大小,支持响应式设计。
  3. 网格布局(Grid Layout):网格布局是一种二维的布局系统,将页面划分为行和列的网格,通过在父元素上设置display: grid来创建一个网格布局。可以使用网格线和网格单元格来控制元素在网格布局中的位置和大小。

    在网格布局中,页面被分成行(rows)和列(columns)。网格布局的主要概念包括:

    1. 网格容器(Grid Container):包含网格项目的父元素,通过设置父元素的CSS属性来启用网格布局。
    .container {
      display: grid; /* 声明容器使用网格布局 */
      grid-template-columns: 1fr 1fr 1fr; /* 定义3列,每列的宽度相等 */
      grid-template-rows: 100px 200px; /* 定义2行,每行的高度分别为100px和200px */
      grid-gap: 10px; /* 设置网格项之间的间距 */
    }
    
    1. 网格项目(Grid Items):网格容器的直接子元素,它们将被放置在网格中,并根据网格容器的设置进行排列。
    .item {
      grid-column: 1 / 4; /* 定义项目跨越3列 */
      grid-row: 1 / 2; /* 定义项目跨越1行 */
    }
    

    网格布局的主要特点包括:

    • 多维布局:与Flexbox不同,网格布局是一种二维布局模型,可以同时定义行和列,适用于复杂的布局要求。
    • 灵活控制:可以通过设置网格容器的属性,控制网格项的位置、尺寸和间距。
    • 自适应性:灵活适应不同设备和屏幕大小,支持响应式设计。
    • 网格线和网格轨道:网格线是用来定义网格的分隔线,而网格轨道则是相邻网格线之间的空间。
  4. 定位布局(Positioning):定位布局通过使用position属性来控制元素在文档流中的定位。常见的定位值包括static(默认)、relativeabsolutefixed。通过使用这些定位值,可以精确地定位和叠加元素。

    CSS中的定位属性有三种主要值:

    1. position: static;(默认值):元素遵循常规的文档流布局,不受top、bottom、left和right等属性的影响。
    2. position: relative;:元素相对于其正常位置进行偏移,但仍然占据原有空间。通过设置top、bottom、left和right属性,可以控制元素在当前位置的偏移量。
    .relative-box {
      position: relative;
      top: 20px;
      left: 30px;
    }
    
    1. position: absolute;:元素相对于最近的非static定位的祖先元素(或根据浏览器窗口定位,如果没有非static定位的祖先元素)进行定位。通过设置top、bottom、left和right属性,可以将元素放置在指定的位置上。
    .absolute-box {
      position: absolute;
      top: 50px;
      right: 20px;
    }
    

    在使用定位布局时,需要注意:

    • 使用position: relative;来进行微调或相对定位,使元素在正常文档流中的位置进行微调。
    • 使用position: absolute;来实现元素的精确定位,使元素相对于容器或页面进行定位。
    • 使用z-index属性来控制元素的堆叠顺序,确保元素按照所需的层级关系进行叠放。
    • 定位布局可能会导致元素的重叠或覆盖,需要注意避免视觉上的混乱。

CSS的盒模型:

CSS的盒模型描述了在网页布局中每个HTML元素如何被视为一个矩形盒子,该盒子由四个关键部分组成: 内容区域(content area)、内边距(padding)、边框(border)和外边距(margin)。

示例代码

.box {
  width: 200px; /* 盒子的宽度 */
  height: 100px; /* 盒子的高度 */
  padding: 20px; /* 内边距 */
  border: 1px solid black; /* 边框 */
  margin: 10px; /* 外边距 */
}

在上述代码中,我们定义了一个类名为 .box 的元素,并将这些属性应用于该类。这些属性的作用:

  1. width 和 height:用于设置盒子的宽度和高度。这指定了盒子内容区域的尺寸。
  2. padding:用于设置盒子的内边距。内边距是位于内容区域和边框之间的空间,可以设置为一个数值,或者使用简写形式表示四个方向的数值(如 padding: 10px; 或者 padding: 10px 20px 10px 20px;)。
  3. border:用于设置盒子的边框样式、宽度和颜色。边框将内边距和内容区域与外边距分开。
  4. margin:用于设置盒子的外边距。外边距是盒子和相邻元素之间的空间,可以设置为一个数值,或者使用简写形式表示四个方向的数值(如 margin: 10px; 或者 margin: 10px 20px 10px 20px;)。

在计算元素的宽度和高度时,应该考虑到盒模型的所有部分。例如,如果给定的 .box 元素具有宽度为200px,那么实际渲染的盒子宽度将是 200px + 2 * 20px + 2 * 1px + 2 * 10px,即内边距、边框和外边距的总和。

本篇笔记为个人总结,学习交流使用,欢迎各位大佬评价指正,非常感谢!