CSS
基础
选择器
- 标签选择器,如
div
- ID选择器,如
#root
- class选择器,如
.container
- 子代选择器,父子关系,如
div > p
- 后代选择器 ,可以是爷爷和孙子的关系,如
div p
- 相邻兄弟选择器,如
div + p
, 选择紧邻着div后面的p - 属性选择器,如
[type=input]
- 伪类选择器,如
:hover
、:first-child
、:nth-child()
、:first-of-type
、 - 通配符选择器,
*
优先级:!important
> inline selector
> id selector
> class selector
> tag selector
> *
> 浏览器默认样式 > 继承样式
常见的继承样式如font-size
、color
、visibility
等
display
block
如div
、h1~h6
、p
、header
等
- 元素独占一行,默认根据父元素计算出元素的宽度
- 可以手动设置元素
width
和height
inline
如a
、span
、img
等
- 元素不独占一行
- 不可以手动设置元素
width
和height
img
有点特殊,虽然它的display
为inline
,但它的表现更贴近inline-block
,比如它可以手动设置width
和height
属性
inline-block
如input
等,兼具了block
和inline
的特性
- 元素不独占一行
- 但可以手动设置元素
width
和height
盒模型
盒模型指的是元素由它的content、padding、border、margin
几个部分组成。
除此之外,元素的box-sizing
属性默认为content-box
,这意味此时当我们设置元素的width
,实际上是在设置content
的长度;我们可以把box-sizing
修改为border-box
,那么此时元素的width
表示content + padding + border
的长度
transition
.app {
transition-property: width;
transition-duration: 3s;
transition-timing-function: ease-in;
transition-delay: 1s;
}
animation
@keyframes anime {
from {
background: pink;
}
to {
background: yellow;
}
}
.app {
<!-- 动画名 -->
animation-name: anime;
<!-- 动画持续时间 -->
animation-duration: 3s;
<!-- 动画曲线-->
animation-timing-function: ease-in-out;
<!-- 延迟 -->
animation-delay: 1s;
<!-- 动画播放次数-->
animation-iteration-count: 2;
<!-- 动画是否在下一周期逆向地播放-->
animation-direction: alternate;
<!-- 动画是在运行还是暂停-->
animation-play-state: paused;
<!-- 动画的结束状态-->
animation-fill-mode: forwards;
}
文本与换行
对于浏览器的文本,不同语言的文本在换行时采用的规则不一样。根据换行时的行为差异,可以把文本分为两类:
- CJK文本,即中文、日文和韩文
- Non-CJK文本,比如我们用的最多的英文
在默认情况下,即
word-wrap: normal
,word-break: normal
,white-space: normal
时,CJK文本可以在任意2个字符间断行,而英文只能在空白符处断行。
<body>
<div>
<a>苹果</a>
<a>草莓</a>
<a>香蕉</a>
<a>橘子</a> <!-- 额外补充,如果设置成inline-block,也可以实现文本不分割的效果 -->
<br />
<a>aaa</a>
<a>bbb</a>
<a>ccc</a>
<a>ddd</a>
</div>
</body>
橘子一词可能被分割开成橘 子
苹果 草莓 香蕉 橘
子
ddd
一词不会被分割开成d dd
aaa bbb ccc
ddd
word-break
如果我们想要CJK文本表现的和非CJK文本一样或者想要非CJK文本表现和CJK文本一样要怎么办呢?
word-break
属性就是来处理这种情况。默认情况下word-break: normal
,CJK文本和非CJK应用自己的默认换行规则。设置为word-break: break-all
后,非CJK文本会应用CJK文本的换行规则,可以在任意位置断行。而设置word-break: keep-all
后,CJK文本会应用非CJK文本的换行规则,只能在空白处断行。
word-wrap
word-wrap
属性用来处理这样的情景:一个不可分割的字符串过长,超过容器盒的宽时应该如何处理?在默认情况下(word-wrap: normal
),字符串超出了容器盒的宽,不会断行。当设为word-wrap: break-word
时,过长的字符串会发生断行。
white-space
white-space
属性是用来设置针对空白符的处理规则。其中white-space: nowrap
会使文本中换行无效。这一规则优先于上面提到的规则。所以在white-space: nowrap
时,无论是设置了word-break: break-all
还是设置了word-wrap: break-word
,文本都不会换行。
object-fit
对于img
标签这种可替换元素来说,当我们不指定元素的宽高,元素的宽高将根据原图的宽高计算得出;当我们只指定元素的width
,会根据原图的宽高比例计算出height
;如果我们指定了元素的width
和height
但比例和原图比例不一致时,图片就会自适应的进行拉伸,此时object-fit
默认值为fill
我们可以通过修改object-fit
来调整图片适应宽高的策略。
object-fit: fill
填充,因此图片会被拉伸或压缩object-fit: cover
填充,同时保证图片比例不变,因此图片会被裁剪object-fit: contain
容纳图片,因此元素两侧会出现空白区域
background-clip
表示图片裁剪范围,默认值是border-box
,有意思的是我们可以把它的值设置为text
,即把背景裁剪到字体身上。
<style media="screen">
.gradient-text {
background: -webkit-linear-gradient(pink, red);
-webkit-background-clip: text;
color: transparent;
}
</style>
<p class="gradient-text">Gradient text</p>
clip-path
Flex
容器属性
.flex-container {
display: flex;
flex-direction: row;
/* 主轴的方向,默认row,从左往右 */
flex-wrap: nowrap;
/* 是 否换行,默认不换行*/
justify-content: center;
/* 主轴上的布局,默认flex-start */
align-items: center;
/* 交叉轴上的布局,默认值flex-start */
align-content: center;
/* 多条轴线的布局 */
}
项目属性
.flex-items {
order: 2;
/* 项目的order, 越大的越后面*/
flex-grow: 1;
/* 扩张比例,默认0,不占剩余空间 */
flex-shrink: 0;
/* 缩小比例,默认1,自动缩小*/
flex-basis: 200px;
/* 主轴上的宽度 */
flex: 1 0 200px;
/* 上面三条的缩写 */
align-self: flex-end;
/* 修改项目的交叉轴布局*/
}
Flex 搭配 margin
给Flex容器内的项目设置margin为auto,则margin会自动占据剩下的所有未分配空间。
<!-- 实现一个导航栏 -->
<ul class="g-nav">
<li>导航A</li>
<li>导航B</li>
<li>导航C</li>
<li>导航D</li>
<li class="g-login">登陆</li>
<li>注册</li>
</ul>
<style>
.g-nav {
display: flex;
padding: 0;
margin: 0;
list-style: none;
}
.g-nav li {
padding: 0 20px;
}
.g-login {
margin-left: auto;
}
</style>
Grid
Flex
是通用的一维布局方案,可以解决绝大多数布局问题。Grid
是二维布局方案,在某些场景下使用可能有奇效。
我们通常使用grid-template-rows
、grid-template-columns
来划分网格轨道,从而把项目分割成一个个的网格,同时可以使用grid-template-area
把多个不同网格用同一个符号标识。这三个属性的缩写为grid-template
。对于这样的网格,我们称之为显式网格。
某些时候,比如当实际的网格数量大于预设的显式数量,又或者当某个网格项被放置在显式网格之外,这时候就会自动生成新的网格轨道,这就是隐式网格。对于隐式网格我们可以使用grid-auto-row
、grid-auto-column
来指定网格轨道的宽高,还可以使用grid-auto-flow
控制网格的排序方式。
对于以上介绍的六个属性,我们可以使用grid
进行简写。它的值有三种写法:①和grid-template
一致,只用来表示显式网格。②grid-template-rows / [auto-flow && dense?] grid-auto-column
。③[auto-flow && dense?] grid-auto-row / grid-template-columns
。这里的auto-flow
指的是grid-auto-flow
的值,当auto-flow
写在/
号前面表示grid-auto-flow: row
,当auto-flow
写在/
号后面表示grid-auto-flow: column
。
CSS Module
形如xx.module.css
的文件通 常称为css模块。
.Root {
color: pink;
}
import style from './style.module.css'
function App() {
return <div className={style.Root}></div>
}
常见问题
水平垂直居中
一:absolute + margin-top
.outer {
position: relative
}
.inner {
width: 200px;
height: 200px;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -100px;
}
二:absolute + calc
.outer {
position: relative
}
.inner {
width: 200px;
height: 200px;
border-radius: 50%;
position: absolute;
top: calc(50% - 100px);
left: calc(50% - 100px);
}
以上两种方法通常用于绝对定位元素的宽高为固定值时,若宽高不确定,则不可使用。
三:absolute + transform
.outer {
position: relative
}
.inner {
width: 200px;
height: 200px;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
四:flex + margin: auto
.outer {
display: flex;
}
.inner {
width: 200px;
height: 200px;
border-radius: 50%;
margin: auto;
}
五:flex
.outer {
display: flex;
justify-content: center;
align-items: center;
}
BFC
BFC,也就是Block Formatting Contexts (块级格式化上下文)
明确地,它是一个独立的盒子,并且这个独立的盒子内部布局不受外界影响。
何时会触发BFC:
- 根元素
<html>
float
的值不为none
。position
的值不为relative
和static
。overflow
的值为auto
,scroll
或hidden
。display
的值为table-cell
,table-caption
,inline-block
中的任何一个。
作用
一:清除浮动(阻止高度塌陷)
<style>
.outer {
<!-- 使用overflow: auto;使outer元素成为BFC(触发outer元素的BFC)-->
overflow: auto;
}
.inner {
width: 200px;
height: 200px;
float: left;
}
</style>
<body>
<div class='outer'>
<div class='inner'>
</div>
</div>
</body>
二:外边距合并:同属一个BFC的相邻元素会发生外边距(margin)重叠。
<style>
.upper {
margin: 20px;
}
.lower {
margin: 20px;
}
.bfc {
overflow: auto;
}
</style>
<div class="upper"></div>
<div class="bfc">
<div class="lower">
</div>
</div>
三:阻止元素被浮动元素覆盖,可用来实现两列布局
<style>
.float {
float: left;
}
.content {
overflow: auto;
}
</style>
<div class="float"></div>
<div class="content"></div>
清除浮动
一:上述的BFC清除浮动
二:添加额外标签,应用clear: both
<style>
.float {
float: left;
}
.clear {
clear: both;
}
</style>
<div>
<div class="float">
</div>
<div class="clear">
</div>
</div>
三:使用伪元素,应用clear: both
<style>
.float {
float: left;
}
.clearfix:after {
content: "";
display: block;
clear: both;
}
</style>
<div class="clearfix">
<div class="float">
</div>
</div>
display/visibility/opacity
display: none,visibility: hidden, opacity: 0
三者的区别:
三个样式的作用都是使目标元素不可见,不过三个元素之间也是有区别的
-
结构上
display: none
会让目标元素不会被渲染进渲染树, 因此不占空间,而且不能点击。visibility: hidden
目标元素会被渲染进渲染树,因此占空间,但是不能点击。opacity: 0
目标元素会被渲染进渲染树,因此占空间,而且能点击。 -
继承上
display: none
作用于父元素后,子元素也不会被渲染(即使给子元素加了display: block
)visibility: hidden
作用于父元素后,子元素继承这个属性,也不可见;不过可以给子元素设置visibility: visible
使其可见。opacity: 0
作用于父元素后,虽然子元素 不会继承这个属性,但是子元素的透明度也会被影响,所以也不可见;而且不能通过给子元素设置opacity: 1
使其变成不透明。 -
性能上
display: none
会造成回流/重绘,性能影响大visibility: hidden
会造成元素内部的重绘,性能影响相对小opacity: 0
由于opacity
属性启用了GPU加速,性能最好
opacity
属性的补充
opacity
是不继承属性,父元素设置opacity,子元素并不会继承。但是因为该属性的特殊性(类似background
),父元素有了透明度,子元素的样式也会被影响。如果父元素设置opacity: 0.5
,子元素设置opacity: 0.5
,那么实际上子元素的透明度是0.5 * 0.5 = 0.25。
如果希望子元素不被父元素的透明度影响,我们可以使用background: rgba
代替opacity: 0
文本溢出
单行文本
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
多行文本
行内元素的间隙
两个inline
或inline-block
元素中会产生间隙。
<div>
<span>item</span>
<span>item</span>
</div>
可以看作是<span>item item</span>
解决方案:
-
将子元素标签的结束符和下一个标签的开始符写在同一行或把所有子标签写在同一行
<body>
<div class="a">
1
</div><div class="a">
2
</div>
</body> -
父元素设置font-size: 0; 子元素重新设置正确的font-size
其他
Better-Scroll
npm i @better-scroll/core -S
better-scroll
主要用于解决移动端的滚动需求。提供了让滚动元素显得有弹性、下拉加载或上拉加载等功能。
import BScroll from '@better-scroll/core'
function App() {
const myRef = useRef(null)
useEffect(() => {
const bs = new BScroll(myRef.current, {})
return () => {
bs.destroy()
}
}, [])
return (
<div className="wrapper" ref={myRef} >
<div className="content">
<div className="item">item1</div>
<div className="item">item3</div>
<div className="item">item4</div>
<div className="item">item2</div>
<div className="item">item5</div>
</div>
</div>
)
}
使用better-scroll
时,两大要点:
wrapper
使用overflow: hidden
content
的高或宽要大于wrapper
的,才会有滚动条和滚动效果
事件派发
bs.on('scrollStart', () => {}) // 开始滚动时触发
bs.on('scroll', () => {}) // 滚动过程中持续触发
bs.on('scrollEnd', () => {}) // 结束滚动时触发
其中scroll
由于会持续触发,可能对性能产生影响,所以默认情况下scroll
事件不会触发。
我们可以设置probeType
配置项来改变该行为,比如probeType: 3
来使任何时候都派发scroll
事件。
new BScroll(el, {
probeType: 3
})