笔记 - CSS入门

390 阅读14分钟

CSS基础

浏览器与支持特性

caniuse.com

关于CSS优先级:

一般情况下,优先级如下: (外部样式)External style sheet <(内部样式)Internal style sheet <(内联样式)Inline style 有个例外的情况,就是如果外部样式放在内部样式的后面,则外部样式将覆盖内部样式。

选择器语法

选择器 { 属性: 值; /* 注释 */ }

at语法

/* 编码声明,必须放在第一行! */
@charset "UTF-8"; 
/* 导入CSS文件 */
@import url(2.css); 
 /* 媒体查询 */
@media (min-width: 100px) and (max-width: 200px){
 syntax
} 

css语法检查:
  1. w3c css validator
  2. 编辑器自带纠错
border调试法:
  1. 给需要调试的元素第一行加上醒目border border: 1px solid red;
  2. 如果能够显示出,则该元素可以被匹配到,选择器未出错
  3. 将border下移,逐行检查,如果哪一行未能显示border,则前一行出错
  4. 问题解决删除border (类似js log调试法,脚本语言万岁)

练习素材: 1.模仿psd

  • freepik -365psd
  1. 效果图 dribbble.com
  2. 商业网站

Normal Flow 文档流

实际上HTML5并未区分内联元素与块元素,display:inline则显示成内联元素,display:block显示成块元素。 而浏览器的默认样式中:

  • 内联元素(inline) 从左到右排列,超出一行则折入下一行。 inline不接受 width 和 height 设置宽高。 inline的宽度由其内部的元素宽度总和决定。 inline的高度由line-height间接决定。即如果使用padding增加内边距,其可见高度会增加,但实际高度未增加。但line-height能增加其实际高度。line-height可被继承。 e.g.
    <style>
        span {
            border: 1px solid red;
            /* 增加可见高度
          padding: 10px 20px;
          */
          /* 增加实际高度
          line-height: 100px;
          */
        }
        div {
            border: 1px solid red;
        }
        body {
            padding: 20px;
        }
    </style>
    <div>
        <span>span元素+padding</span>
    </div>
  • 块级元素(block) 从上到下排列,一行只有一个块级元素,每一个另起一行。 block接受width和height设置宽高。 block的宽度默认是auto width=auto;,而不是100%,即能有多宽占多宽。加上例如margin之类属性后其本身宽度也会自动缩短。 block的高度由内部文档流元素决定。
  • 内联块(inline-block) inline block元素具有两者的特点,一行中可显示多个元素,但超出一行的元素不会折入下一行,而是完整出现在下一行。 接受width和height设置宽高。

(尽量不要写width=100%,极易出错)

tips: 一口气生成多行 e.g.

element.class{$数字 内容}*num

element: 需要生成的元素 .class: 生成的元素拥有的class name {...}: 正则+内容,$代表数字 *num: 生成个数

overflow 溢出
/* overflow */
overflow: visible;  默认
overflow: hidden; 隐藏
overflow: scroll; 滚动,即使内容没有溢出也会显示滚动条,丑
overflow: auto;  自动,不超出时不显示滚动条,超出时显示


脱离文档流

脱离文档流之后不算在所在容器的高度中

float: left / right / etc.;
position: absolute / fixed;

盒模型

margin -> border -> padding -> content
content box width = content width
border box width = content width + padding width + border width
e.g.

.content-box {
  margin: 25px;
  border: 5px solid red;
  padding: 15px;
  /* box-sizing属性决定盒类型 */
  box-sizing: content-box;
  width: 100px;
}

.border-box {
  margin: 25px;
  border: 5px solid green;
  padding:15px;
  box-sizing: border-box;
  width: 100px;
}

截屏2021-02-03 21.42.20.png

相对而言border-box更好用

margin合并

上下合并,左右不合并

  1. 父子margin合并
  • 可用padding,border挡住
  • 可用overflow: hidden挡住
  • 可用display: flex
  1. 兄弟margin合并
  • 可用display: inline消除

基本单位

  • px 像素
  • em 相对字号的倍数 e.g.
font-size: 20px;
width: 3em;

则width为20px*3=60px

  • % 百分比
  • 整数

windows only 的选色/截图工具: snipaste sspai.com/item/83

