理解CSS(下)| 青训营笔记

167 阅读11分钟

三、层叠上下文(The Stacking Context)

理解

image.png

有哪些方式形成新的层叠上下文:

image.png

层叠顺序不仅指不同的层叠上下文的顺序,同一个层叠上下文内,元素间也有顺序:

在同一个层叠上下文中,元素之间的层叠顺序是按照以下规则确定的

  1. 背景和边框:层叠上下文元素的背景和边框位于最底层。
  2. 负 z-index:拥有负 z-index 值的子元素按照 z-index 从小到大的顺序绘制。数值小的元素会被数值大的元素覆盖。
  3. 块级元素:按照 HTML 代码中的顺序绘制非定位的块级元素。位于后面的元素将覆盖位于前面的元素。
  4. 浮动元素:按照 HTML 代码中的顺序绘制浮动元素。位于后面的元素将覆盖位于前面的元素。
  5. 内联元素:按照 HTML 代码中的顺序绘制非定位的内联元素。位于后面的元素将覆盖位于前面的元素。
  6. z-index 为 0 或 auto 的定位元素:按照 HTML 代码中的顺序绘制 z-index 为 0 或 auto 的定位元素。位于后面的元素将覆盖位于前面的元素。
  7. 正 z-index:拥有正 z-index 值的子元素按照 z-index 从小到大的顺序绘制。数值小的元素会被数值大的元素覆盖。 在同一个层叠上下文中,元素之间的层叠顺序受多种因素影响,包括元素的类型(如块级、内联、浮动或定位元素)、z-index 值以及在 HTML 代码中的顺序。

image.png

案例

image.png

image.png

编写z-index的建议:

  1. 使用css 变量或者预处理语言的变量,管理z-index的值
  2. 将预设间隔设置10或100,方便后续的插入

image.png

四、变形、过渡、动画

transform 变形 3D

CSS transform 属性允许我们对元素进行 2D 或 3D 变换。这里我们主要讨论一下 3D 变换相关的属性。

  1. transform:这是一个复合属性,可以包含一个或多个 3D 变换函数。以下是一些常用的 3D 变换函数: - rotateX(angle):绕 X 轴旋转指定的角度。 - rotateY(angle):绕 Y 轴旋转指定的角度。 - rotateZ(angle):绕 Z 轴旋转指定的角度。 - scale3d(sx, sy, sz):分别沿 X、Y 和 Z 轴缩放元素。 - translate3d(tx, ty, tz):分别沿 X、Y 和 Z 轴移动元素。 - perspective(p):设置透视距离。较小的值会增强 3D 效果。
  2. transform-origin:定义变换的基点,即元素进行变换时以哪个点为中心。默认值为 "50% 50% 0",即元素的中心点。
  3. transform-style:设置元素的子元素是否位于 3D 空间中。取值为 flat(默认)或 preserve-3d。当设置为 preserve-3d 时,子元素将保留其 3D 位置。
  4. perspective:定义观察者距离元素的距离,对于创建 3D 效果非常有用。较小的值会增强 3D 效果。此属性通常应用于父元素上。
  5. perspective-origin:定义透视投影点的位置。默认值为 "50% 50%",即元素的中心点。

image.png

字节官方提供的案例:3D Dice (codepen.io)

