深入理解CSS | 青训营笔记

191 阅读18分钟

CSS是什么?

CSS是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。CSS目前最新版本为CSS3,是能够真正做到网页表现与内容分离的一种样式设计语言。 CSS主要用来设计网页的样式,美化网页;它不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。

CSS的作用

(1)在几乎所有的浏览器上都可以使用。

(2)以前一些非得通过图片转换实现的功能,现在只要用CSS就可以轻松实现,从而更快地下载页面。

(3)使页面的字体变得更漂亮,更容易编排,使页面真正赏心悦目。

(4)可以轻松地控制页面的布局 。

(5)可以将许多网页的风格格式同时更新,不用再一页一页地更新了。可以将站点上所有的网页风格都使用一个CSS文件进行控制,只要修改这个CSS文件中相应的行,那么整个站点的所有页面都会随之发生变动。

一、基础知识


Casading规则、选择器、继承、值和单位、盒模型

01-层叠(Casading)、优先级

  • 层叠三大规则(优先程度递减):

    • 样式表来源
    • 选择器优先级
    • 源码位置
  • 样式表来源重要排序(重要性程度递增):

    • 用户代理样式(默认浏览器样式)
    • 用户样式表
    • 作者样式表
    • 作者样式表中的 ! important
    • 用户样式表中的 ! important
    • 用户代理样式表中的 ! important

    例:

    用户自己写的h1的字体样式会覆盖掉浏览器默认的样式

image.png

若是加上 ! important,原本字体显示的蓝色覆盖了红色,加上 ! important后,字体就会变成红色

image.png

02-选择器的优先级

  • 基础选择器

    • #id -- ID选择器。Tagname -- 类型选择器或者标签选择器。
    • .class -- 类选择器。* -- 通用选择器。该选择器匹配所有元素组合器
    • 子组合器(>)—―匹配的目标元素是其他元素的直接后代。如: .parent >.child。
    • 相邻兄弟组合器(+)—―匹配的目标元素紧跟在其他元素后面。如: p +h2。
    • 通用兄弟组合器(~)—―匹配所有跟随在指定元素之后的兄弟元素,如: li.active ~li。
    • 复合选择器多个基础选择器可以连起来使用,如:h1.page-header。
  • 属性选择器

    • 通过约束属性值,div[data-title="aaa"]
  • 伪类选择器

    • 选中处于某个特定状态或相对于其父级或兄弟元素的位置的元素。如:first-child ,:hover
  • 伪元素选择器

    • 匹配在文档中没有直接对应HTML元素的特定部分,或插入内容。如 h2:: first-letter, div::before
  • 逻辑选择器

    • 较新的选择器:is() :has() :where() :not()

选择器优先级

image.png

根据源码位置判断样式生效(谁最后声明的谁生效)

例:h1标签字体颜色最后生效为蓝色

image.png

  • 由层叠概念引申出CSS代码 good practice

    • 选择器尽量少用id
    • 尽量不要用 ! important
    • 自己的样式加载在引用库样式的后面

03-继承

image.png

  • 大部分具有继承特性的属性跟文本相关:

    color、font、font-family、font-size、font-weight、font-variant、font-style、line-height、letter-spacing、text-align、text-indent、text-transform、white-space以及word-spacing

    还有少部分列表、表格的属性

  • 可以使用inherit关键字显式指定一个属性值从其父元素继承

04-CSS的值和单位

image.png

05-盒模型

浏览器根据视觉格式化模型(visual formatting model),将所有元素表示为盒子模型,css通过盒模型做layout

最里层的蓝色区域为content

image.png

控制盒子类型:display: block、inline、inline-block、flex、...

控制盒子大小&计算方式:width,height ... & box-sizing: content-box、border-box

控制盒中内容流:overflow: auto、scroll、hidden、...

控制定位:position: static、 relative、absolute、fixed、sticky

是否可见:visibility: visible、hidden、 ...

由盒模型的特性能实现一些展现形式?

image.png

盒模型-负外边距

padding、border、margin中,只有margin可以设置负值

设置左边或顶部的负外边距,元素就会相应地向左或向上移动,导致元素与它前面的元素重叠:

