CSS SECRETS

引言

编码技巧

  • currentColor 文本的颜色

背景与边框

半透明边框


1
2
3
4
5
6
div {
padding: 50px;
border: 10px solid rgba(255,255,255,0.5);
background: red;
background-clip: padding-box; // 保留padding的背景
}

多重边框

box-shadow

1
box-shadow: 0 0 0 10px #655, 0 0 0 20px red;
  • 不会影响布局,可通过内边距或外边距来模拟
  • 不会影响鼠标事件,可以通过inset关键字加上内边距来实现
  • 只能产生实线

outline

  • 可以通过outline-offset来指定与边缘的距离,可以为负值
  • 没有圆角

灵活的背景定位

background-position方案

1
2
background: url(***) no-repeat bottom right red; /* 回退方案 */
background-position: right 10px bottom 10px;

background-origin + padding方案

1
2
3
padding: 10px;
background: url(***) no-repeat red;
background-origin: content-box; /* border-box padding-box(默认) */

calc()

1
background-position: calc(100% - 20px) calc(100% - 10px);

边框内圆角


1
2
3
4
5
background: tan;
border-radius: .8em;
padding: 1em;
box-shadow: 0 0 0 .6em #655; // 可以根据border-radius计算得到
outline: .6em solid #655;

条纹背景


比较复杂,看书比较好理解

另外,这个:
https://hugogiraudel.com/2013/02/04/css-gradients/#a-few-things-about-linear-gradients