color 颜色

  1. 关键词颜色 e.g. red 红,transparent 全透明
  2. 十六进制 e.g. #FF6600 淘宝专用色
  3. rgb, rgba e.g. rgb(255,0,127) 完全不透明 rgba(255,0,127,0.2) a的最大值1为完全不透明,最小值0为完全透明
  4. hsl hsl(色相, 饱和度%,亮度%) 色相:0-360 赤橙黄绿青蓝紫红 饱和度:百分比,一般70-80%,饱和度低则不显眼,饱和度高则亮眼 亮度:0为全暗,100为全白

tips: 关于alpha通道 rgb, hsl, hex均可使用a rgb(r, g, b) -> rgba(r, g, b, a) hsl(h, s, l) -> hsla(h, s, l, a) #FF6600 -> #FF660000(全透明) #FF660011(不透明) #FF660088 (半透明)

Float & Flex布局

布局分类

  1. 固定宽度布局 960px, 1000px, 1024px,电脑页面
  2. 不固定宽度布局。 主要靠文档流,原本就是自适应,不需要额外样式。 多半是手机页面布局。
  3. 响应式布局

怎样选择布局

截屏2021-02-09 16.36.15.png

Float布局 - 为IE准备

  1. 子元素加float: left和width
  2. 父元素加.clearfix e.g.
<style>
/* css reset */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* 使脱离文档流的子元素高度可被父元素包裹 */
.clearfix::after {
  content: '';
  display: block;
  clear: both;
}

/* 
   加入float属性使div.logo和nav脱离文档流
   不再作为block元素存在
   此时父元素header的高度为0
   需要给header加入.clearfix
*/
.logo {
  border: 1px solid red;
  height: 40px;
  width: 100px;
  float: left;
  margin-top: 5px;
  /* 使logo和nav居中对齐 */
}
nav {
  border: 1px solid green;
  height: 50px;
  width: 200px;
  float: right ;
}
header {
  border: 1px solid black;
}
</style>  
<header class="clearfix">
  <div class="logo">LOGO</div>
  <nav>Navigation</nav>
</header>

  • 一般来说float布局里,一行的最后一个元素不写width,由其自身决定。
  • float布局不需要做响应式(由于float基本适配IE,而手机上没有IE,自然不需要为了手机屏幕做的响应式)
  • IE6-7存在双倍margin bug
    1. 可以减半margin e.g. 假设原margin-left: 10px 则在该行下增加 _margin-left: 5px; IE可识别并计算出需要的margin
    2. 可以加display: inline-block对抗bug

tips: 怎样去除图片下方多余的背景色条
给需要去掉的img加一行: vertical-align: top;或者vertical-aligin: middle 原理: line-height
一个简单的nav示例

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <style>
/* css reset */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
img {
  max-width: 100%; 
}
/* 卸除列表默认样式 */
ul, ol{
  list-style: none;
}
/* clearfix */
.clearfix::after {
  content: '';
  display: block;
  clear: both;
}

.logo {
  background: black;
  display: inline-block;
  float: left;
}
.logo > img {
  /* 当宽度不好固定时可直接设置高度 */
  height: 26px;
  /* 裁去图片下方多余的背景色块 */
  vertical-align: middle;
}
ul > li {
  float: left;
  border: 1px solid red;
  /* 上下4px,左右0.5倍 */
  padding: 4px 0.5em;
}
ul {
  border: 1px solid green;
  display: inline-block;
}

nav {
  float: left;
}
  </style>
</head>
<body>
  <div class="logo">
    <img src="" alt="logo">
  </div>
<nav>
  <ul class="clearfix">
    <li>首页</li>
    <li>商品</li>
    <li>优惠</li>
    <li>关于</li>
  </ul>
</nav>
</body>
</html>

tips: 用outline替代border进行调试 使用border进行调试时其宽度可能会干扰显示,此时使用outline属性替代border outline: 1px solid red;

tips: 如何让元素自动居中 margin: 0 auto;
指定auto为第二个参数基本上会告诉浏览器自动确定左右边距本身,方法是将它们均等设置。它保证左右边距将设置为相同的大小。第一个参数0表示顶部和底部边距都将设置为0。 其效果等同于

margin-top:0;
margin-bottom:0;
margin-left:auto;
margin-right:auto;

最好使用margin-left:auto; margin-right:auto;,以防覆盖margin-top, margin-bottom.

负margin(平均布局)

