前端开发技巧-CSS Behavior


2018/5/6 frontend css

使用 overflow-scrolling 支持弹性滚动

要点:iOS 页面非 body 元素的滚动操作会非常卡(Android 不会出现此情况),通过 overflow-scrolling: touch 调用 Safari 原生滚动来支持弹性滚动,增加页面滚动的流畅度

场景:iOS 页面滚动

兼容:iOS 自带 -webkit-overflow-scrolling

body {
  -webkit-overflow-scrolling: touch;
}
.elem {
  overflow: auto;
}
1
2
3
4
5
6

使用 transform 启动 GPU 硬件加速

要点:有时执行动画可能会导致页面卡顿,可在特定元素中使用硬件加速来避免这个问题

场景:动画元素(绝对定位、同级中超过 6 个以上使用动画)

兼容:transform

.elem {
  transform: translate3d(0, 0, 0); /* translateZ(0)亦可 */
}
1
2
3

使用 attr()抓取 data-*

要点:在标签上自定义属性 data-*,通过 attr() 获取其内容赋值到 content

场景:提示框

兼容:data-*attr()

代码:在线演示

.tips {
	position: relative;
	margin-top: 10px;
	padding: 0 20px;
	border-radius: 10px;
	height: 40px;
	background-color: $purple;
	line-height: 40px;
	color: #fff;
	&::after {
		position: absolute;
		left: 0;
		top: 0;
		border-radius: 5px;
		width: 100%;
		height: 100%;
		background-color: rgba(#000, .5);
		opacity: 0;
		text-align: center;
		font-size: 12px;
		content: attr(data-msg);
		transition: all 300ms;
	}
	&:first-child {
		margin-top: 0;
	}
	&:hover::after {
		left: calc(100% + 20px);
		opacity: 1;
	}
	&[href]:empty::before {
		content: attr(href);
	}
	&[href]:empty:hover::after {
		display: none;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

使用:valid 和:invalid 校验表单

要点:<input>使用伪类 :valid:invalid 配合 pattern 校验表单输入的内容

场景:表单校验

兼容:pattern:valid:invalid

代码:在线演示

.form-validation {
	width: 500px;
	div {
		margin-top: 10px;
		&:first-child {
			margin-top: 0;
		}
	}
	label {
		display: block;
		padding-bottom: 5px;
		font-weight: bold;
		font-size: 16px;
	}
	input,
	textarea {
		display: block;
		padding: 0 20px;
		outline: none;
		border: 1px solid #ccc;
		width: 100%;
		height: 40px;
		caret-color: $blue;
		transition: all 300ms;
		&:valid {
			border-color: $green;
			box-shadow: inset 5px 0 0 $green;
		}
		&:invalid {
			border-color: $red;
			box-shadow: inset 5px 0 0 $red;
		}
	}
	textarea {
		height: 122px;
		resize: none;
		line-height: 30px;
		font-size: 16px;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

使用 pointer-events 禁用事件触发

要点:通过 pointer-events:none 禁用事件触发(默认事件、冒泡事件、鼠标事件、键盘事件等),相当于<button>disabled

场景:限时点击按钮(发送验证码倒计时)、事件冒泡禁用(多个元素重叠且自带事件、a 标签跳转)

兼容:pointer-events

代码:在线演示

.disabled-trigger {
	padding: 0 20px;
	border-radius: 10px;
	height: 40px;
	background-color: $purple;
	pointer-events: none;
	line-height: 40px;
	color: #fff;
}
1
2
3
4
5
6
7
8
9

使用+或~美化选项框

要点:<label>使用 +~ 配合 for 绑定 radiocheckbox 的选择行为

场景:选项框美化、选中项增加选中样式

兼容:+、~

代码:在线演示

.beauty-selection {
	display: flex;
	li {
		display: flex;
		align-items: center;
		margin-left: 20px;
		&:first-child {
			margin-left: 0;
		}
	}
	input:checked + label {
		background-color: $orange;
	}
	label {
		margin-right: 5px;
		padding: 2px;
		border: 1px solid $orange;
		border-radius: 100%;
		width: 18px;
		height: 18px;
		background-clip: content-box;
		cursor: pointer;
		transition: all 300ms;
		&:hover {
			border-color: $blue;
			background-color: $blue;
			box-shadow: 0 0 7px $blue;
		}
	}
	span {
		font-size: 16px;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

使用:focus-within 分发冒泡响应

要点:表单控件触发 focusblur 事件后往父元素进行冒泡,在父元素上通过 :focus-within 捕获该冒泡事件来设置样式

场景:登录注册弹框、表单校验、离屏导航、导航切换

兼容::focus-within:placeholder-shown

代码:在线演示

.bruce {
	background-color: #999;
}
.bubble-distribution {
	position: relative;
	margin-top: 50px;
	padding: 25px;
	border-radius: 2px;
	width: 320px;
	background-color: #fff;
	h3 {
		font-weight: bold;
		font-size: 16px;
		color: #333;
	}
	div {
		margin-top: 10px;
	}
	img {
		position: absolute;
		left: 50%;
		bottom: 100%;
		margin: 0 0 -20px -60px;
		width: 120px;
	}
	ul {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-top: 10px;
		height: 30px;
		line-height: 30px;
	}
	li {
		position: relative;
		width: 45%;
		transition: all 300ms;
		&:focus-within {
			background: linear-gradient(90deg, $blue 50%, transparent 0) repeat-x,
				linear-gradient(90deg, $blue 50%, transparent 0) repeat-x,
				linear-gradient(0deg, $blue 50%, transparent 0) repeat-y,
				linear-gradient(0deg, $blue 50%, transparent 0) repeat-y;
			background-position: 0 0, 0 100%, 0 0, 100% 0;
			background-size: 8px 1px, 8px 1px, 1px 8px, 1px 8px;
			animation: move 500ms infinite linear;
		}
	}
	input[type=text],
	input[type=password] {
		padding: 10px;
		outline: none;
		border: 1px solid #e9e9e9;
		border-radius: 2px;
		width: 100%;
		height: 40px;
		transition: all 300ms;
		&:focus:valid {
			border-color: $blue;
		}
		&:focus:invalid {
			border-color: $red;
		}
	}
	input[type=radio] {
		position: absolute;
		width: 0;
		height: 0;
		&:checked + label {
			border: 3px solid transparent;
			background-color: $blue;
			color: #fff;
		}
	}
	label {
		display: block;
		border-bottom: 1px solid #ccc;
		width: 100%;
		background-clip: padding-box;
		cursor: pointer;
		text-align: center;
		transition: all 300ms;
	}
	button {
		overflow: hidden;
		margin-top: 10px;
		outline: none;
		border: none;
		border-radius: 2px;
		width: 100%;
		height: 40px;
		background-color: $blue;
		cursor: pointer;
		color: #fff;
		transition: all 300ms;
	}
}
.accout,
.password,
.code {
	img {
		display: none;
		margin-bottom: -27px;
	}
	&:focus-within {
		img {
			display: block;
		}
		& ~ img {
			display: none;
		}
	}
}
.code {
	display: flex;
	justify-content: space-between;
	button {
		margin-top: 0;
	}
	input {
		&:not(:placeholder-shown) {
			width: 70%;
			& + button {
				width: 25%;
			}
		}
		&:placeholder-shown {
			width: 100%;
			& + button {
				width: 0;
				opacity: 0;
			}
		}
	}
}
@keyframes move {
	to {
		background-position: 6% 0, -6% 100%, 0 -6%, 100% 6%;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139

使用:hover 描绘鼠标跟随

要点:将整个页面等比划分成小的单元格,每个单元格监听 :hover,通过 :hover 触发单元格的样式变化来描绘鼠标运动轨迹

场景:鼠标跟随轨迹、水波纹、怪圈

兼容::hover

代码:在线演示

@function randomNum($max, $min: 0, $u: 1) {
	@return ($min + random($max)) * $u;
}

.mouse-following {
	display: flex;
	overflow: hidden;
	flex-wrap: wrap;
	height: 100%;
	cursor: pointer;
	li {
		position: relative;
		width: 30px;
		height: 30px;
		&::before {
			position: absolute;
			left: 0;
			right: 0;
			top: 0;
			bottom: 0;
			border-radius: 100%;
			background-color: transparent;
			content: "";
			transform: scale3d(.1, .1, 1);
			transition: all 500ms ease-in;
		}
		&:hover {
			&::before {
				transform: scale3d(1.8, 1.8, 1.8);
				transition: transform 0s;
			}
		}
		@for $i from 1 through 500 {
			&:nth-child(#{$i}):hover {
				&::before {
					background-color: rgba(randomNum(255), randomNum(255), randomNum(255), .8);
				}
			}
		}
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

使用 max-height 切换自动高度

要点:通过 max-height 定义收起的最小高度和展开的最大高度,设置两者间的过渡切换

场景:隐藏式子导航栏、悬浮式折叠面板

兼容:max-height

代码:在线演示

.auto-height {
	width: 300px;
	li {
		margin-top: 5px;
		cursor: pointer;
		&:first-child {
			margin-top: 0;
		}
		&:hover p {
			border-bottom-width: 1px;
			max-height: 600px;
		}
	}
	h3 {
		padding: 0 20px;
		height: 40px;
		background-color: $red;
		cursor: pointer;
		line-height: 40px;
		font-size: 16px;
		color: #fff;
	}
	p {
		overflow: hidden;
		padding: 0 20px;
		border: 1px solid $red;
		border-top: none;
		border-bottom-width: 0;
		max-height: 0;
		line-height: 30px;
		transition: all 500ms;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

使用 transform 模拟视差滚动

要点:通过 background-attachment: fixedtransform 让多层背景以不同的速度移动,形成立体的运动效果

场景:页面滚动、视差滚动文字阴影、视差滚动文字虚影

兼容:background-attachmenttransform

代码:在线演示

$bg: "https://yangzw.vip/static/codepen/bg.jpg";

.bruce {
	overflow: auto;
	perspective: 1px;
	transform-style: preserve-3d;
	p {
		height: 300px;
		line-height: 300px;
		text-align: center;
		font-size: 20px;
		color: $red;
	}
}
.parallax-scrolling {
	display: flex;
	justify-content: center;
	align-items: center;
	height: 1000px;
	background: url($bg) no-repeat center fixed;
	li {
		width: 500px;
		text-align: center;
		font-weight: bold;
		font-size: 60px;
		&:nth-child(1) {
			color: $red;
			transform: translateZ(-1px);
		}
		&:nth-child(2) {
			color: $blue;
			transform: translateZ(-2px);
		}
		&:nth-child(3) {
			color: $green;
			transform: translateZ(-3px);
		}
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

使用 animation-delay 保留动画起始帧

要点:通过 transform-delayanimation-delay 设置负值时延保留动画起始帧,让动画进入页面不用等待即可运行

场景:开场动画

兼容:transformanimation

代码:在线演示

.initial-keyframe {
	position: relative;
	width: 100px;
	height: 100px;
	li {
		position: absolute;
		border-radius: 100%;
		width: 100%;
		height: 100%;
		background-color: $green;
		transform: rotate(0) translate(-80px, 0);
		animation: rotate 3s linear infinite;
		&:nth-child(2) {
			animation-delay: -1s;
		}
		&:nth-child(3) {
			animation-delay: -2s;
		}
	}
}
@keyframes rotate {
	to {
		transform: rotate(1turn) translate(-80px, 0);
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

使用 resize 拉伸分栏

要点:通过 resize 设置横向自由拉伸来调整目标元素的宽度

场景:富文本编辑器、分栏阅读

兼容:resize

代码:在线演示

.stretching-column {
	overflow: hidden;
	border: 1px solid $blue;
	width: 600px;
	height: 300px;
	line-height: 20px;
	font-size: 16px;
	color: $orange;
	.left {
		overflow: hidden;
		float: left;
		position: relative;
		height: 100%;
	}
	.right {
		overflow: hidden;
		padding: 10px;
		height: 100%;
		background-color: #f0f0f0;
		word-break: break-all;
	}
}
.resize-bar {
	overflow: scroll;
	width: 200px;
	height: 100%;
	opacity: 0;
	resize: horizontal;
	&::-webkit-scrollbar {
		width: 200px;
		height: 100%;
	}
	&:hover,
	&:active {
		& ~ .resize-line {
			border-left: 1px dashed $blue;
		}
	}
}
.resize-line {
	position: absolute;
	right: 0;
	top: 0;
	bottom: 0;
	border-left: 1px solid #ccc;
	border-right: 2px solid #f0f0f0;
	pointer-events: none;
}
.resize-text {
	overflow-x: hidden;
	position: absolute;
	left: 0;
	right: 5px;
	top: 0;
	bottom: 0;
	padding: 10px;
	word-break: break-all;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

PS:本文整理自 https://juejin.im/post/5d4d0ec651882549594e7293 侵删。

上次更新: 12/4/2019, 9:50:01 AM