1
2
background: linear-gradient(#fb3 33.3%, blue 0, blue 66.7%, red 0); /* 10px:10px:10px 最后面的30%可以写为0*/
background-size: 100% 30px;
1
2
3
4
5
background: #58a;
background-image: repeating-linear-gradient(30deg,
hsla(0, 0%, 100%, .1),
hsla(0, 0%, 100%, .1) 15px,
transparent 0, transparent 30px);

复杂的背景图案



1
2
3
4
5
6
/* 波点 */
background-image:
radial-gradient(tan 30%, transparent 0),
radial-gradient(tan 30%, transparent 0);
background-size: 30px 30px;
background-position: 0 0, 15px 15px;


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 棋盘 */
background-image:
linear-gradient(45deg, tan 25%, transparent 0),
linear-gradient(45deg, transparent 75%, red 0),
linear-gradient(45deg, blue 25%, transparent 0),
linear-gradient(45deg, transparent 75%, green 0);
background-size: 30px 30px;
background-position: 0 0, 15px 15px, 15px 15px, 0px 0px;

or

background-image:
linear-gradient(45deg, tan 25%, transparent 0, transparent 75%, tan 0),
linear-gradient(45deg, blue 25%, transparent 0, transparent 75%, blue 0);
background-size: 30px 30px;
background-position: 0 0, 15px 15px;

伪随机背景

“蝉原则”,质数的思想

连续的图像边框


1
2
3
4
5
6
7
8
/* 老式信封样式边框 */
background: linear-gradient(white, white) padding-box,
repeating-linear-gradient(-45deg,
red 0, red 12.5%,
transparent 0, transparent 25%,
#58a 0, #58a 37.5%,
transparent 0, transparent 50%) 0 / 5em 5em;
background-origin: border-box;

1
2
3
4
5
6
7
8
9
10
11
12
/* 蚂蚁行军边框 */
@keyframes ants {
to {
background-position: 100%;
}
}
background: linear-gradient(white, white) padding-box,
repeating-linear-gradient(-45deg,
black 0, black 25%,
white 0, white 50%) 0 / 0.5em 0.5em;
background-origin: border-box;
animation: ants 12s linear infinite;
1
2
3
4
5
6
7
/* 脚注 */
.footnote {
border-top: .15em solid transparent;
border-image: 100% 0 0 linear-gradient(90deg, currentColor 4em, transparent 0);
padding-top: .5em;
font: 220%/1.4 Baskerville, Palatino, serif;
}

形状

自适应的椭圆

1
2
/* 半椭圆 */
border-radius: 50% / 100% 100% 0 0;

平行四边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
button  {
width: 200px;
height: 100px;
position: relative;
background: transparent;
border: none;
}
button::before {
content: '';
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
z-index: -1;
background: #58a;
transform: skew(45deg);
}

菱形图片


1
2
3
4
5
6
7
8
9
10
11
12
.picture {
margin: 200px auto;
width: 155px;
height: 155px;
transform: rotate(45deg);
overflow: hidden;
border: 1px solid gray;
}
.picture > img {
max-width: 100%;
transform: rotate(-45deg) scale(1.42);
}

更好的方案

1
2
3
4
5
6
7
img:hover {
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
img {
transition: 1s clip-path;
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}

切角效果

四个角的切角效果

1
2
3
4
5
6
7
8
background: #58a;
background:
linear-gradient(135deg, transparent 15px, #58a 0) top left,
linear-gradient(-135deg, transparent 15px, #58a 0) top right,
linear-gradient(-45deg, transparent 15px, #58a 0) bottom right,
linear-gradient(45deg, transparent 15px, #58a 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;

内凹圆角

1
2
3
4
5
6
7
background:
radial-gradient(circle at top left, transparent 15px, #58a 0) top left,
radial-gradient(circle at top right, transparent 15px, #58a 0) top right,
radial-gradient(circle at bottom left, transparent 15px, #58a 0) bottom left,
radial-gradient(circle at bottom right, transparent 15px, #58a 0) bottom right;
background-size: 50% 50%;
background-repeat: no-repeat;

svg + border-image 的方案

1
2
3
4
5
6
7
8
9
background: #58a;
background-clip: padding-box;
border: 15px solid #58a;
/* 1对应svg文件的坐标系统,可以用33.4% */
border-image: 1 url('data:image/svg+xml,\
<svg xmlns="http://www.w3.org/2000/svg"\
width="3" height="3" fill="%2358a">\
<polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2"/>\
</svg>')

裁切路径方案

1
2
3
4
5
clip-path: polygon(
20px 0, calc(100% - 20px) 0, 100% 20px,
100% calc(100% - 20px), calc(100% - 20px) 100%,
20px 100%, 0 calc(100% - 20px), 0 20px
);

梯形标签页


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
div::before {
content: '';
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
z-index: -1;
background: #ccc;
background-image: linear-gradient(hsla(0, 0%, 100%, .6), hsla(0, 0%, 100%, 0));
border: 1px solid rgba(0, 0, 0, .4);
border-bottom: none;
border-radius: 1em 1em 0 0;
box-shadow: 0 .15em white inset;
}

#div1:before {
transform: perspective(.5em) scaleY(2) rotateX(5deg);
transform-origin: bottom;
}

#div2:before {
transform: perspective(0.5em) scaleY(2) rotateX(5deg);
transform-origin: bottom left;
}

#div3:before {
transform: perspective(0.5em) scaleY(2) rotateX(5deg);
transform-origin: bottom right;
}

饼图

一个饼图动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@keyframes spin {
to {transform: rotate(.5turn)}
}
@keyframes bg {
50% {background: #655}
}
.pie {
width: 100px;
height: 100px;
border-radius: 50%;
background: yellowgreen;
background-image: linear-gradient(to right, transparent 50%, #655 0);
}
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: yellowgreen;
transform-origin: left;
animation: spin 3s linear infinite,
bg 6s step-end infinite;
}

各种比率的饼图

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
<!--五分之一的饼图 因为20/50/2-->
<div class="pie" style="animation-delay: -20s"></div>

@keyframes spin {
to {transform: rotate(.5turn)}
}
@keyframes bg {
50% {background: #655}
}
.pie {
width: 100px;
height: 100px;
border-radius: 50%;
background: yellowgreen;
background-image: linear-gradient(to right, transparent 50%, #655 0);
}
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: yellowgreen;
transform-origin: left;
animation: spin 50s linear infinite,
bg 100s step-end infinite;
animation-play-state: paused;
animation-delay: inherit;
}

SVG解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<svg viewBox="0 0 32 32">
<!--半径为16的圆周长约为100-->
<circle r="16" cx="16" cy="16" />
</svg>

@keyframes fillup {
to {
stroke-dasharray: 158 158;
}
}
svg {
width: 200px;
height: 200px;
transform: rotate(-90deg);
background: yellowgreen;
border-radius: 50%;
}
circle {
fill: yellowgreen;
stroke: #655;
stroke-width: 32;
stroke-dasharray: 0 158;
animation: fillup 5s linear infinite;
}

视觉效果

单侧投影

1
box-shadow: 0px 5px 4px -4px rgba(0,0,0,.5);

邻边投影

1
box-shadow: 3px 3px 4px -2px rgba(0,0,0,.5);

两侧投影

1
2
box-shadow: 6px 0 4px -2px rgba(0,0,0,.5),
-6px 0 4px -2px rgba(0,0,0,.5);

不规则投影

1
filter: drop-shadow(3px 3px 4px #000);
  • 可以用到伪元素,边框等
  • 文字也会被打上投影,且不会受text-shadow的影响

染色效果

1
2
3
4
5
6
7
8
img {
transition: .5s filter;
filter: sepia(1) saturate(4) ;
}
img:hover,
img:focus {
filter: none;
}

基于混合模式的方案
luminosity: 保留上层元素的HSL亮度信息,从下层吸取色相和饱和度信息

1
2
3
4
5
6
7
8
9
10
11
<a>
<img src="./cat.png" alt="">
</a>

a {
display: inline-block;
background: hsl(335, 100%, 50%);
}
img {
mix-blend-mode: luminosity;
}

1
2
3
4
5
6
7
8
9
10
11
.tinted-image {
width: 640px;
height: 440px;
background-size: cover;
background-color: hsl(335, 100%, 50%);
background-blend-mode: luminosity;
transition: .5s background-color;
}
.tinted-image:hover {
background-color: transparent;
}

毛玻璃效果

1
filter: blur(20px);

折角效果

1
2
3
4
5
6
7
8
9
10
11
div {
background: #58a;
width: 300px;
height: 200px;
background:
linear-gradient(to left bottom,
transparent 50%, rgba(0, 0, 0, .4) 0)
no-repeat 100% 0 / 2em 2em,
linear-gradient(-135deg,
transparent 1.41em, #58a 0); /* 这里的2em是沿着渐变轴的所以要改成1.41 */
}

30度的折角呢?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
div {
position: relative;
background: #58a;
width: 300px;
height: 200px;
border-radius: .5em;
background:
linear-gradient(-150deg,
transparent 1.5em, #58a 0);
}
div::before {
content: '';
position: absolute;
top: 0;
right: 0;
background: linear-gradient(to left bottom,
transparent 50%, rgba(0, 0, 0, .2) 0, rgba(0, 0, 0, .4)) 100% 0 no-repeat;
width: 1.73em;
height: 3em;
transform: translateY(-1.3em) rotate(-30deg);
transform-origin: bottom right;
border-bottom-left-radius: inherit;
box-shadow: -.2em .2em .3em -.1em rgba(0, 0, 0, .2);
}

字体排印

插入换行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
dt, dd {
display: inline;
}
dd {
margin: 0;
font-weight: bold;
}
dd + dt::before {
content: '\A';
white-space: pre;
}
dd + dd::before {
content: ', ';
font-weight: normal;
}

<dl>
<dt>Name:</dt>
<dd>Lea Verou</dd>
<dt>Email:</dt>
<dd>Verou@qq.com</dd><dd>youxingzhi@qq.com</dd>
<dt>Location:</dt>
<dd>Earth</dd>
</dl>

文本行的斑马条纹


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pre {
padding: .5em;
line-height: 1.5;
background: beige;
background-image: linear-gradient(rgba(0,0,0,.2) 50%, transparent 0);
background-size: auto 3em;
background-origin: content-box;
}

<pre>
while (true) {
var d = new Date();
if (d.getDate() == 1 && d.getMonth() == 3) {
alert('ddd')
}
}
</pre>

调整tab的宽度

1
tab-size: 2

华丽的&符号


1
2
3
4
5
6
7
8
9
10
11
@font-face {
font-family: Ampersand;
src: local('Baskerville-Italic'),
local('GoudyOldStyleT-Italic'),
local('Palatino-Italic'),
local('BookAntiqua-Italic');
unicode-range: U+26; /* '&'.charCodeAt(0).toString(16) => 26 */
}
h1 {
font-family: Ampersand, Helvetica, sans-serif;
}

自定义下划线


1
2
3
4
5
6
7
8
9
10
a[href] {
text-decoration: none;
font-size: 60px;
/*background: linear-gradient(gray, gray) no-repeat;*/
background: linear-gradient(90deg, gray 66%, transparent 0) repeat-x; /* 虚线 */
background-repeat: repeat-x;
background-size: .2em 1px;
background-position: 0 1.15em;
text-shadow: .05em 0 white, -.05em 0 white; /* 不让下划线穿过字母 */
}

现实中的文字效果

凸版印刷效果

  1. 深色背景,浅色字体

给文字顶部加深色投影:text-shadow: 0 -1px 1px black

  1. 浅色背景,深色字体

给文字底部加浅色投影:text-shadow: 0 1px 1px white

空心字效果

1
2
3
4
5
6
7
8
9
div {
font-size: 100px;
width: 300px;
height: 200px;
background-color: deeppink;
color: white;
text-shadow: 1px 1px black, -1px -1px black,
1px -1px black, -1px 1px black;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div>
<svg width="2em" height="1.2em">
<use xlink:href="#css"/>
<text id="css" y="1em">CSS</text>
</svg>
</div>

div {
color: white;
font-size: 100px;
}
div text {
fill: currentColor;
}
div use {
stroke: black;
stroke-width: 6;
stroke-linejoin: round;
}

文字外发光效果

1
2
3
4
5
6
7
8
9
div {
font-size: 100px;
background: #203;
color: #ffc;
transition: 1s;
}
div:hover {
text-shadow: 0 0 .1em, 0 0 .3em;
}

文字凸起效果


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
button {
outline: none;
border-radius: 20px;
border: none;
font-size: 100px;
background: hsl(204, 50%, 60%);
color: white;
box-shadow: 0 1px hsl(204, 50%, 60%),
0 2px hsl(204, 50%, 55%),
0 3px hsl(204, 50%, 50%),
0 4px hsl(204, 50%, 45%),
0 5px hsl(204, 50%, 40%),
0 5px 10px black;
text-shadow: 0 1px hsl(0, 0%, 85%),
0 2px hsl(0, 0%, 80%),
0 3px hsl(0, 0%, 75%),
0 4px hsl(0, 0%, 70%),
0 5px hsl(0, 0%, 65%),
0 5px 10px black;
}
button:active, button:focus {
box-shadow: none;
text-shadow: none;
}

@mixin test-3d($color: white, $depth: 5) {
$shadows: ();
$shadow-color: $color;

@for $i from 1 through $depth {
$shadow-color: darken($shadow-color, 10%);
$shadows: append($shadows, 0 ($i * 1px) $shadow-color, comma);
}

color: $color;
text-shadow: append($shadows,
0 ($depth * 1px) 10px black, comma);
}

环形文字


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
.circular {
width: 400px;
height: 400px;
margin: 400px auto;
}
.circular path {
fill: none;
}
.circular svg {
overflow: visible;
}

<div class="circular">
<svg viewBox="0 0 100 100">
<!--
M 050 移动到点(0,50)
a 50,50 0 1,1 0,1 以当前所在的这个点为起点,以当前点右侧 0 单位、下方 1 单位的那个点为终点,画一段圆弧。
这段圆弧的水平 半径和垂直半径都必须是 50。如果存在两种可能的圆弧度数,选择 度数较大的那一种;
同时,如果存在两种可能的圆弧方向,选择画 在这两个点右侧的那一种,而不是左侧的
z 闭合
-->
<path d="M 0,50 a 50,50 0 1,1 0,1 z" id="circle" />
<text>
<textPath xlink:href="#circle">
circular reasoning works because
</textPath>
</text>
</svg>
</div>

用户体验

选用合适的鼠标光标

  • 禁用 cursor: not-allowed
  • 隐藏 cursor: none

扩大可点击区域

  • 利用边框
1
2
border: 10px solid trasparent;
background-clip: padding-box; /* 防止背景扩张到边框 */
  • 利用伪元素
    1
    2
    3
    4
    5
    6
    button::before {
    content: '';
    position: absolute;
    top: -10px; right: -10px;
    bottom: -10px; left: -10px;
    }

自定义复选框

  • 自定义复选框/单选框
  • 开关式按钮
    利用label,具体略

滚动提示

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
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
</ul>

ul {
overflow: auto;
width: 10em;
height: 8em;
padding: .3em .5em;
border: 1px solid silver;
background:
linear-gradient(white, hsla(0,0%,100%,0)),
radial-gradient(at 50% 0, rgba(0,0,0,.2),
transparent 70%);
background-repeat: no-repeat;
background-size: 100% 50px, 100% 15px;
background-attachment: local, scroll;
}

交互式的图片对比控件

  1. resize方案

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
img {
user-select: none;
}
.image-slider {
position: relative;
display: inline-block;
}
.image-slider > div {
position: absolute;
top: 0; bottom: 0; left: 0; right: 0;
width: 50%;
max-width: 100%;
overflow: hidden;
resize: horizontal;
}
.image-slider > div::before {
content: '';
position: absolute;
bottom: 0; right: 0;
width: 12px; height: 12px;
background: white;
cursor: ew-resize;
padding: 5px;
background: linear-gradient(-45deg, white 50%, transparent 0);
background-clip: content-box;
}
.image-slider img {
display: block;
}

<div class="image-slider">
<div>
<img src="cat.png" alt="">
</div>
<img src="cat-after.png" alt="">
</div>
  1. js方案
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
img {
user-select: none;
}
.image-slider {
position: relative;
display: inline-block;
}
.image-slider > div {
position: absolute;
top: 0; bottom: 0; left: 0; right: 0;
width: 50%;
overflow: hidden;
}
.image-slider img {
display: block;
}
.image-slider input {
position: absolute;
left: 0; bottom: 10px;
width: 100%;
margin: 0;
filter: contrast(.5);
mix-blend-mode: luminosity;
}

<div class="image-slider">
<img src="cat.png" alt="">
<img src="cat-after.png" alt="">
</div>

var $$ = function (sel) {
return document.querySelectorAll(sel)
}
$$('.image-slider').forEach(function (slider) {
var div = document.createElement('div')
var img = slider.querySelector('img')
slider.insertBefore(div, img)
div.appendChild(img)

var range = document.createElement('input')
range.type = 'range'
range.oninput = function () {
div.style.width = this.value + '%'
}
slider.appendChild(range)
})

结构与布局

自适应内部元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
figure {
max-width: 300px;
border: 1px solid gray;
width: min-content; /* 解析为这个容器内部最大的不可断行元素的宽度 */
margin: auto;
}
figure > img {
max-width: inherit;
}

<p>Some text [...]</p>
<figure>
<img src="cat.png" alt="">
<figcaption>
The great sir adam catlace was named after countess ada lovelace, the first programmer
</figcaption>
</figure>
<p>More text [...]</p>

精确控制表格列宽

关于table几个重要的属性

1
2
3
table-layout: fixed; /* 可以精确控制单元格的宽度 */
border-collapse: collapse; /* 单元格的边框进行合并 */
border-spacing: 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
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
li {
list-style: none;
width: 100px;
height: 100px;
background-color: gray;
display: inline-block;
}

/*
li:first-child:nth-last-child(4) 即是第一个又是倒数第四个
li:first-child:nth-last-child(4) ~ li 它的所有后代li元素节点
*/
li:first-child:nth-last-child(4),
li:first-child:nth-last-child(4) ~ li {
background-color: orange;
}

/* scss写法如下 */
@mixin n-items($n) {
&:first-child:nth-last-child(#{$n}),
&:first-child:nth-last-child(#{$n}) ~ & {
@content;
}
}

li {
@include n-items(4) {
background-color: yellow;
}
}


<ul>
<li></li>
<li></li>
<li></li>
</ul>

<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>

<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>

同理,可以利用这个技巧来实现列表项的总数大于等于4时选中所有列表:

1
2
3
4
li:first-child:nth-last-child(n+4),
li:first-child:nth-last-child(n+4) ~ li {
background-color: orange;
}

或者,当列表项为2~6时,选中整个列表:

1
2
3
4
li:first-child:nth-last-child(n+2):nth-last-child(-n+6),
li:first-child:nth-last-child(n+2):nth-last-child(-n+6) ~ li {
background-color: orange;
}

满幅的背景,定宽的内容

一般做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<footer>
<div class="wrapper">
<!-- 页脚内容 -->
</div>
</footer>

footer {
background: #333;
}

.wrapper {
max-width: 900px;
margin: 1em auto;
}

更加简单的方法:

1
2
3
4
5
6
7
8
9
<footer>
<!-- 页脚内容 -->
</footer>

footer {
padding: 1em; /* 回退 */
padding: 1em calc(50% - 450px);
background: red;
}

垂直居中

  1. 基于绝对定位的方法

  2. 基于视口单位的解决方案

只适用于视口居中,如果main的父元素出现了滚动条,则不适合

1
2
3
4
5
6
main {
width: 18em;
background-color: red;
margin: 50vh auto 0;
transform: translateY(-50%);
}
  1. flexbox
1
2
3
4
5
6
7
8
9
body {
display: flex;
min-height: 100vh;
margin: 0;
}

main {
margin: auto;
}

紧贴底部的页脚

参考:

https://css-tricks.com/couple-takes-sticky-footer/

  1. 内容底部负边距
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.wrapper {
min-height: 100%;

/* Equal to height of footer */
/* But also accounting for potential margin-bottom of last child */
margin-bottom: -50px;
}
.footer, .push {
height: 50px;
}

<div class="wrapper">
<!-- 内容过多时用这个来占位 -->
<div class="push"></div>
</div>
<footer class="footer">footer</footer>
  1. 页脚上部负边距
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.content {
min-height: 100%;
}
.content-inside {
padding-bottom: 50px;
}
.footer {
height: 50px;
margin-top: -50px;
}

<div class="content">
<div class="content-inside">
content
</div>
</div>
<footer class="footer"></footer>
  1. calc

局限:对容器中的布局不适合

1
2
3
4
5
6
7
8
9
10
11
<div class="content">
content
</div>
<footer class="footer">footer</footer>

.content {
min-height: calc(100vh - 50px);
}
.footer {
height: 50px;
}
  1. flexbox
1
2
3
4
5
6
7
8
9
10
11
12
body {
display: flex;
flex-direction: column;
}
.content {
flex: 1 0 auto;
}

<div class="content">
content
</div>
<footer class="footer"></footer>

过渡与动画

缓动效果

提示:

  1. 对取auto值的height属性进行动画效果不生效时可以使用max-height

  2. transition: .5s height, .8s .5s width

参考:

贝塞尔曲线扫盲

CSS3动画那么强,requestAnimationFrame还有毛线用?

缓动提示框:

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
label {
position: relative;
}
input:not(:focus) + .callout {
transform: scale(0);
transition-timing-function: ease; /* 防止 scale(1) => scale(0) 根据贝塞尔曲线会计算出 scale(-0.1)的值 */
transition-duration: .25s; /*消失的动画快一点*/
}
.callout {
position: absolute;
background-color: orange;
width: 200px;
padding: 10px;
border-radius: 4px;
top: 120%;
left: 0;
transition: .5s cubic-bezier(.25, .1, .3, 1.5);
transform-origin: 1.4em -.4em;
}

<label for="">
<input type="text">
<span class="callout">
Only letters, numbers, underscores(_) and hyphens(-) allowed!
</span>
</label>

逐帧动画

闪烁效果

animation-direction

  • 反转循环周期,同时反转调整函数
  • reverse 反转所有
  • alternate 反转偶数个
  • alternate-reverse 反转奇数个

1
2
3
4
5
6
7
8
@keyframes blink-smooth {
to {
color: transparent;
}
}
.highlight {
animation: 1s blink-smooth 3 alternate;
}

如果不想要平滑的过渡,可以使用steps

1
2
3
4
5
6
7
8
@keyframes blink-smooth {
50% {
color: transparent;
}
}
.highlight {
animation: 1s blink-smooth 3 steps(1);
}

打字动画

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
@keyframes typing {
from { width:0 }
}
@keyframes caret {
50% { border-color: currentColor; }
}
h1 {
/*必须为等宽字体*/
font-family: Monaco;
/*width: 15ch; !* 0 这个字符的宽度,如果是等宽字体比较有用*!*/
border-right: .05em solid transparent;
animation: typing 4s steps(1) infinite,
caret 1s steps(1) infinite;
white-space: nowrap;
overflow: hidden;
}

<h1>CSS is awesome!</h1>
<script>
document.querySelectorAll('h1').forEach(function (h1) {
var len = h1.textContent.length, s = h1.style
s.width = len + 'ch'
s.animationTimingFunction = 'steps('+len+'),steps(1)'
})
</script>

状态平滑的动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@keyframes panoramic {
to {
background-position: 100% 0;
}
}
div {
width: 150px;
height: 150px;
background: url("long_pic.png");
background-size: auto 100%;
animation: panoramic 1s linear infinite alternate;
animation-play-state: paused; /* 动画暂停 */
}
div:hover, div:focus {
animation-play-state: running; /* 动画运行 */
}

沿环形路径平移的动画

下列代码可以实现基本需求,但是头像也倒过来了,有什么办法可以解决呢

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
@keyframes spin {
to {
transform: rotate(1turn);
}
}

.path {
box-sizing: border-box;
/*padding: 10px;*/
width: 300px;
height: 300px;
border-radius: 50%;
background-color: orange;
text-align: center;
}

.avatar {
width: 50px;
height: 50px;
border-radius: 50%;
animation: spin 3s infinite linear;
transform-origin: 50% 150px;
}

<div class="path">
<img src="1.png" class="avatar" alt="">
</div>

利用辅助元素

  1. 利用相反动画抵消
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
@keyframes spin {
to {
transform: rotate(1turn);
}
}
@keyframes spin-reverse {
from {
transform: rotate(1turn);
}
}

.avatar {
display: inline-block;
width: 50px;
height: 50px;
border-radius: 50%;
animation: spin 3s infinite linear;
transform-origin: 50% 150px;
}
.avatar img {
width: 100%;
height: 100%;
border-radius: 50%;
animation: inherit;
animation-name: spin-reverse; /* 抵消外层动画 */
}

<div class="path">
<div class="avatar">
<img src="1.png">
</div>
</div>
  1. 利用animation-direction
    1
    2
    3
    4
    5
    .avatar img {
    ...
    animation: inherit;
    animation-direction: reverse; /* 抵消外层动画 */
    }

不添加元素

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
@keyframes spin {
from {
transform:
/*等于以50%, 150px为transform-origin旋转*/
translate(50%, 150px)
rotate(0turn)
translate(-50%, -150px)
/*等于以50%,50%为transform-origin旋转*/
translate(50%,50%)
rotate(1turn)
translate(-50%,-50%)
}
to {
transform:
translate(50%, 150px)
rotate(1turn)
translate(-50%, -150px)

translate(50%, 50%)
rotate(0turn)
translate(-50%, -50%);
}
}

.avatar {
display: inline-block;
width: 50px;
height: 50px;
border-radius: 50%;
animation: spin 3s infinite linear;
}

进一步简化:

表示不理解!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@keyframes spin {
from {
transform:
translateY(150px)
translateY(-50%)
rotate(0turn)
translateY(-150px)
translateY(50%)
rotate(1turn);

}
to {
transform:
translateY(150px)
translateY(-50%)
rotate(1turn)
translateY(-150px)
translateY(50%)
rotate(0turn);
}
}