做float平均布局时,一个元素里包裹数个子元素,每个子元素都有自己的margi-right,则最后一个元素会因为其右侧margin溢出而转到下一行 此时可在所有子元素外再套一层父元素 ,并使其margin-right为负数 截屏2021-02-10 17.15.06.png

Flex布局(flex flow) 弹性盒模型

弹性盒模型顾名思义,其大小和方向可自动适应当前布局。譬如子元素宽度和大于父元素时,子元素会自动缩减其宽度以适应。

.container {
  display: flex; /* 或者 display: inline-flex */
}
flex-direction 弹性盒模型方向
flex-direction: row;  /* default, left->right */
flex-direction: row-reverse; /* right->left */
flex-direction: column; /* top->down */
flex-direction: colunm-reverse; /* down->top */
flex-wrap 折行控制
flex-wrap: nowrap; /* default 不折行 */
flex-wrap: wrap; /* 折行, 不断开 */
flex-wrap:  wrap-reverse; /* 反向折行,元素倒叙,从下往上排 */
justify-content 主轴方向,默认横轴
justify-content: flex-start; /* <-- 元素靠左排列 */
justify-content: flex-end; /* 元素靠右排列 --> */
justify-content: center; /* 居中排列 */
justify-content: space-between; /* 中间有间隔的均匀分布 */
justify-content: space-around; /* 包围式有间隔均匀分布 */
align-item 次轴方向,默认纵轴
align-item: stretch; /* 在无高度的时候根据内容高度自动拉伸 */
align-item: flex-start; /* 全部向上,贴在顶部*/
align-item: flex-end; /* 全部向下,贴在底部 */
align-item: center; /* 聚在中心 */
align-content 多行内容
align-content: flex-start; /* 贴在顶部 */
align-content: flex-end; /* 贴在底部 */
align-content: center; /* 集中在中间 */
align-content: strech; /* 自动伸展 */
align-content: space-between;
align-content: space-around;

关于CSS选择器选择子元素

<style>
.container {
  display: flex; /* 或者 display: inline-flex */
  border: 1px solid red;
  flex-direction: row;
  flex-wrap: wrap;
}
.item {
  width: 50px;
  border: 1px solid green;
  height: 50px;
}

/* class=item,相对于父元素的第一个子元素 */

.item:first-child{
  
}
/* class=item,相对于父元素的n个子元素->第二个 */
.item:nth-child(2){
  
}
.item:nth-child(3){
  
}
.item:nth-child(4){
  
}
/* class=item,相对于父元素最后一个子元素 */
.item:last-child{
  
}
</style>
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
</div>


flex item

order 默认order=0,从小到大排列,负值会在前面。
flex-grow (自动长胖属性) flex-grow: num; num=0 没有变化 num=1 得一份 num=2 得两份 ... 使每个子元素按分数分配宽度
flex-shrink 控制变瘦,当原始宽度小于实际宽度,空间不够互相挤压时。使用该属性需要设置原始宽度。 flex-shrink:0 防止变瘦 flex-shrink:1 默认值,自动变瘦
缩写 flex: flex-grow flex-shrink flex-basis; 三个属性在缩写时都必须写上! e.g. flex: 1, 100, 1000px;
align-self 令某个item拥有自己的方向 e.g. align-self: flex-end;

Grid布局

Grid

.container {
  display: grid | inline-grid;
}

row column

.container {
grid-template-columns: 30px 30% auto;
grid-template-row: 30px 30% auto;
}

start end

/* 控制开始位置和结束位置 */
.sub-item {
grid-column-start: 1;
grid-column-end: 2;
}

grid-template-areas

利用标签直接划分区域

CSS 定位

div分层

从上到下:文字内容(内联子元素) - 浮动元素,块级子元素 - border - background div的层级关系遵从前后顺序,后面的会盖住先前的文字。

position

只有position的值不为static时,才能设置z-index
static:默认值,文档流内
relative:升起,但不脱离文档流,常作为absolute的父元素使用。可配合z-index使用
absolute:绝对定位,脱离原本的位置,需要有一个不为static的父元素作为基准的定位元素(多半是relative)。 对话框的关闭按钮,鼠标提示都可用absolute做。
e.g. 鼠标悬停显示提示

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
<style>
button {
  position: relative;
}

button span {
  position: absolute;
  border: 1px solid black;
  white-space: nowrap;
  bottom: calc(100% + 15px); /* 块高度 + 15px */
  left: 50%; /* 移动至宽度50%处 */
  transform: translateX(-50%); /* 居中对齐 */
}

