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语法检查:
- w3c css validator
- 编辑器自带纠错
border调试法:
- 给需要调试的元素第一行加上醒目border
border: 1px solid red; - 如果能够显示出,则该元素可以被匹配到,选择器未出错
- 将border下移,逐行检查,如果哪一行未能显示border,则前一行出错
- 问题解决删除border (类似js log调试法,脚本语言万岁)
练习素材: 1.模仿psd
- freepik -365psd
- 效果图 dribbble.com
- 商业网站
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;
}
相对而言border-box更好用
margin合并
上下合并,左右不合并
- 父子margin合并
- 可用padding,border挡住
- 可用overflow: hidden挡住
- 可用display: flex
- 兄弟margin合并
- 可用display: inline消除
基本单位
- px 像素
- em 相对字号的倍数 e.g.
font-size: 20px;
width: 3em;
则width为20px*3=60px
- % 百分比
- 整数
windows only 的选色/截图工具: snipaste sspai.com/item/83
color 颜色
- 关键词颜色 e.g. red 红,transparent 全透明
- 十六进制 e.g. #FF6600 淘宝专用色
- rgb, rgba e.g. rgb(255,0,127) 完全不透明 rgba(255,0,127,0.2) a的最大值1为完全不透明,最小值0为完全透明
- 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布局
布局分类
- 固定宽度布局 960px, 1000px, 1024px,电脑页面
- 不固定宽度布局。 主要靠文档流,原本就是自适应,不需要额外样式。 多半是手机页面布局。
- 响应式布局
怎样选择布局
Float布局 - 为IE准备
- 子元素加
float: left和width - 父元素加
.clearfixe.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
- 可以减半margin
e.g. 假设原margin-left: 10px
则在该行下增加
_margin-left: 5px;IE可识别并计算出需要的margin - 可以加
display: inline-block对抗bug
- 可以减半margin
e.g. 假设原margin-left: 10px
则在该行下增加
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为负数
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()
浏览器渲染原理
- 构建 DOM - HTML tree
- 构建 CSSOM - CSS tree
- 合并 DOM, CSSOM -> Render tree
- 根据渲染树构成 Layout (文档流,盒模型,计算大小、位置),形成线框。
- Paint, 绘制边框颜色,文字颜色,阴影等。
- 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…
一颗小红心:
- transform, transition and hover js.jirengu.com/hogucoluqo/…
- animation js.jirengu.com/mepakaraco/…