《CSS 揭秘》备忘录

笔记和思考有一定个人向,如有错误敬请指出,笔记的目录会尽量和书本目录保持一致。

Let’s go!

关于本书

浏览器支持与回退机制

浏览器兼容性查询网站:

一些早期浏览器可能需要加上前缀才能支持某些特性。不同浏览器不同的特性支持给开发带来很多麻烦,不过依托 Autoprefixer,我们现在不需要再担心这些了。

background: -moz-linear-gradient(90deg, #ff0, #f00);
background: -o-linear-gradient(90deg, #ff0, #f00);
background: -webkit-linear-gradient(90deg, #ff0, #f00);
background: linear-gradient(90deg, #ff0, #f00);

回退机制:可以确保网站不会在低版本浏览器挂掉,只是看起来没那么炫。

/* 添加实色,取渐变色中间色值 */
background: rgb(255, 128, 0);
background: linear-gradient(90deg, #ff0, #f00);

引言

Web 标准:是敌还是友

标准的制定过程

  1. 编辑草案(ED)
  2. 首个公开草案(FPWD)
  3. 工作草案(WD)
  4. 候选推荐草案(CR)
  5. 提名推荐草案(PR)
  6. 正式推荐草案(REC)

CSS 编码技巧

尽量减少重复代码

  • 尽量减少重复代码。
  • 代码可维护性的最大要素:尽量减少改动时要编辑的地方
  • 当某些值互相依赖时,应该把它们相互关系用代码表达出来。
font-size: 12px;
line-height: 2; /* 24px */
  • 代码易维护代码量少有时不可兼得,需自行把控。
border-width: 10px;
border-left-width: 0;
  • currentColor:解析为 color 属性的值。是很多 CSS 属性的初始值(border-color/outline-color/text-shadow/box-shadow)
.currentColor {
border: 1px solid;
color: #f00;
}
红色边框!
  • inherit:继承。可用于任何 CSS 属性中,总是绑定到父元素的计算值(伪元素绑定至宿主元素)。
.callout {
position: relative;
width: 100px;
background: #eee;
border: 1px solid #aaa;
padding: 5px;
}
.callout::before {
content: '';
position: absolute;
top: -1px;
left: 10px;
padding: 5px;
background: inherit;
border: inherit;
border-right: 0;
border-bottom: 0;
transform: translateY(-50%) rotate(45deg);
}
小箭头的样式完美继承

相信你的眼睛,而不是数字

有时精准的尺度看起来不会那么精准,完美垂直居中的设计会感觉并不完全居中。这种视觉上的差距普遍存在,可以针对性调整。(垂直居中略向上偏移、文本容器上下内边距调小)

关于响应式网页设计

媒体查询是实现响应式网页的常用方法,但不能滥用,应作为实现弹性布局的最后杀器使用(如不同大小视口下完全改变网站的布局形态)。

要尽最大努力实现弹性可伸缩的布局,并在媒体查询的各个断点区间内指定相应的尺寸。媒体查询的断点应根据设计自身来决定,而不是设备。

建议:

  • 使用百分比长度取代固定长度,或使用视口单位(vw/vh/vmin/vmax)。
  • 大分辨率下设置 max-width,以得到固定宽度。
  • 给替换元素(img/video/iframe 等)设置 max-width: 100%。
  • 背景图片想铺满容器而不管容器尺寸变化:background-size: cover。
  • 行列式布局时,以视口宽度决定列的数量。
  • 多列文本指定列宽 column-width 而不是列数,这样小屏幕可以自动显示单列布局。

合理使用简写

老话:减少改动时要编辑的地方,减少重复代码。

展开属性和简写的配合。

/* 以 ‘/’ 分隔position和size,是为了避免数值歧义 */
background:
url(tr.png) no-repeat top right / 2em 2em,
url(bt.png) no-repeat bottom right / 2em 2em,
url(bl.png) no-repeat bottom left / 2em 2em;

background:
url(tr.png) top right,
url(bt.png) bottom right,
url(bl.png) bottom left;
background-size: 2em 2em;
background-repeat: no-repeat;

背景与边框

半透明边框

background-clip 默认值为 border-box,即背景会被 border 外边沿裁切掉,设置为 padding-box 则从内边距外沿裁切。

.translucent-border {
border: 10px solid rgba(255, 0, 0, 0.5);
background: #000;
color: #fff;
background-clip: padding-box;
}
半透明边框

多重边框

box-shadow 方案

  • 投影行为不会影响布局。
  • 投影不会响应鼠标事件。
/* box-shadow: x-offset y-offset blur spread color inset; */
.multiple-border-shadow {
background: #9a0;
box-shadow:
0 0 0 5px #655,
0 0 0 10px #f00,
0 2px 5px 10px rgba(0, 0, 0, 0.6);
}
box-shadow 多重边框

outline 方案

  • 只适用两层边框。
  • outline 描边不贴合圆角。
  • 可以控制描边类型、边距。
.multiple-border-outline {
background: #9a0;
border: 5px solid #655;
outline: 5px solid #f00;
}
outline 双重边框

灵活的背景定位

background-position 的扩展语法方案

扩展语法允许我们指定背景图片距离任意角的偏移量。(IE9+)

padding: 10px;
background-position: right 10px bottom 10px;

background-origin 方案

有一种常见情况:背景图片偏移量与容器内边距一致。

background-origin 默认值 padding-box,这样边框才不会遮住图片。background-position 的 left/top 参考 background-origin 属性值而定。

/* background-position 参照 content-box 而定,不用耦合内边距了 */
padding: 10px;
background-origin: content-box;
background-position: right bottom;

calc() 方案

/* calc函数内部运算符两侧空白符不能少 */
background-position: calc(100% - 20px) calc(100% - 10px);

边框内圆角

结合 outline 和 box-shadow。

.inner-rounding {
width: 100px;
padding: 10px;
margin: 10px;
background: #ceb591;
border-radius: 10px;
outline: 6px solid #655;
box-shadow: 0 0 0 5px #655; /* 取圆角半径一半 */
}
边框内圆角

条纹背景

普通线性渐变

.linear-gradient {
width: 150px;
height: 100px;
background: linear-gradient(#fb3 20%, #58a 80%);
}
普通线性渐变

条纹效果

.linear-gradient-cancel {
width: 150px;
height: 100px;
background: linear-gradient(#fb3 50%, #58a 50%); /* 取消渐变效果 */
background-size: 100% 3em; /* 设置条纹大小 */
background-repeat: repeat; /* 默认就会重复平铺 */
}
条纹效果

条纹效果更好的写法

.repeating-linear-gradient {
width: 150px;
height: 100px;
background: repeating-linear-gradient(
90deg,
#fb3 0,
#fb3 1em,
#58a 1em,
#58a 2em);
}
条纹效果更好的写法

改改角度就能得到斜向条纹

.diagonal-stripe {
width: 150px;
height: 100px;
background: repeating-linear-gradient(
60deg,
#fb3 0,
#fb3 1em,
#58a 1em,
#58a 2em);
}
斜向条纹

复杂的背景图案

网格

多个水平、垂直的线性渐变叠加起来可产生网格

.net-grid {
width: 150px;
height: 150px;
background: #fff;
background-image:
linear-gradient(rgba(200,0,0,.5) 2px, transparent 0),
linear-gradient(90deg, rgba(200,0,0,.5) 2px, transparent 0);
background-size: 1em 1em;
}

网格

波点

径向渐变的组合应用

.polka {
width: 150px;
height: 150px;
background: #fff;
background-image:
radial-gradient(#6cf 30%, transparent 0),
radial-gradient(#6cf 30%, transparent 0);
background-size: 30px 30px;
background-position: 0 0, 15px 15px;
}

波点

棋盘

线性渐变的组合应用

.chekerboard-css {
width: 150px;
height: 150px;
background: #eee;
background-image:
linear-gradient(45deg,
rgba(0,0,0,.25) 25%, transparent 0,
transparent 75%, rgba(0,0,0,.25) 0),
linear-gradient(45deg,
rgba(0,0,0,.25) 25%, transparent 0,
transparent 75%, rgba(0,0,0,.25) 0);
background-size: 30px 30px;
background-position: 0 0, 15px 15px;
}
/* svg 写法
background: #eee url('data:image/svg+xml,\
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill-opacity=".25" >\
<rect x="50" width="50" height="50" />\
<rect y="50" width="50" height="50" />\
</svg>'
);
*/

棋盘

蚂蚁行军

background-clip 和 线性渐变 的组合应用

@keyframes ants {to {background-position: 100%;}}
.marching-ant {
padding: 1em;
border: 1px solid transparent;
// padding之内填充白色,border之内填充斜条纹
background:
linear-gradient(#fff, #fff) padding-box,
repeating-linear-gradient(
-45deg,
#000 0, #000 25%, #fff 0, #fff 50%) 0 / .6em .6em;
animation: ants 15s linear infinite;
}

蚂蚁行军

形状

自适应椭圆

border-radius 的应用

border-radius: top-left-radius top-right-radius bottom-right-radius bottom-left-radius;

.ellipse {
width: 100px;
height: 50px;
background: #fb3;
border-radius: 50%;
}

自适应椭圆

半椭圆

border-radius 的应用

.half-ellipse {
width: 100px;
height: 50px;
background: #fb3;
border-radius: 100% 0 0 100% / 50%; // ‘/’分隔水平和垂直方向的圆角半径。
}

半椭圆

平行四边形

伪元素 skew 的应用

.parallelograms {
position: relative;
display: inline-block;
padding: .5em 1em;
color: #fff;
}
.parallelograms::before {
content: '';
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
z-index: -1;
background: #58a;
transform: skew(45deg);
}

平行四边形

菱形图片

// 写法一
// <div class="diamond"><img/></div>
.diamond {
width: 250px;
height: 250px;
transform: rotate(45deg);
overflow: hidden;
margin: 100px;
}

.diamond img {
max-width: 100%;
transform: rotate(-45deg) scale(1.42);
z-index: -1;
position: relative;
}

// 写法二
// <img class="diamond" />
.diamond {
width: 200px;
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); // 兼容性稍差
transition: .5s;
}
.diamond:hover {
// x1 y1, x2 y2, x3 y3, x4 y4
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}

切角效果

每一个 线性渐变 产生1/4矩形块

.beveled-corners {
background: #58a;
background: linear-gradient(135deg, transparent 5px, #58a 0) top left,
linear-gradient(-135deg, transparent 5px, #58a 0) top right,
linear-gradient(-45deg, transparent 5px, #58a 0) bottom right,
linear-gradient(45deg, transparent 5px, #58a 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;
padding: 10px;
width: 150px;
color: #fff;
}

切角效果

弧形切角

把上面的 线性渐变 换成 径向渐变 就ok啦~

.scoop-corners {
background: #58a;
background: radial-gradient(circle at top left, transparent 10px, #58a 0) top left,
radial-gradient(circle at top right, transparent 10px, #58a 0) top right,
radial-gradient(circle at bottom right, transparent 10px, #58a 0) bottom right,
radial-gradient(circle at bottom left, transparent 10px, #58a 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;
padding: 10px;
width: 150px;
color: #fff;
}

弧形切角

饼图

书上写的方法个人感觉并不是很完美,比如0、100进度状态是一样的。所以稍微改写了一下。如果想要从0开始变化的动画效果,需要 JS 修改百分比数协助一下。

.pie-svg {
width: 100px;
height: 100px;
transform: rotate(-90deg);
border-radius: 50%;
}
.pie-circle {
fill: #ddd;
stroke: #6cf;
stroke-width: 32;
stroke-dasharray: 30 100;
transition: stroke-dasharray 0.8s;
}

/* 辅助动画
var pieSVG = document.getElementById('pie-svg');
var pieCircle = document.getElementById('pie-circle');
var pieNum = pieSVG.getAttribute('data-num');
pieCircle.style['stroke-dasharray'] = pieNum + ' 100';
*/

视觉效果

投影

box-shadow 的应用

box-shaodw: x-offset y-offset blur spread color;

单/对边投影

可设置多个阴影

.one-shadow {
width: 150px;
height: 100px;
background: #fb3;
box-shadow: 0 5px 5px -5px #000, 0 -5px 5px -5px #000;
}

单/对边投影

邻边投影

.side-shadow {
width: 150px;
height: 100px;
background: #fb3;
box-shadow: 3px 3px 6px -3px #000;
}
邻边投影

染色效果

滤镜大法

filter 效果

.color-tint-filter {
width: 200px;
transition: 1s;
filter: sepia() saturate(4) hue-rotate(180deg);
}
.color-tint-filter:hover {
filter: none;
}

背景图大法

background-blend-mode 效果

.color-tint-bg {
width: 200px;
height: 200px;
margin: auto;
background-image: url(/assets/csssecret/cat.jpg);
background-size: cover;
background-color: hsl(335, 100%, 50%);
background-blend-mode: luminosity;
transition: .5s;
}
.color-tint-bg:hover {
background-color: transparent;
}

毛玻璃效果

.glass-blur {
width: 300px;
padding: 20px;
margin: 0 auto;
}
.glass-blur, .glass-blur main::before {
background: url(/assets/csssecret/cat.jpg) 0 / cover;
}
.glass-blur main {
position: relative;
background: rgba(255,255,255,.3);
overflow: hidden;
border-radius: .3em;
z-index: 1;
padding: 1em;
color: #fff;
box-shadow: 0 .5em 1em rgba(0, 0, 0, 0.6);
}
.glass-blur main::before {
content: '';
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: -30px;
z-index: -1;
filter: blur(20px);
}


毛玻璃效果毛玻璃效果毛玻璃效果毛玻璃效果毛玻璃效果毛玻璃效果毛玻璃效果毛玻璃效果毛玻璃效果毛玻璃效果毛玻璃效果毛玻璃效果毛玻璃效果

折纸效果

.folded-corner {
position: relative;
width: 12em;
background: #58a;
background: linear-gradient(-150deg, transparent 1.5em, #58a 0); // angle=30deg, size=1.5em
padding: 2em;
color: #fff;
border-radius: .5em;
}

.folded-corner::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; // =size/cos(angle)
height: 3em; // =size/sin(angle)
transform: translateY(-1.3em) rotate(-30deg); //width-height, 2*angle-90deg
transform-origin: bottom right;
border-bottom-left-radius: inherit;
box-shadow: -.2em .2em .3em -.1em rgba(0,0,0,.15)
}
折纸效果

字体排印

连字符断行

同时 html 要指定 lang=”en” 才会生效。

.hyphenation {
width: 8.7em;
text-align: justify;
hyphens: auto;
}

“The only way to get rid of a temptation is to yield to it.”

插入换行

用于 dl、dt、dd 的自定义列表。

.line-break {
width: 8.7em;
text-align: justify;
hyphens: auto;
}

Name:
Lea Verou
Email:
lea@verou.me
leaverou@mit.edu
Location:
Earth

文本行的斑马条纹

用于pre的文本斑马条纹

.zebra-lines {
padding: .5em;
line-height: 1.5;
background: hsl(20, 50%, 95%);
background-image: linear-gradient(rgba(120,0,0,.1) 50%, transparent 0);
background-size: auto 3em; // 行高的2倍
background-origin: content-box; // 避免padding的影响
}

while (true) {
  var d = new Date();
  if (d.getDate() == 1 && d.getMonth() == 3) {
    alert("TROLOLOL");
  }
}

自定义下划线

linear-gradient 模拟下划线

.underline {
background: linear-gradient(90deg, #aaa 66%, transparent 0) repeat-x;
background-size: .5em 2px;
background-position: 0 1.3em; // 受 line-height 影响
line-height: 1.5;
}

自定义下划线

现实中的文字效果

text-shadow 的应用

凸版印刷效果

.letterpress {
padding: .8em 1em;
background: #8e99a5;
color: #454d55;
text-shadow: 0 1px 1px rgba(255,255,255,.8);
}
.letterpress2 {
padding: .8em 1em;
background: #454d55;
color: #8e99a5;
text-shadow: 0 -1px 1px #000;
}
凸版印刷效果

凸版印刷效果

空心字效果

.stroke-text {
text-shadow: 1px 1px #f00, -1px -1px #f00, 1px -1px #f00, -1px 1px #f00;
}
空心字效果

文字外发光效果

.glow-text {
color: #203;
transition: .5s;
text-shadow: 0 0 .1em, 0 0 .3em;
}
文字外发光效果

文字凸起效果

.extruded-text {
background: #58a;
color: white;
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 #000;
}
文字凸起效果

环形文字

svg 的应用

.circular {
width: 10em;
height: 10em;
margin: 2em auto;
}
.circular svg {
display: block;
overflow: visible;
transition: 10s linear transform;
}
.circular svg:hover { transform: rotate(-2turn); }
.circular text { fill: currentColor; }
.circular path { fill: none; }

$$('.circular').forEach(function(el) {
var NS = "http://www.w3.org/2000/svg";

var svg = document.createElementNS(NS, "svg");
svg.setAttribute("viewBox", "0 0 100 100");

var circle = document.createElementNS(NS, "path");
circle.setAttribute("d", "M0,50 a50,50 0 1,1 0,1z");
circle.setAttribute("id", "circle");

var text = document.createElementNS(NS, "text");
var textPath = document.createElementNS(NS, "textPath");
textPath.setAttributeNS("http://www.w3.org/1999/xlink", 'xlink:href', '#circle');
textPath.textContent = el.textContent;
text.appendChild(textPath);

svg.appendChild(circle);
svg.appendChild(text);

el.textContent = '';
el.appendChild(svg);
});

环形文字效果测试环形文字效果测试环形文字效果测试环形文字效果测试

用户体验

选用合适的鼠标光标

鼠标光标样式可告知用户当前执行动作,提升用户体验。

cursor: url(xxx.png);
/*
default、pointer、crosshair、help、move、progress、text、wait、cell、alias、copy、no-drop、not-allowed、node、no-resize、zoom-in、zoom-out...
*/

扩大可点击区域

可点击区域(热区)向外扩张也可以带来可用性的提升。没人愿意对一个狭小按钮尝试点击很多次。

.hit-area {
position: relative;
width: 25px;
height: 25px;
line-height: normal;
background: #58a;
border-radius: 50%;
border: 1px solid #bbb;
color: #fff;
cursor: pointer;
font-size: 16px;
}
// 不会影响布局
.hit-area:before {
content: '';
position: absolute;
top: -10px; right: -10px;
bottom: -10px; left: -10px;
}

自定义复选框

原文用到了 CSS3 的 clip 属性。。。现在兼容性还不大好,不敢直接用在项目里呢。。。
原文虽然说不能用 display:none 隐藏起来,会损失键盘的可访问性,那就 opacity: 0 隐藏起来呗😂

.custom-checkbox {
position: relative;
display: inline-block;
cursor: pointer;
}
.custom-checkbox .checkbox-original {
opacity: 0;
position: absolute;
width: 0;
height: 0;
z-index: -1;
}
.custom-checkbox .checkbox-inner {
background: #fff;
width: 15px; height: 15px;
display: inline-block;
vertical-align: middle;
border: 1px solid #aaa;
}
.custom-checkbox .checkbox-original:checked + .checkbox-inner {
background: #000;
}
.custom-checkbox .checkbox-label {
padding-left: 5px;
display: inline-block;
vertical-align: middle;
}

/* checkbox-inner 为自定义图标
<label class="custom-checkbox">
<span class="checkbox-input">
<input type="checkbox" class="checkbox-original" checked />
<span class="checkbox-inner"></span>
</span>
<span class="checkbox-label">自定义复选框文字</span>
</label>
*/

弱化背景

书上提到 伪元素box-shadow 两种方案,但是对于遮罩层事件、控制和滚动有一定局限性。

// 伪元素
body.dimmed::before {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
z-index: 1;
background: rgba(0, 0, 0, .8);
}

// box-shadow
.lightbox {
position: fixed;
top: 50%; left: 50%;
margin: -200px;
box-shadow: 0 0 0 50vmax rgba(0,0,0,.8);
}

// 常规套路
.overlay { // 遮罩层
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0, 0, 0, .8);
}
.lightbox { // 突出显示的对话框
position: absolute;
z-index: 1;
}

/*
<div class="overlay">
<div class="lightbox">突出显示的对话框</div>
</div>
*/

模糊背景

main {
transition: .6s;
background: #fff;
}

main.de-emphasized {
filter: blur(3px);
}

.dialog {
background: #fff;
position: fixed;
top: 50%; left: 50%;
z-index: 1;
width: 10em;
padding: 2em;
margin: -5em;
border: 1px solid silver;
border-radius: .5em;
box-shadow: 0 .2em .5em rgba(0,0,0,.5),
0 0 0 100vmax rgba(0,0,0,.2);
}

/*
<div class="dialog">突出显示的对话框</div>
<main>
文字内容
</main>
*/

结构与布局

自适应内部元素

min-content 解析为容器内最大的不可断行元素的宽度。(最宽的单词、图片或固定宽度的盒元素)

width: min-content;

精确控制表格列宽

table-layout 默认值为 auto,表格内容会影响单元格宽度。可设置为 fixed,宽度控制由开发者决定。

table {
table-layout: fixed;
width: 100%;
}

满屏定宽

.fluid-fixed {
padding: 10px calc(50% - 250px);
background: #abc;
}

/* 传统写法需要多个元素
.fluid-fixed {background: #abc;}
.fluid-fixed. wrapper {max-width: 900px; margin: 10px auto;}
*/
内容宽度是 500px

垂直居中

绝对定位方案

.vertical-center-abs {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
绝对定位垂直居中

基于视口单位的解决方案

有一定局限性,仅限视口中的居中。

.vertical-center-vh {
margin: 50vh auto 0; // margin百分比值是以父元素宽度计算的
transform: translateY(-50%);
}

基于Flexbox的解决方案

.vertical-center-flex-wrapper {
background: #abc;
display: flex;
width: 300px; height: 150px;
align-items: center;
justify-content: center;
}
/* 子元素也可以这样
.vertical-center-flex {
margin: auto;
}
*/
flex垂直居中

紧贴底部的页脚

flex 方案解决最方便。

body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1;
}
footer {}
/* vh 方案
main{ min-height:calc(100vh - hHeader - hFooter); }
*/

/* 稍麻烦的个人方案
html
body
.wrapper
header
main
footer

html,body { height:100%; }
.wrapper { position:relative; min-height:100%; }
footer {
position:absolute;bottom:0;left: 0;right: 0;
height:50px;
}
*/

过渡与动画

缓动效果

可视化的贝塞尔曲线控制效果
常见内置缓动曲线:
缓动曲线图

@keyframes bounce {
60%, 80%, to {
transform: translateY(200px);
animation-timing-function: ease;
}
70% { transform: translateY(150px); }
90% { transform: translateY(180px); }
}
.bounce-ball {
width: 0; height: 0; padding: 20px;
border-radius: 50%;
margin: auto;
background: #f00 radial-gradient(at 30% 30%, #fdd, #f00);
animation: bounce 1.5s cubic-bezier(.1,.25,1,.25) infinite;
}
/*
贝塞尔曲线控制函数,控制动画锚点,端点在(0,0)和(1,1)之间,xy互换可得反向版本
cubic-bezier(x1,y1,x2,y2)
*/

弹性过渡

cubic-bezier 函数的应用,控制锚点使垂直方向上突破 0-1 区间。

.callout {
transition: .5s cubic-bezier(.25,.1,.3,1.5) transform;
transform-origin: 1.4em -.4em;
}
button:not(:focus) + .callout:not(:hover) {
transform: scale(0);
transition: .25s transform;
}

弹性过渡

逐帧动画

GIF 缺点:限制256色;不透明;无法调整动画参数。
逐帧动画:把动画所有帧拼合到一张 PNG 图片,采用 steps() 函数。
steps 不同于其它调速函数的平滑特点,它会在帧与帧之间硬切。

@keyframes loader {
to { background-position: -800px 0; }
}

.loader {
width: 100px; height: 100px;
text-indent: 999px; overflow: hidden;
background: url(/assets/csssecret/loader.png) 0 0;
animation: loader 1s infinite steps(8);
}

我是原图

我是逐帧动画

Loading…

闪烁效果

@keyframes blink { 50% { color: transparent; } }

.blink {
padding: 1em;
animation: 1s blink Infinite;
}

打字动画

闪烁效果 和 steps 的结合应用。

@keyframes typing { from { width: 0; } }
@keyframes caret { 50% { border-right-color: transparent; } }

.typing {
font: 500 16px Consolas, Monaco, monospace;
width: 5em; /*width: 8.25em;*/
white-space: nowrap;
overflow: hidden;
border-right: 1px solid;
animation: typing 3s steps(5) infinite,
caret 1s steps(1) infinite;
}

打字动画

状态平滑的动画

默认情况下,动画会立即停止播放,并生硬地跳回开始状态。

@keyframes panoramic {
to { background-position: 100% 0; }
}
.panoramic {
width: 150px; height: 150px;
background: url(/assets/csssecret/travel.jpg);
background-size: auto 100%;
animation: panoramic 10s linear infinite alternate;
animation-play-state: paused;
// animation-play-state: paused; 动画运行状态,默认 running
// animation-direction: alternate; 轮流反向动画
}
.panoramic:hover, .panoramic:focus {
animation-play-state: running;
}

沿环形路径平移的动画

每个 transform-origin 都可以被两个 translate() 模拟出来。

@keyframes spin {
from {
transform: rotate(0turn)
translateY(-100px) translateY(50%)
rotate(1turn);
}
to {
transform: rotate(1turn)
translateY(-100px) translateY(50%)
rotate(0turn);
}
}
.along-path .avatar {
display: block;
width: 50px;
margin: calc(50% - 25px) auto 0;
border-radius: 50%;
animation: spin 3s infinite linear;
}
.along-path {
width: 200px; height: 200px;
padding: 10px;
border-radius: 50%;
background: #fb3;
}