image.png

如果设置右边或者底部的负外边距,并不会移动元素,而是将它后面的元素拉过来:

image.png

二、布局和定位


01-概述

CSS 3 之前用的布局:

  • Normal Flow常规流:默认的布局格式,有块级格式化上下文和内联格式化上下文
  • Float浮动流:用float属性控制脱流,做横向布局
  • Positioning定位流:用position属性控制,flexd和absolute脱离文档流可以自由定位、覆盖等

CSS 3 之后的新增布局

  • Flex弹性盒子布局
  • Grid网格布局
  • Multicol多列布局
  • 一堆空间布局
  • 二维空间布局
  • 文本、内容的多列展示

02-常规流布局

image.png

image.png

03-块级格式化上下文(block formatting context)

  • 格式化上下文的布局规范为:

    “在一个块格式区域中,盒子会从包含块的顶部开始,按序垂直排列。同级盒子间的垂直距离会由“margin"属性决定。相邻两个块级盒子之间的垂直间距会遵循外边距折叠原则被折叠。 在一个块格式区域中,每个盒子的左外边缘会与包含块左边缘重合(如果是从右到左的排版顺序,则盒子的右外边缘与包含块右边缘重合)。”

  • BFC(BFC具有一定的“沙盒”特性)

    BFC本身是block formatting context的缩写,是一种格式规范。如果说一个盒子是BFC或者有BFC特性,那么BFC表示的是block formatting context root。不管它外部显示类型是什么,但是它的内部显示类型是flow-root,其实就是这个盒子内部形成了一个新的块级格式化上下文

如何触发一个盒子的BFC特性?(以下条件满足任何一个即可)

  • display: flow-root l inline-block;
  • position: absolute | fixed;
  • float:不为none;
  • overflow:不为visible

04-外边距塌陷

会产生外边距塌陷的情况∶

  • 两个兄弟元素之间相邻的上下外边距
  • 父子元素之间相邻的上下外边距
  • 内容为空元素自己上下外边距相邻

image.png

消除外边距塌陷的方法:

  • 在两个相邻的上下边距之间增加border.padding或者内联元素,使之不相邻
  • 在父子元素重叠时,除了上述方法,还可以设置父元素为BFC,使得父子不在同级BFC中

image.png

05-内联格式化上下文

“在内联格式区域中,盒子会从包含块的顶部开始,按序水平排列。只有水平外边距、边框和内边距会被保留。这些盒子可以以不同的方式在垂直方向上对齐:可以底部对齐或顶部对齐,或者按文字底部进行对齐。我们把包含一串盒子的矩形区域称为一个线条框。(The rectangular area thatcontains the boxes that form a line is called a line box.) ”

image.png

例:

当内联元素都是vertical-algin: baseline

image.png

当图片改为vertical-algin: middle

image.png

06-弹性盒子布局

Flexible Box Layout是为了提供更加高效灵活的布局方式,在即便是宽高未知的情况下,也能排列和分割一个盒子内部的布局。而且在不同布局方向(横向/纵向)的调整更为灵活。

image.png

弹性盒子的相关属性分为两类:

  • 作用于父级元素

    建立一个弹性盒子--display: flex l inline-flex;

    规定盒子的主轴方向--flex-direction: row l column l.. .;

    子元素折行显示形式--flex-wrap: nowrap l wrap l wrap-reverse;

    主轴方向子元素的排列方式--justify-content: center l space-between l ...;

    交叉轴方向子元素的对齐方式--align-items: flex-start l center l stretch l ...;

    交叉轴方向多行子元素的布局方式-- align-content: flex-start l space-between l ...;

    以明确值设定子元素间的间隔-- gap: <row-gap> <column-gap>;

  • 作用于子级元素

    规定item未放缩之前的默认大小--flex-basis: autol长度值...;

    规定有剩余空间时,对item的分配比例--flex-grow: number;

    规定空间不够时,对item的压缩的比例--flex-shrink: number;

    以上三项的缩写--flex: grow shrink basis;默认0 1 auto

    规定item从左到白(row布局)--order: number;默认是0

    规定单个item在交叉轴上的位置--align-self: auto l center l flex-start l...