button span{
  display: none; /* 未点击时隐藏 */
}
button:hover span{
  display: inline-block; /* 鼠标悬停时显示 */
}
</style>
</head>
<body>
  <div style="height:100px;"></div>
  <button>点击查看提示
    <span class="tips">我是一行提示</span>
  </button>
</body>
</html>

tips: 关于:hover 鼠标悬停在元素上时会触发。但只对可视客户端有效,在触摸屏上无效。

fixed:固定定位,基于viewport定位。 问题:并非永远基于viewport,如果父元素里含有transform属性,则fixed基于父元素而非viewport定位。 可用于做回到顶部按钮和烦死人的广告。 手机上的bug非常多最好不要使用。 sticky:粘滞定位,黏在哪里滚动之后还会位于相对的前方或者后方。支持性很差。
tips: 文字内容不准换行 添加css属性white-space

white-space: nowrap;

CSS 动画

动画:24帧 游戏:30帧 现在大部分显示器的最低刷新频率为60Hz,即每秒60帧。

setInterval()制作动画

setInterval()可被用于实现css动画,使用position: relative并改变其属性(比如left)。 e.g. html

<div id="demo"></div>

css

#demo {
  width: 100px;
  height: 100px;
  border: 1px solid red;
  position: relative;
  left:0;
}

js

var n=1;
var id = setInterval(() => {
  if (n<=200){
    demo.style.left=n+'px';
    n=n+1;
  }
  else{
    clearInterval(id);
  }
}, 1000/60);


**tips:关于停止setInterval()** > setInterval()在窗口和工作接口上提供的setInterval()方法重复调用函数或执行代码片段,每次调用之间有固定的时间延迟。它返回一个时间间隔ID,该ID唯一地标识时间间隔,因此您可以稍后通过调用clearInterval()来删除它。

因此可利用clearInterval()清除唯一的ID停止setInterval()

var id = setInterval(() => {
  if (condition){
    statements ...
  }
  else{
    clearInterval(id)
  }
}, 1000/60)

tips:paint flashing观察性能 develop tool中打开rendering 勾上Paint flashing,能观察到CSS是否重新渲染

transform做动画

html

<div id="demo"></div>

css

#demo {
  width: 100px;
  height: 100px;
  border: 1px solid red;
  transition: all is linear;
}

/* 设置transform动画 */
#demo.end {
  transform: translateX(200px);
}

js

setTimeout(()=>{
  demo.classList.add('end');
}, 3000);

transform制作的动画图形并非缓慢移动,而是急速闪现在目标位置。 transform触发的css渲染次数远远少于setInterval()

浏览器渲染原理

  1. 构建 DOM - HTML tree
  2. 构建 CSSOM - CSS tree
  3. 合并 DOM, CSSOM -> Render tree
  4. 根据渲染树构成 Layout (文档流,盒模型,计算大小、位置),形成线框。
  5. Paint, 绘制边框颜色,文字颜色,阴影等。
  6. Compose 根据层叠关系合成,展示画面。

执行js脚本 -> 构建style -> 形成layout -> 绘制页面 -> 合成最终画面

渲染的三种更新方式中,layout和paint可能会被省略。根据颜色和位置大小的改编决定哪种会被省略。

  • 完全更新:对布局位置的修改会触发(div.remove()),元素relayout
  • 跳过layout更新:修改背景颜色会触发,repaint + composite
  • 跳过layout + paint更新:元素位移(transform)会触发,composite。需要全屏查看,iframe有问题。
repaint(重绘)

repaint发生更改时,元素的外观被改变,且在没有改变布局的情况下发生,如改变outline,visibility,backgroundcolor,不会影响到dom结构渲染。

reflow(渲染)

与repaint区别就是他会影响到dom的结构渲染,同时他会触发repaint,他会改变他本身与所有父辈元素(祖先),这种开销是非常昂贵的,导致性能下降是必然的,页面元素越多效果越明显。 所以display:none才会产生reflow visibility:hidden只会出发repaint

常见触发

触发repaint

-color,hover引起的颜色,text-align等变化

触发reflow
  • width/height/border/margin/padding
  • 动画,display
  • appendChild等dom元素操作
  • font字体改变
  • background的修改,注意着字面上可能以为是重绘,但是浏览器确实回流了,经过浏览器厂家的优化,部分background的修改只触发repaint,当然IE不用考虑;
  • scroll页面
  • resize页面
  • 读取元素的属性offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE));