image.png

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D 骰子案例</title>
  <style>
      /* 设置骰子的基本样式 */
      .dice {
          width: 100px; /* 骰子的宽度 */
          height: 100px; /* 骰子的高度 */
          position: relative; /* 使用相对定位,使子元素可以相对于此元素进行定位 */
          perspective: 800px; /* 设置 3D 视图距离,让骰子看起来有透视效果 */
          margin: 200px; /* 设置外边距,将骰子放置在页面中间 */
      }

      /* 设置骰子容器的样式,用于包含 6 个骰子面 */
      .dice-container {
          width: 100%; /* 容器宽度设置为 100%,使其和父元素(骰子)一样宽 */
          height: 100%; /* 容器高度设置为 100%,使其和父元素(骰子)一样高 */
          position: absolute; /* 使用绝对定位,使容器相对于骰子定位 */
          animation: rotate 20s linear infinite; /* 应用旋转动画,持续时间为 20 秒,线性速度,无限循环 */
          transform-style: preserve-3d; /* 保留 3D 转换,使子元素的 3D 转换相对于容器生效 */
      }

      /* 定义旋转动画关键帧 */
      @keyframes rotate {
          0% { transform: rotateX(0deg) rotateY(0deg); } /* 初始状态:无旋转 */
          100% { transform: rotateX(3600deg) rotateY(7200deg); } /* 结束状态:绕 X 轴旋转 3600 度,绕 Y 轴旋转 7200 度 */
      }

      /* 设置每个骰子面的基本样式 */
      .face {
          width: 100%; /* 面的宽度设置为 100%,使其和父元素(容器)一样宽 */
          height: 100%; /* 面的高度设置为 100%,使其和父元素(容器)一样高 */
          position: absolute; /* 使用绝对定位,使骰子面相对于容器定位 */
          display: flex; /* 使用 flex 布局,使骰子点居中显示 */
          justify-content: center; /* 水平居中对齐 */
          align-items: center; /* 垂直居中对齐 */
          background-color: #eee; /* 骰子面的背景颜色 */
          border: 1px solid #ccc; /* 骰子面的边框 */
          backface-visibility: hidden; /* 隐藏背面,使骰子在旋转时不显示背面 */
      }

      /* 设置骰子点的基本样式 */
      .dot {
          width: 20px; /* 骰子点的宽度 */
          height: 20px;
          /* 骰子点的高度 */
          background-color: black; /* 骰子点的背景颜色 */
          border-radius: 50%; /* 骰子点的圆角,设置为 50% 使其呈现为圆形 */
      }

      .face-1 {
          transform: rotateY(0deg) translateZ(50px);
      }

      .face-2 {
          transform: rotateY(90deg) translateZ(50px);
      }

      .face-3 {
          transform: rotateY(180deg) translateZ(50px);
      }

      .face-4 {
          transform: rotateY(270deg) translateZ(50px);
      }

      .face-5 {
          transform: rotateX(90deg) translateZ(50px);
      }

      .face-6 {
          transform: rotateX(-90deg) translateZ(50px);
      }
  </style>
</head>
<body>
<div class="dice">
  <div class="dice-container">
    <div class="face face-1">
      <div class="dot" style="background-color: red"></div>
    </div>
    <div class="face face-2">
      <div class="dot" style="position:absolute; top: 10px; left: 10px;"></div>
      <div class="dot" style="position:absolute; bottom: 10px; right: 10px;"></div>
    </div>
    <div class="face face-3">
      <div class="dot"></div>
      <div class="dot" style="position:absolute; top: 10px; left: 10px;"></div>
      <div class="dot" style="position:absolute; bottom: 10px; right: 10px;"></div>
    </div>
    <div class="face face-4">
      <div class="dot" style="position:absolute; top: 10px; left: 10px;"></div>
      <div class="dot" style="position:absolute; top: 10px; right: 10px;"></div>
      <div class="dot" style="position:absolute; bottom: 10px; left: 10px;"></div>
      <div class="dot" style="position:absolute; bottom: 10px; right: 10px;"></div>
    </div>
    <div class="face face-5">
      <div class="dot"></div>
      <div class="dot" style="position:absolute; top: 10px; left: 10px;"></div>
      <div class="dot" style="position:absolute; top: 10px; right: 10px;"></div>
      <div class="dot" style="position:absolute; bottom: 10px; left: 10px;"></div>
      <div class="dot" style="position:absolute; bottom: 10px; right: 10px;"></div>
    </div>
    <div class="face face-6">
      <div class="dot" style="position:absolute; top: 10px; left: 10px;"></div>
      <div class="dot" style="position:absolute; top: 10px; right: 10px;"></div>
      <div class="dot" style="position:absolute; bottom: 10px; left: 10px;"></div>
      <div class="dot" style="position:absolute; bottom: 10px; right: 10px;"></div>
      <div class="dot" style="position:absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);"></div>
    </div>
  </div>
</div>
</body>
</html>

transition过渡

通过指定某些元素属性从一种起始状态,在一段时间内以某种变化节奏,过渡到终止状态。

```
div {
  transition:<property> <duration> <timing-function> <delay>
}
```

其中timing-function一般有三种用法:线性((linear)、贝塞尔曲线(cubic-bezier()或ease-in等)、阶跃(step)

  • 线性(linear): 线性 timing-function 意味着动画在其整个过程中保持恒定的速度。这意味着在执行动画的每个时间片段中,动画元素的移动速度都相同。要应用线性 timing-function,可以使用 linear 值:

    animation-timing-function: linear;
    
    
  • 贝塞尔曲线(cubic-bezier() 或 ease-in 等): 贝塞尔曲线 timing-function 提供了更为复杂的速度控制。贝塞尔曲线通过一个四阶(cubic)贝塞尔函数定义动画速度的变化。这意味着动画可以在某些时间片段内加速,然后在其他时间片段内减速。CSS 提供了一些预定义的贝塞尔曲线值,如 ease-inease-outease-in-out 和 ease。此外,还可以使用 cubic-bezier() 函数自定义贝塞尔曲线:

    animation-timing-function: ease-in; /* 预定义值 */
    animation-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1); /* 自定义贝塞尔曲线 */
    
    
  • 阶跃(step): 阶跃 timing-function 用于创建分段的、非平滑动画。这种类型的动画在其执行过程中会跳过一定数量的帧,使动画元素在特定的时间点发生突然的变化。阶跃 timing-function 使用 steps() 函数定义,其中包含一个整数参数,表示动画的阶段数:

    animation-timing-function: steps(4);
    
    