06-网格布局

2017年推出的Grid布局可以定义由行和列组成的二维布局,然后将元素放置到网格中。元素可以只占其中一个单元格,也可以占据多行或多列。

image.png

image.png

Grid和Flex布局的使用策略

  • Flex

    • 一堆布局
    • 基于内容
    • 浏览器兼容性更好
  • Grid

    • 二堆布局
    • 基于布局
    • 2017年后浏览器的版本普遍支持

Grid for layout,Flexbox for components

  • 大面积或整体布局推荐使用Grid布局
  • 小面积或组件中,或Grid Item中可以使用Flex做灵活布局

07-定位Position

为了我们可以在文档流的基础上,让元素移动,做出更多灵活的改变。当posion属性的取值非static的时候,可以使用top,right, bottom,lert对其进行定位。

  • relative

    元素相对于自己原来在文档流中的位置进行定位,但是原来文档流的空间还在。

image.png

  • absolute

    元素被移出正常文档流,且没有预留空间,相对于最近的非static定位祖先元素的进行定位。

image.png

  • fixed

    元素被移出正常文档流,且没有预留空间,相对于屏幕视口进行定位,屏幕滚动也不会改变位置

image.png

  • sticky

    元素相对它的最近滚动祖先(祖先的overflow是scroll/hidden/auto)的视口(scrollport)定位

image.png

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


01-The stacking content

层叠上下文是对HTML元素的三维构想,将元素沿着垂直屏幕的虚构的Z轴排开

层叠上下文结构

image.png

一个新的层叠上下文渲染时会对应一个浏览器渲染时的render layer(渲染层)

image.png

注意∶不是浏览器devtool图层工具中看到的图层

形成新的叠层上下文的条件(任一即可):

  • position:relative 或 absolute;并且z-index不是auto(css3之前)
  • position: fixed 或sticky(css3之前)
  • flex或grid的子元素﹔并且z-index不是auto(css3之前)
  • opacity的值小于1
  • transform 的值不为none
  • will-change 的值不为通用值

02-stackina order

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

image.png

z-index只在同一个层叠上下文内比较

子元素的z-index无法超越父元素的z-index显示顺序


编写z-index的建议:

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

image.png

四、变形、过渡、动画


01-transform 变形

2D相关属性

  • transform: translate(移动)、rotate(旋转)、scale(放缩)、matrix(变形矩阵)等
  • transform-origin: right top、center等表示变形时依据的原点

image.png

3D相关属性:

  • transform: translate3d . rotate3d、scale3d、matrix3d等
  • transform-origin: right top、50px 30px 等表示变形时依据的原点
  • transform-style: flat或 preserve-3d看子元素的3d表现
  • perspective:观看点距离z=0这个平面的距离,可以在transform中用perspective()使用作用为当前元素,也可以直接使用,给后代元素一个统一值
  • perspective-origin:观看者的位置,如top、bottom等
  • backface-visibility:元素正面只有朝向观察者的时候可见

image.png

02-transition 过渡

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

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

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

常见的曲线变化应用

image.png

step 的应用:逐帧动画、定格动画、闪烁、时钟等

image.png

03-animation 动画

@keyframes关键帧用来定义动画过程中出现的关键样式

image.png

animation-* 相关属性用来为元素添加动画

animation-name:定义好的关键帧的名字
animation-duration:动画时长
animation-timing-function:动画节奏
animation-delay:延时开始的时间
animation-iteration-count:执行次数
animation-direction:是否反向或交替
animation-fill-mode:动画执行前后的样式采用
animation-play-state:动画运行状态

04-transform、transition、animation--性能相关

image.png

如何写动画性能更好?

  • 尽量不用触发reflow的属性
  • 在遇到性能问题时可以触发硬件加速,比如设置will-change属性、设置transform3d等
  • 尽量使用transform和 opacity去写动画

五、响应式设计


01-响应式设计推荐遵循的原则

  1. 优先选用流式布局,如百分比、flex、grid等
  2. 使用响应式图片,匹配尺寸,节省带宽
  3. 使用媒体查询为不同的设备类型做适配
  4. 给移动端设备设置简单、统一的视口
  5. 使用相对长度,em、rem . vw 做为长度度量

02-媒体查询的使用

媒体查询允许某些样式只在页面满足特定条件时才生效。我们可以将媒体类型〈如screen、print)以及媒体特性〈如视口宽度、屏幕比例、设备方向:横向或纵向)做为约束条件。

image.png

image.png

使用媒体查询的一些Tips

  • 媒体查询同样遵循cascading层叠覆盖原则, min-和max-选择一个
  • 由于设备的多样化逐渐不可枚举,断点的选择尽量根据内容选择
  • 由于断点的增加会增加样式处理的复杂度,所以尽量减少断点

image.png

03-设备像素、参考像素和移动设备视口

image.png

设备像素(物理像素)︰显示器上绘制的最小单位,显示屏通过控制每个像素点的颜色,使屏幕显示出不同的图像。

设备像素和设备相关,屏幕从工厂出来那天起,它上面的物理像素点就固定不变了。

image.png

image.png

DPI && PPI

dpi (dots per inch)︰每英寸多少点

ppi (pixels per inch)︰每英寸多少像素数

当屏幕分辨率是X*Y,计算公式:

image.png

image.png

CSS像素

image.png

CSS像素(reference pixel).其实是一个视角单位。规范给出的定义是,1css像素是从一臂之遥看解析度为96DPI(即1英寸96点)的设备输出时,1点(即1/96英寸)的视角。

通常认为常人臂长为28英寸,那么视线与水平线的夹角是:(1/96)in / (28in * 2* PI/360deg)= 0.0213度

如果1css像素永远等于1设备像素,那么

image.png

但是真正使用的CSS像素并不是用0.0213度去精确计算的,因为css像素存在的目的是为了保证阅读体验一致,所以对不同的物理设备,CSS使得浏览器中1css像素的大小在不同物理设备上看上去大小总是差不多。 真正实现时,为了方便基本都是根据设备像素换算的。浏览器根据硬件设备能够直接获取css像素

DPR设备像素比

设备像素比(dpr) : 描述的是未缩放状态下,设备像素和CSS像素的初始比例关系

image.png

image.png

移动端的viewport 布局视口(viewport) 是页面中html元素(根元素)的包含块,默认情况下,window.document.documentElement.clientWidth就是viewport的宽度

在移动设备中,默认的布局视口由于历史兼容pc屏幕的原因,并不符合需求,我们经常需要用<mela>标签对viewport进行设定,来完成移动端设备的适配。

比如:默认iphone的布局视口是980px,展示如图:

image.png

image.png

viewport的meta标签中的属性

  • width
  • height
  • initial-scaleminimum-scale
  • maximum-scale
  • user-scalable

默认iPhone的viewport可以认为是:

<meta name="viewport" content="width=980">

其中initial-scale,在未设定时,如果width设定了,那么它会自动设置放缩值:

initial-scale =屏幕宽度(例子中是390) /980~0.398相比scale=1的时候,缩小了0.398倍

常见的移动端viewport的设置:

  • 保持scale为1

    <meta name="viewport" content="width=device-width,initial-scale=1">

    好处是:在所有设备上不管横屏还是竖屏,让布局视口的宽度和设备屏幕的宽度保持一致,且参考像素不放缩。

    不好的是:如果设备的dpr > 1,那么想要画出一个设备像素粗细的线,需要其他方法实现。

  • 保持scale放缩参数是1/dpr

    const calcScale = 1 / window.devicePixelRation;

    <meta name="viewport" content="initial-scale=calcScale, maximum-scale=calcScale ,minimum-scale=calcScale ,user-scalable=no">

    好处是:1个css px等于1个设备像素,全局层面解决“真实1像素”问题。

    不好的是:不同设备想达到1个css px严格等于1个设备像素,需要处理兼容性才能达到。而且,全局等比放缩,对某些固定尺寸需要特殊处理。

04-相对长度的使用

em

image.png

