CSS是什么?
CSS是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。CSS目前最新版本为CSS3,是能够真正做到网页表现与内容分离的一种样式设计语言。 CSS主要用来设计网页的样式,美化网页;它不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。
CSS的作用
(1)在几乎所有的浏览器上都可以使用。
(2)以前一些非得通过图片转换实现的功能,现在只要用CSS就可以轻松实现,从而更快地下载页面。
(3)使页面的字体变得更漂亮,更容易编排,使页面真正赏心悦目。
(4)可以轻松地控制页面的布局 。
(5)可以将许多网页的风格格式同时更新,不用再一页一页地更新了。可以将站点上所有的网页风格都使用一个CSS文件进行控制,只要修改这个CSS文件中相应的行,那么整个站点的所有页面都会随之发生变动。
一、基础知识
Casading规则、选择器、继承、值和单位、盒模型
01-层叠(Casading)、优先级
-
层叠三大规则(优先程度递减):
- 样式表来源
- 选择器优先级
- 源码位置
-
样式表来源重要排序(重要性程度递增):
- 用户代理样式(默认浏览器样式)
- 用户样式表
- 作者样式表
- 作者样式表中的 ! important
- 用户样式表中的 ! important
- 用户代理样式表中的 ! important
例:
用户自己写的h1的字体样式会覆盖掉浏览器默认的样式
若是加上 ! important,原本字体显示的蓝色覆盖了红色,加上 ! important后,字体就会变成红色
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()
选择器优先级
根据源码位置判断样式生效(谁最后声明的谁生效)
例:h1标签字体颜色最后生效为蓝色
-
由层叠概念引申出CSS代码 good practice
- 选择器尽量少用id
- 尽量不要用 ! important
- 自己的样式加载在引用库样式的后面
03-继承
-
大部分具有继承特性的属性跟文本相关:
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的值和单位
05-盒模型
浏览器根据视觉格式化模型(visual formatting model),将所有元素表示为盒子模型,css通过盒模型做layout
最里层的蓝色区域为content
控制盒子类型: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、 ...
由盒模型的特性能实现一些展现形式?
盒模型-负外边距
padding、border、margin中,只有margin可以设置负值
设置左边或顶部的负外边距,元素就会相应地向左或向上移动,导致元素与它前面的元素重叠:
如果设置右边或者底部的负外边距,并不会移动元素,而是将它后面的元素拉过来:
二、布局和定位
01-概述
CSS 3 之前用的布局:
- Normal Flow常规流:默认的布局格式,有块级格式化上下文和内联格式化上下文
- Float浮动流:用float属性控制脱流,做横向布局
- Positioning定位流:用position属性控制,flexd和absolute脱离文档流可以自由定位、覆盖等
CSS 3 之后的新增布局
- Flex弹性盒子布局
- Grid网格布局
- Multicol多列布局
- 一堆空间布局
- 二维空间布局
- 文本、内容的多列展示
02-常规流布局
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-外边距塌陷
会产生外边距塌陷的情况∶
- 两个兄弟元素之间相邻的上下外边距
- 父子元素之间相邻的上下外边距
- 内容为空元素自己上下外边距相邻
消除外边距塌陷的方法:
- 在两个相邻的上下边距之间增加border.padding或者内联元素,使之不相邻
- 在父子元素重叠时,除了上述方法,还可以设置父元素为BFC,使得父子不在同级BFC中
05-内联格式化上下文
“在内联格式区域中,盒子会从包含块的顶部开始,按序水平排列。只有水平外边距、边框和内边距会被保留。这些盒子可以以不同的方式在垂直方向上对齐:可以底部对齐或顶部对齐,或者按文字底部进行对齐。我们把包含一串盒子的矩形区域称为一个线条框。(The rectangular area thatcontains the boxes that form a line is called a line box.) ”
例:
当内联元素都是vertical-algin: baseline
当图片改为vertical-algin: middle
06-弹性盒子布局
Flexible Box Layout是为了提供更加高效灵活的布局方式,在即便是宽高未知的情况下,也能排列和分割一个盒子内部的布局。而且在不同布局方向(横向/纵向)的调整更为灵活。
弹性盒子的相关属性分为两类:
-
作用于父级元素
建立一个弹性盒子--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布局可以定义由行和列组成的二维布局,然后将元素放置到网格中。元素可以只占其中一个单元格,也可以占据多行或多列。
Grid和Flex布局的使用策略
-
Flex
- 一堆布局
- 基于内容
- 浏览器兼容性更好
-
Grid
- 二堆布局
- 基于布局
- 2017年后浏览器的版本普遍支持
Grid for layout,Flexbox for components
- 大面积或整体布局推荐使用Grid布局
- 小面积或组件中,或Grid Item中可以使用Flex做灵活布局
07-定位Position
为了我们可以在文档流的基础上,让元素移动,做出更多灵活的改变。当posion属性的取值非static的时候,可以使用top,right, bottom,lert对其进行定位。
-
relative
元素相对于自己原来在文档流中的位置进行定位,但是原来文档流的空间还在。
-
absolute
元素被移出正常文档流,且没有预留空间,相对于最近的非static定位祖先元素的进行定位。
-
fixed
元素被移出正常文档流,且没有预留空间,相对于屏幕视口进行定位,屏幕滚动也不会改变位置
-
sticky
元素相对它的最近滚动祖先(祖先的overflow是scroll/hidden/auto)的视口(scrollport)定位
三、层叠上下文(The Stacking Context)
01-The stacking content
层叠上下文是对HTML元素的三维构想,将元素沿着垂直屏幕的虚构的Z轴排开
层叠上下文结构
一个新的层叠上下文渲染时会对应一个浏览器渲染时的render layer(渲染层)
注意∶不是浏览器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
层叠顺序不仅指不同的层叠上下文的顺序,同一个层叠上下文内,元素间也有顺序:
z-index只在同一个层叠上下文内比较
子元素的z-index无法超越父元素的z-index显示顺序
编写z-index的建议:
- 使用css,变量或者预处理语言的变量,管理z-index的值
- 将预设间隔设置10或100,方便后续的插入
四、变形、过渡、动画
01-transform 变形
2D相关属性︰
- transform: translate(移动)、rotate(旋转)、scale(放缩)、matrix(变形矩阵)等
- transform-origin: right top、center等表示变形时依据的原点
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:元素正面只有朝向观察者的时候可见
02-transition 过渡
通过指定某些元素属性从一种起始状态,在一段时间内以某种变化节奏,过渡到终止状态
div{
transition: <property> <duration> <timing-function> <delay>
}
其中timing-function一般有三种用法:线性(linear)、贝塞尔曲线(cubic-bezier()或ease-in等)、阶跃(step)
常见的曲线变化应用
step 的应用:逐帧动画、定格动画、闪烁、时钟等
03-animation 动画
@keyframes关键帧用来定义动画过程中出现的关键样式
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--性能相关
如何写动画性能更好?
- 尽量不用触发reflow的属性
- 在遇到性能问题时可以触发硬件加速,比如设置will-change属性、设置transform3d等
- 尽量使用transform和 opacity去写动画
五、响应式设计
01-响应式设计推荐遵循的原则
- 优先选用流式布局,如百分比、flex、grid等
- 使用响应式图片,匹配尺寸,节省带宽
- 使用媒体查询为不同的设备类型做适配
- 给移动端设备设置简单、统一的视口
- 使用相对长度,em、rem . vw 做为长度度量
02-媒体查询的使用
媒体查询允许某些样式只在页面满足特定条件时才生效。我们可以将媒体类型〈如screen、print)以及媒体特性〈如视口宽度、屏幕比例、设备方向:横向或纵向)做为约束条件。
使用媒体查询的一些Tips
- 媒体查询同样遵循cascading层叠覆盖原则, min-和max-选择一个
- 由于设备的多样化逐渐不可枚举,断点的选择尽量根据内容选择
- 由于断点的增加会增加样式处理的复杂度,所以尽量减少断点
03-设备像素、参考像素和移动设备视口
设备像素和设备相关,屏幕从工厂出来那天起,它上面的物理像素点就固定不变了。
DPI && PPI
dpi (dots per inch)︰每英寸多少点
ppi (pixels per inch)︰每英寸多少像素数
当屏幕分辨率是X*Y,计算公式:
CSS像素
CSS像素(reference pixel).其实是一个视角单位。规范给出的定义是,1css像素是从一臂之遥看解析度为96DPI(即1英寸96点)的设备输出时,1点(即1/96英寸)的视角。
通常认为常人臂长为28英寸,那么视线与水平线的夹角是:(1/96)in / (28in * 2* PI/360deg)= 0.0213度
如果1css像素永远等于1设备像素,那么
DPR设备像素比
设备像素比(dpr) : 描述的是未缩放状态下,设备像素和CSS像素的初始比例关系
移动端的viewport 布局视口(viewport) 是页面中html元素(根元素)的包含块,默认情况下,window.document.documentElement.clientWidth就是viewport的宽度。
在移动设备中,默认的布局视口由于历史兼容pc屏幕的原因,并不符合需求,我们经常需要用<mela>标签对viewport进行设定,来完成移动端设备的适配。
比如:默认iphone的布局视口是980px,展示如图:
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
应用场景:可以让展示区域根据展示字号的不同,做出放缩调整
//html
<div class="small-paragraph">
文字较小时候的段落呈现
</div>
<div class="large-paragraph">
文字较大时候的段落呈现
</div>
//css
.small-paragraph{
font-size: 12px;
}
.large-paragraph{
font-size: 20px;
}
rem
rem︰根元素的字体大小。通过伪类root或者html选择器选定。由于是根元素的font-size,所以不会像em那样出现多重嵌套问题,减少了复杂性,同时作为一个相对单位,可以进行适配放缩,可以用来做响应式布局。
vw和vh
vw︰视窗宽度的1%。
vh∶视窗高度的1%。同样,vw也可以作为响应式布局的基准单位。由于vw天然是视口宽度的1%,所以不需要js动态配置。
和rem方案类似,方案设定可以如下:
六、CSS生态相关
01-语言增强
cSS预处理器
预处理器如何让提高研发效率?
- 自定义变量 -- 提高可复用
- 嵌套、作用域 -- 避免全局污染、结构层次清晰、减少复杂组合选择器
- mixins、继承 -- 提高可复用、可维护性
- 操作符、条件/循环语句、自定义函数 -- 提高可编程能力、增加灵活性
scss、less、stylus简单对比
广义CSS预处理器
CSS后处理器
postcss机制浅析
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
styled-component机制浅析
-
Step1生成第一个classname做为componentld
这个类名没有CSS样式,但是当需要引用其它组件的时候,可以作为一个嵌套选择器来使用
-
Step2生成第二个classname做为唯一类名(hash值),使用stylis,生成和唯一类名关联的CSS字符串
-
Step3唯一类名对应的css样式insert到
<head>的<style>中 -
Step4将两个类名写到目标节点的class中
pros & cons
Atomic CSS(原子化CSS)
原子化 CSS是一种CSS的架构方式,它倾向于小巧且用途单一的class,并以视觉效果进行命名。
Tailwind为例:
要实现:
Tailwind如何做?
- 实用工具库优先(Utilities-First)
//利用基础的规则库预先定义好生成规则
@tailwind base;
@tailwind components;
@tailwind utilities;
- 按需生成
//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;
}
- 支持配置样式规则&自定义插件
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',
}
}
}