上述代码将动画分为4个阶段,每个阶段在动画执行过程中都会有一个突然的变化。

综上所述,timing-function 属性通过调整动画速度的变化,为创建复杂、吸引人的动画提供了很大的灵活性。

image.png

五、响应式设计

六、CSS生态相关

  • 语言增强:预处理器、后处理器
  • 工程架构:CSS模块化、CSS-ln-Js、Atomic CSS

语言增强 -- CSS预处理器

image.png

预处理器如何提高研发效率?

image.png

image.png

scss、less、stylus简单对比

Dart Sass 的源代码、文档和示例:sass/dart-sass: The reference implementation of Sass, written in Dart. (github.com)

Sass 的源代码、文档和示例:sass/sass: Sass makes CSS fun! (github.com)

Less 的源代码:less/less.js: Less. The dynamic stylesheet language. (github.com)

stylus 的源代码:stylus/stylus: Expressive, robust, feature-rich CSS language built for nodejs (github.com)

标题scsslessstylus
css语法兼容兼容兼容常规兼容
可编程能力较强:逻辑处理能力丰富较弱:不支持自定义函数较强
社区活跃、使用人数最多(存疑)star 3.5k;burbon库支持较多star 16.9k;twitter bootstrap框架相对少 star 11k;
代码演示
  1. Sass (SCSS 语法):展示了 Sass 的变量、函数(darken)、mixin 和 @include 指令
@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
  -moz-border-radius: $radius;
  -ms-border-radius: $radius;
  border-radius: $radius;
}
​
.button {
  background-color: darken($blue, 10%);
  padding: 10px 20px;
  color: white;
  @include border-radius(5px);
}

  1. Less:展示了 Less 的变量、函数(darken)、mixin 和 mixin 调用
.mixin(@border-radius) {
  -webkit-border-radius: @border-radius;
  -moz-border-radius: @border-radius;
  -ms-border-radius: @border-radius;
  border-radius: @border-radius;
}
​
.button {
  @base-color: blue;
  background-color: darken(@base-color, 10%);
  padding: 10px 20px;
  color: white;
  .mixin(5px);
}

  1. Stylus:展示了 Stylus 的变量、函数(darken)、mixin 和 mixin 调用。注意 Stylus 的语法比其他两者更加简洁。
border-radius(radius)
  -webkit-border-radius radius
  -moz-border-radius radius
  -ms-border-radius radius
  border-radius radius
​
.button
  base-color = blue
  background-color darken(base-color, 10%)
  padding 10px 20px
  color white
  border-radius(5px)

语言增强 -- 广义CSS预处理器

现在项目中常见的样式处理流程

image.png

语言增强 -- CSS后处理器

Plugins:PostCSS Plugins

CSS 后处理器是一种工具,它在 CSS 预处理器处理生成的 CSS 代码之后运行。其主要目的是优化和改进最终的 CSS 输出,以提高性能、浏览器兼容性和代码可维护性。

CSS 后处理器使用 JavaScript 插件(或其他编程语言编写的工具)来处理 CSS,这些插件可以解决不同的问题或执行特定任务。常见的 CSS 后处理器任务包括:

  1. 自动添加浏览器前缀(autoprefixer):根据目标浏览器和其版本,自动添加适当的浏览器前缀以确保跨浏览器兼容性。
  2. CSS 压缩(minification):删除 CSS 代码中的空格、换行符和注释,以减少文件大小,提高加载速度。
  3. 优化和合并规则(optimization):查找和合并重复的 CSS 规则,重写代码以减少不必要的选择器和规则,从而减少文件大小和提高性能。
  4. 使用 CSS 变量(CSS custom properties):将 CSS 预处理器中使用的变量转换为原生的 CSS 变量,从而在运行时更改样式。
  5. 实现未来 CSS 规范(future-proofing):将尚未得到广泛支持的新 CSS 规范转换为目前可用的兼容语法,以便在不等待浏览器支持的情况下使用新功能。

PostCSS 是目前最流行的 CSS 后处理器。它提供了一个插件系统,使开发人员能够根据需要选择和配置插件。PostCSS 可以与构建工具(如 Webpack、Gulp 和 Grunt)结合使用,将后处理集成到自动化构建和部署流程中。

image.png

语言增强 -- postcss机制浅析

Astexplorer:AST explorer是一个在线工具,用于可视化各种编程语言的抽象语法树(AST)。它可以帮助开发者更好地理解代码在解析过程中是如何被表示的。AST 是一种树形数据结构,用于表示源代码中的结构和语法关系。

在 Astexplorer 中,可以输入源代码,选择相应的解析器,然后查看生成的 AST。这个工具支持多种编程语言和相应的解析器,如 JavaScript、TypeScript、HTML、CSS、JSON 等。除了显示 AST,Astexplorer 还允许我们通过点击树形结构中的节点来高亮源代码中的对应部分,反之亦然。

Astexplorer 对于编译器和解析器的开发、编写代码转换工具(如 Babel 插件)以及深入了解编程语言的语法和结构非常有用。通过 Astexplorer,开发者可以更直观地理解源代码在解析和转换过程中是如何被操作和处理的。

  • PostCSS 的工作机制可以分为以下几个步骤:
  1. 解析:PostCSS 使用 CSS 解析器将 CSS 代码解析成一个 Abstract Syntax Tree(AST,抽象语法树)。AST 是一种树形数据结构,它表示了 CSS 代码的结构和层次关系,使得插件可以更容易地遍历和操作 CSS 规则。
  2. 插件:PostCSS 的插件系统是其核心功能。插件是 JavaScript 函数,它们在 PostCSS 生成 AST 后,对 AST 进行操作和修改。插件可以独立使用,也可以组合成一个管道(pipeline),按照特定的顺序执行多个插件。这使得 PostCSS 非常灵活,开发者可以根据项目需求选择和配置插件。
  3. 转换:在插件处理 AST 后,PostCSS 将修改后的 AST 转换回 CSS 代码。这个过程中,PostCSS 会保留原始代码中的格式、缩进和注释,以便生成的 CSS 代码具有良好的可读性。
  4. 集成:PostCSS 可以与各种构建工具(如 Webpack、Gulp 和 Grunt)集成,以便将后处理过程集成到自动化构建和部署流程中。这种集成可以简化开发流程,确保生成的 CSS 代码经过优化且兼容目标浏览器。

image.png

工程架构 -- CSS模块化

css-modules/css-modules: Documentation about css-modules (github.com)

CSS Module 就是为了解决全局污染问题出现的方案,解决CSS全局污染,本质上是保证样式集合对应的选择器是唯一的,从这个角度看,主流的单纯针对于防止全局污染的方案大概有以下三种:

image.png

工程架构 -- CSS-in-JS

cij的playground(下面那张图的演示地址):CSS in JS Playground

CSS-in-JS(JavaScript 中的 CSS)是一种现代的前端开发模式,它允许开发者直接在 JavaScript 代码中编写 CSS 样式,利用js动态生成css,这种在React中就是一个大杀器。CSS-in-JS 的目的是解决组件化和模块化的开发过程中遇到的一些 CSS 问题,例如全局作用域、命名冲突、依赖管理和代码重用等。

在 CSS-in-JS 中,样式被当作 JavaScript 对象来处理,这样可以使用 JavaScript 的所有特性(例如变量、函数、条件语句等)来创建动态样式。为组件创建的样式会在运行时注入到 DOM 中,这样就可以实现局部作用域,避免样式污染和命名冲突。

CSS-in-JS 的优点:

  1. 局部作用域:样式仅应用于特定的组件,避免了全局样式污染和命名冲突。
  2. 代码组织和重用:将样式与相应的组件绑定,使组件更易于维护和重用。
  3. 动态样式:可以使用 JavaScript 的能力来根据状态、属性和逻辑创建动态样式。
  4. 依赖管理:通过 JavaScript 模块系统管理样式依赖,简化了构建和打包过程。
  5. 主题和样式共享:通过 JavaScript 变量和对象轻松共享主题和样式。

一些流行的 CSS-in-JS 库包括:

  1. styled-components:使用 ES6 标签模板字符串创建样式化的组件。
  2. emotion:具有高性能的 CSS-in-JS 库,提供了多种样式定义方式。
  3. JSS:灵活的、独立的 CSS-in-JS 库,支持插件和样式复用。

需要注意的是,CSS-in-JS 并非适用于所有场景,也有一些潜在的缺点,如性能开销、额外的学习曲线、以及与传统 CSS 的不兼容。因此,在选择 CSS-in-JS 时,需要根据项目需求和团队技能进行权衡

工程架构 -- styled.component 机制浅析

工程架构 -- CSS-in-JS pros & cons

工程架构 -- 原子化CSS