应用场景:可以让展示区域根据展示字号的不同,做出放缩调整

//html
    <div class="small-paragraph">
        文字较小时候的段落呈现
    </div>

    <div class="large-paragraph">
        文字较大时候的段落呈现
    </div>
        
//css
    .small-paragraph{
            font-size: 12px;
        }
        .large-paragraph{
            font-size: 20px;
        }

image.png

rem

rem︰根元素的字体大小。通过伪类root或者html选择器选定。由于是根元素的font-size,所以不会像em那样出现多重嵌套问题,减少了复杂性,同时作为一个相对单位,可以进行适配放缩,可以用来做响应式布局。

image.png

vw和vh

vw︰视窗宽度的1%。

vh∶视窗高度的1%。同样,vw也可以作为响应式布局的基准单位。由于vw天然是视口宽度的1%,所以不需要js动态配置。

和rem方案类似,方案设定可以如下:

image.png

六、CSS生态相关


01-语言增强

cSS预处理器

image.png

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

  • 自定义变量 -- 提高可复用
  • 嵌套、作用域 -- 避免全局污染、结构层次清晰、减少复杂组合选择器
  • mixins、继承 -- 提高可复用、可维护性
  • 操作符、条件/循环语句、自定义函数 -- 提高可编程能力、增加灵活性

scss、less、stylus简单对比

image.png

广义CSS预处理器

image.png

CSS后处理器

image.png

postcss机制浅析

image.png

02-工程架构

CSS模块化

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

  • BEM命名规范--通过.block_element--modifier这种命名规范来约束开发者,从而实现样式隔离
  • vue-loader 的scoped方案--通过编译的方式,在html元素上添加data-xxx的唯一属性,然后css添加属性选择器[data-xxx]的方式,实现样式隔离
  • css Modules--通过编译的方式,将一个css file中的样式命名默认转换为一个全局唯一的名称,实现样式隔离,(常用 css-loader 或 postcss-module )

CSS-In-Js

将应用的CSS样式写在JavaScript文件里面,利用js动态生成css

  • inline-style -- 代表:radium
  • unique classname -- styled-component

image.png

styled-component机制浅析

  • Step1生成第一个classname做为componentld

    这个类名没有CSS样式,但是当需要引用其它组件的时候,可以作为一个嵌套选择器来使用

  • Step2生成第二个classname做为唯一类名(hash值),使用stylis,生成和唯一类名关联的CSS字符串

  • Step3唯一类名对应的css样式insert到<head><style>

  • Step4将两个类名写到目标节点的class中

image.png

pros & cons

image.png

Atomic CSS(原子化CSS)

原子化 CSS是一种CSS的架构方式,它倾向于小巧且用途单一的class,并以视觉效果进行命名。

Tailwind为例:

要实现: image.png

image.png

image.png

Tailwind如何做?

  1. 实用工具库优先(Utilities-First)
//利用基础的规则库预先定义好生成规则
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
  1. 按需生成
//html
body>
    <h1 class="text-3xl font-bold underline text-blue flex-grow">
        Hello world!
    </h1>
</body>

//css
.flex-grow {
    flex-grow: 1;
}
.text-3xl {
    font-size: 1.875rem;
    line-height: 2.25rem;
}
.font-bold {
    font-weight:700;
}
.underline {
    text-decoration-line;
    underline;
}
  1. 支持配置样式规则&自定义插件

module.exports = {
    theme: {
        colors: {
            'blue' : '#1fb6ff',
            'purple': '#7e5bef',
            'pink': '#ff49db',
            'orange': '#ff7849',
            'green' : '#13ce66',
            'yellow' : '#ffc82c',
            'gray-dark ' : '#273444',
            'gray' : '#8492a6',
            'gray-light' : '#d3dce6',
          },
    fontFamily: {
        sans:[ "Graphik"," sans-serif"],
        serif: ['Merriweather','serif'],
          },
    extend: {
        spacing: {
        '8xl' : '96rem',
        '9xl': '128rem ' ,
        },
    borderRadius:{
        '4xl' : '2rem',
        }
    }
}

image.png


image.png