tips: 查看元素渲染 csstrigger.com 提供了所有css元素在不同浏览器上的渲染过程。

CSS优化

  • 渲染性能:Google开发者文档developers.google.com/web/fundame…
  • JS优化:使用 requestAnimationFrame()替代 setTimeout() 或者 setInterval()
  • CSS优化:使用 will-change 或者 translate属性

transform 用法

MDN文档有语法格式 developer.mozilla.org/zh-CN/docs/… transform属性均可组合使用。比如放大的同时位移。 #####translate 位移 X: 横轴 Y: 纵轴 Z: 从显示器到屏幕的距离。通过perspective属性设置视点。

transform: translate3d(x, y, z)
transform: translateX(x_value) translateY(y_value)
transform: translate(x_value, y_value)

/* 绝对居中的一种写法(IE不支持) */
top: 50%;
left: 50%;
transform: translate(-50%, -50%)
scale 缩放

倍数缩放

  • transform: scale(1.5) 整体放大1.5倍
  • scaleX(x_value), scaleY(y_value), scaleZ(z_value) X, Y, Z 按比缩放
  • scale3d(x_value, y_value, z_value) X, Y, Z三轴各自按比缩放
  • transform: scale(x_value, y_value) X轴,Y轴各自缩放
  • transform: scale(x_value, y_value, z_value) 相当于于scale3d函数,X, Y, Z三轴各自按比缩放
rotate 旋转
  • transform: rotate( deg | turn | rad )
  • transform: = rotate3d(x_value, y_value, z_value)
  • transform: rotateX( x_value )
  • transform: rotateY( y_value )
  • transform: rotateZ( z_value )
skew 倾斜
  • transform: skew(deg) 用法基本同上,xyz三轴均可。

transition 过渡

添加中间帧 transition: 属性 时长 过渡方式 延迟

  • all可以代表所有属性
  • 过渡方式: linear, ease, ease-in, ease-out, ease-in-out, cubic-bezier, step-start, step-end, steps
  • background颜色可以过渡
  • opacity透明度可以过渡 不适用的情况:
  • display: block => display: none 不显示则无结果。虽然看不见但位置还在。如果想要消失效果,使用visibility: visible => visibility: hidden

animation

标准写法: animation: 时长 | 过渡方式 | 延迟 | 次数 | 方向 | 填充模式 | 是否暂停 | 动画名

  • 百分数
#example{
  animation: time forwards identifier;
}
@keyframes identifier {
  0% { attributes;}
  66% { attributes;}
  100% { attributes;}
}
  • from to
#example{
  animation: time forwards identifier;
}
@keyframes identifier {
from { attributes;}
66% { attributes;}
to { attributes;}
}

forwards: 属于填充模式 让动画停在最后一帧。

回流 (Reflow)

当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

会导致回流的操作:

  • 页面首次渲染
  • 浏览器窗口大小发生改变
  • 元素尺寸或位置发生改变 -元素内容变化(文字数量或图片大小等等)
  • 元素字体大小变化
  • 添加或者删除可见的DOM元素
  • 激活CSS伪类(例如::hover)
  • 查询某些属性或调用某些方法

一些常用且会导致回流的属性和方法: clientWidth、clientHeight、clientTop、clientLeft offsetWidth、offsetHeight、offsetTop、offsetLeft scrollWidth、scrollHeight、scrollTop、scrollLeft scrollIntoView()、scrollIntoViewIfNeeded() getComputedStyle() getBoundingClientRect() scrollTo()

重绘 (Repaint)

当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。 性能影响 回流(reflow)比重绘(repaint)的代价要更高。 有时即使仅仅回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流。 现代浏览器会对频繁的回流或重绘操作进行优化: 浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。 当你访问以下属性或方法时,浏览器会立刻清空队列:

clientWidth、clientHeight、clientTop、clientLeft offsetWidth、offsetHeight、offsetTop、offsetLeft scrollWidth、scrollHeight、scrollTop、scrollLeft width、height getComputedStyle() getBoundingClientRect() 因为队列中可能会有影响到这些属性或方法返回值的操作,即使你希望获取的信息与队列中操作引发的改变无关,浏览器也会强行清空队列,确保你拿到的值是最精确的。

Reflow & Repaint 部分 引用自:juejin.cn/post/684490…

一颗小红心: