css:变形;伪类;旋转;倾斜;透视;动画延迟;媒体;图标

基础知识

houdunren.com (opens new window)open in new window

#open in new window坐标系统

要使用元素变形操作需要掌握坐标轴,然后通过改变不同坐标来控制元素的变形。

image

  • X 轴是水平轴
  • Y 轴是垂直轴
  • Z 轴是纵深轴

#open in new window变形操作

使用 transform 规则控制元素的变形操作,包括控制移动、旋转、倾斜、3D 转换等,下面会详细介绍每一个知识点。

下面是 CSS 提供的变形动作。

选项说明
none定义不进行转换。
translate(x,y)定义 2D 转换。
translate3d(x,y,z)定义 3D 转换。
translateX(x)定义转换,只是用 X 轴的值。
translateY(y)定义转换,只是用 Y 轴的值。
translateZ(z)定义 3D 转换,只是用 Z 轴的值。
scale(x,y)定义 2D 缩放转换。
scale3d(x,y,z)定义 3D 缩放转换。
scaleX(x)通过设置 X 轴的值来定义缩放转换。
scaleY(y)通过设置 Y 轴的值来定义缩放转换。
scaleZ(z)通过设置 Z 轴的值来定义 3D 缩放转换。
rotate(angle)定义 2D 旋转,在参数中规定角度。
rotate3d(x,y,z,angle)定义 3D 旋转。
rotateX(angle)定义沿着 X 轴的 3D 旋转。
rotateY(angle)定义沿着 Y 轴的 3D 旋转。
rotateZ(angle)定义沿着 Z 轴的 3D 旋转。
skew(x-angle,y-angle)定义沿着 X 和 Y 轴的 2D 倾斜转换。
skewX(angle)定义沿着 X 轴的 2D 倾斜转换。
skewY(angle)定义沿着 Y 轴的 2D 倾斜转换。
perspective(n)为 3D 转换元素定义透视视图。

#open in new window变形叠加

重复设置变形操作时只在原形态上操作。

#open in new window默认处理

下面设置了两次移动,并不会移动 550px 而是只移动 50px。

<style>
    div {
        transform: translateX(500px);
        width: 100px;
        height: 100px;
        background: #9b59b6;
    }

    div:nth-child(1) {
        transform: translateX(50px);
    }
</style>

<div></div>

#open in new window伪类叠加

image

<style>
    div {
        transition: 2s;
        transform: translateX(200px) translateX(50px);
        width: 100px;
        height: 100px;
        background: #9b59b6;
    }

    div:hover {
        transition: 2s;
        transform: translateX(100px);
    }
</style>

<div></div>

#open in new window行级元素

行级元素不产生变形效果,将其转为 inline-blockblock 以及弹性元素时都可以产生变化效果。

image

<style>
    span {
        display: inline-block;
        transition: 2s;
        transform: translateX(100px) translateX(50px);
        width: 100px;
        height: 100px;
        background: #9b59b6;
    }

    span:hover {
        transition: 2s;
        transform: translateX(100px);
    }
</style>

<span>hdcms</span>

#open in new window伪类状态

#open in new window:hover

鼠标移动上后发生改变。

image

article div:nth-child(2):hover {
  transform: rotate(180deg);
}

#open in new window:target

以下操作变化时间为零秒,通过掌握后面的过渡动画可以控制变化时间。

image

<style>
    article {
        width: 300px;
        height: 300px;
        display: grid;
        gap: 10px;
        grid-template-columns: repeat(2, 1fr);
        grid-template-rows: repeat(2, 1fr);
        position: relative;
        border: solid 5px silver;
        color: white;
    }

    article div a {
        color: white;
        text-decoration: none;
    }

    article div,
    article div aside {
        background: blueviolet;
        background-clip: content-box;
        padding: 5px;
        border: solid 2px blueviolet;
        box-sizing: border-box;
        display: flex;
        justify-content: center;
        align-items: center;
        position: relative;
    }

    article div aside {
        position: absolute;
        display: none;
        width: 100px;
        height: 100px;
    }

    aside:target {
        display: block;
        transform: translateY(150px);
        box-shadow: 0 0 10px #ddd;
    }
</style>

<article>
    <div>
        <a href="#hdcms">hdcms</a>
        <aside id="hdcms">
            内容管理系统
        </aside>
    </div>
    <div>
        <a href="#houdunren">houdunren</a>
        <aside id="houdunren">
            在线社区
        </aside>
    </div>
</article>

#open in new window移动元素

  • 沿 X 轴移动时正值向右移动、负值向左移动
  • 沿 Y 轴移动时正值向下移动、负值向上移动
  • 如果使用百分数将控制元素的原尺寸计算百分比然后移动
  • 可同时设置多个值,解析器会从左向右依次执行
  • 变形是在原基础上更改,即第二次设置值时不是在第一次值上变化

#open in new windowtranslateX

正值向右移动、负值向左移动。

image

<style>
    article {
        width: 300px;
        height: 300px;
        position: relative;
        border: solid 5px silver;
    }

    article div {
        width: 100px;
        height: 100px;
        background: blueviolet;
        box-sizing: border-box;
        position: absolute;
        left: 50%;
        margin-left: -50px;
        top: 50%;
        margin-top: -50px;
    }

    article div:nth-child(1) {
        background: #e9dddd;
    }

    article div:nth-child(2) {
        transform: translateX(100px);
    }
</style>
...

<article>
    <div></div>
    <div></div>
</article>

#open in new windowtranslateY

正值向下移动、负值向上移动。

image

article div:nth-child(2) {
  transform: translateY(100px);
}

#open in new windowtranslate

使用 translate 可以控制按 X、Y 同时移动操作,第一个值控制 X 移动,第二个值控制 Y 移动。

image

article div:nth-child(2) {
  transform: translate(100px, -100px);
}

#open in new window百分比移动

元素宽度为 100px 设置 50%时将移动 50px,即百分比是指元素的尺寸的百分比。

image

article div:nth-child(2) {
  transform: translateX(50%);
}

#open in new window元素居中

居中可以使用多种方式,如弹性布局、定位操作,下面来看使用移动操作居中。

image

<style>
    body {
        height: 100vh;
    }

    main {
        width: 400px;
        height: 400px;
        border: solid 5px silver;
        position: relative;
    }

    main div {
        width: 100px;
        height: 100px;
        background: blueviolet;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
    }
</style>

<main>
    <div></div>
</main>

#open in new windowtranslateZ

控制 Z 轴移动,正数向外、负数向里移动。因为 Z 轴是透视轴没有像 X/Y 一样的固定尺寸,所以不能使用百分数。

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
        list-style: none;
    }

    body {
        width: 100vw;
        height: 100vh;
        background: #34495e;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        width: 200px;
        height: 200px;
        transform-style: preserve-3d;
        transition: 2s;
        transform: perspective(900px) rotateY(60deg);
    }

    body:hover main {
        transform: perspective(600px) rotateY(60deg) scaleZ(5);
    }

    div {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: #f1c40f;
    }

    div.b {
        background: #8e44ad;
        transform: translateZ(-100px);
    }
</style>

<main>
    <div class="f"></div>
    <div class="b"></div>
</main>

#open in new windowtranslate3d

用于同时控制 X/Y/Z 轴的移动,三个值必须输入如果某个轴不需要移动时设置为零。

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
        list-style: none;
    }

    body {
        width: 100vw;
        height: 100vh;
        background: #34495e;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        width: 200px;
        height: 200px;
        background: #f1c40f;
        perspective: 600px;
        transform: perspective(600px) rotateY(35deg);
        transition: 2s;
    }

    body:hover main {
        transform: perspective(600px) rotateY(35deg) translate3d(50%, 50%, 200px);
    }
</style>

<main>
    <div></div>
</main>

#open in new window渐变表单

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    body {
        width: 100vw;
        height: 100vh;
        background: #34495e;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        width: 300px;
        height: 300px;
        border: solid 5px silver;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }

    .field {
        position: relative;
        overflow: hidden;
        margin-bottom: 20px;
    }

    .field::before {
        content: '';
        position: absolute;
        left: 0;
        height: 2px;
        bottom: 0;
        width: 100%;
        background: linear-gradient(to right, white, #1abc9c, #f1c40f, #e74c3c, white);
        transform: translateX(-100%);
        transition: 2s;
    }

    .field:hover::before {
        transform: translateX(100%);
    }

    .field input {
        border: none;
        outline: none;
        background: #ecf0f1;
        padding: 10px;
    }
</style>

<main>
    <div class="field">
        <input type="text" placeholder="请输入厚道人帐号">
    </div>
    <div class="field">
        <input type="text" placeholder="请输入密码">
    </div>
</main>

#open in new window页面切换

下面是使用移动效果制作的页面切换效果。

image

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
    * {
        padding: 0;
        margin: 0;
    }

    a {
        text-decoration: none;
    }

    body {
        display: flex;
        width: 100vw;
        height: 100vh;
        flex-direction: column;
    }

    main {
        position: relative;
        background: #f3f3f3;
        flex: 1;
        overflow: hidden;
    }

    nav {
        display: flex;
        justify-content: space-around;
        align-items: center;
        height: 8vh;
        text-align: center;
        background: #34495e;
    }

    nav a {
        flex: 1;
        font-size: 1.3em;
        text-transform: uppercase;
        font-weight: bold;
        opacity: .8;
        color: white;
    }

    nav a:nth-child(2) {
        border-right: solid 1px #aaa;
        border-left: solid 1px #aaa;
    }

    main>div {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        transition: all 1s;
        z-index: 1;
        background: #f3f3f3;
        opacity: 0;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        transform: translate(0, -100%);
        color: white;
        font-size: 2em;
    }

    main>div:target {
        opacity: 1;
        transform: translate(0%, 0%);
    }

    main>div:nth-of-type(1):target {
        background: #3498db;
    }

    main>div:nth-of-type(2):target {
        background: #9b59b6;
    }

    main>div:nth-of-type(3):target {
        background: #16a085;
    }

    div i[class^="fa"] {
        font-size: 100px;
        color: white;
    }
</style>

<body>
    <main>
        <div id="home">
            <i class="fa fa-home" aria-hidden="true"></i>
            houdunren.com
        </div>
        <div id="video">
            <i class="fa fa-vimeo" aria-hidden="true"></i>
        </div>
        <div id="live">
            <i class="fa fa-viadeo" aria-hidden="true"></i>
        </div>
    </main>
    <nav>
        <a href="#home">home</a>
        <a href="#video">video</a>
        <a href="#live">live</a>
    </nav>
</body>

#open in new window缩放元素

比如数值为 2 时表示为原尺寸的两倍。

#open in new windowscaleX

下面是沿 X 轴缩放一半。

image

article div:nth-child(2) {
  transform: scaleX(0.5);
}

#open in new windowscaleY

下面是沿 Y 轴缩放一半。

image

article div:nth-child(2) {
  transform: scaleY(0.5);
}

#open in new windowscale

使用 scale 可同时设置 X/Y 轴的缩放,如果只设置一个值时表示两轴缩放相同。

使用数值定义缩放,如 .5 表示缩小一半,2 表示放大两倍。

image

article div:nth-child(2) {
  transform: scale(0.5, 2);
}

#open in new windowscaleZ

沿 Z 轴缩放元素,需要有 3D 透视才可以查看到效果。

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    body {
        width: 100vw;
        height: 100vh;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        width: 400px;
        height: 400px;
        border: solid 5px silver;
        transform-style: preserve-3d;
        transform: perspective(900px) rotateY(45deg);
        transition: 3s;
    }

    div {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -100px;
        margin-top: -100px;
        width: 200px;
        height: 200px;
    }

    div:nth-child(1) {
        background: #2ecc71;
    }

    div:nth-child(2) {
        background: #e67e22;
        transition: 1s;
        transform: translateZ(-300px);
    }

    body:hover main {

        transform: perspective(900px) rotateY(45deg) scaleZ(3);
    }
</style>

<main>
    <div></div>
    <div></div>
</main>

#open in new windowscale3d

沿 X/Y/Z 三个轴绽放元素。

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
        list-style: none;
    }

    body {
        width: 100vw;
        height: 100vh;
        background: #34495e;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        width: 200px;
        height: 200px;
        transform-style: preserve-3d;
        transition: 2s;
        transform: perspective(900px) rotateY(60deg)
    }

    body:hover main {
        transform: perspective(600px) rotateY(60deg) scale3d(2, 2, 4);
    }

    div {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: #f1c40f;
    }

    div.b {
        background: #8e44ad;
        transform: translateZ(-100px);
    }
</style>

<main>
    <div class="f"></div>
    <div class="b"></div>
</main>

#open in new window菜单缩放

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #34495e;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
    }

    ul {
        list-style: none;
        display: flex;
        justify-content: space-evenly;
        width: 200px;
    }

    ul li {
        position: relative;
    }

    ul li strong {
        background: #e67e22;
        color: #2c3e50;
        padding: 2px 20px;
        cursor: pointer;
        text-transform: uppercase;
    }

    ul li strong+div {
        border: solid 2px #e67e22;
        display: flex;
        flex-direction: column;
        padding: 10px 20px;
        position: absolute;
        transform-origin: left top;
        transform: scale(0);
        z-index: -1;
        transition: .6s;
        background: #e67e22;
    }

    ul li strong+div a {
        display: inline-block;
        padding: 5px;
        font-size: 1em;
        color: #2c3e50;
        text-decoration: none;
        text-transform: uppercase;
    }

    ul li:hover strong+div {
        transform: scale(1);
    }
</style>

<main>
    <ul>
        <li>
            <strong>VIDEO</strong>
            <div>
                <a href="">PHP</a>
                <a href="">hdcms</a>
                <a href="">laravel</a>
            </div>
        </li>
        <li>
            <strong>LIVE</strong>
            <div>
                <a href="">houdunren</a>
                <a href="">angular</a>
                <a href="">css3</a>
            </div>
        </li>
    </ul>
</main>

#open in new window相册放大

下面是使用缩放开发相册放大效果的示例。

image

<style>
    body {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        background: #ddd;
    }

    main {
        display: flex;
        justify-content: center;
        align-items: center;
    }

    main div {
        height: 200px;
        width: 200px;
        background: white;
        border: solid 1px #ddd;
        transition: all .5s;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 1.5em;
        text-transform: uppercase;
        color: blueviolet;
        overflow: hidden;
        border: solid 3px #555;
        box-sizing: border-box;
    }

    main div img {
        height: 100%;
    }

    main:hover div {
        transform: scale(.8) translateY(-30px);
        cursor: pointer;
        filter: blur(15px);
    }

    main div:hover {
        transform: scale(1.6);
        color: white;
        filter: none;
        z-index: 2;
    }

    main div:hover::after {
        content: '';
        position: absolute;
        background: #000;
        width: 100%;
        height: 100%;
        z-index: -1;
        box-shadow: 0 0 5px rgba(0, 0, 0, .3);
    }
</style>

<main>
    <div>
        <img src="1.jpg" alt="">
    </div>
    <div> <img src="2.jpg" alt=""></div>
    <div> <img src="3.jpg" alt=""></div>
</main>

#open in new window旋转操作

使用 CSS 可以控制元素按照不同坐标轴进行旋转。

#open in new windowrotateX

控制元素按照 X 轴进行旋转操作。

#open in new window基本使用

按水平轴发生旋转,如果旋转 90deg 将不可见。

image

article div:nth-child(2) {
  transform: rotateX(180deg);
}

下面是旋转 89deg 后,只会看到一条线。

image

#open in new window父级透视

当 X 旋转 90 度后无法看到元素,这时可以控制父级旋转从上看子元素。

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -200px;
        margin-top: -200px;
        width: 400px;
        height: 400px;
        border: solid 5px silver;
        transform-style: preserve-3d;
        transform: perspective(900px) rotateX(-45deg);
    }

    div {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -100px;
        margin-top: -100px;
        width: 200px;
        height: 200px;
        transition: 1s;
    }

    div:nth-child(1) {
        background: #2ecc71;
    }

    main:hover div:nth-child(1) {
        transform: perspective(900px) rotateX(90deg) rotateY(25deg) rotateZ(45deg);
    }
</style>

<main>
    <div></div>
</main>

#open in new windowrotateY

按垂直轴旋转,如果旋转 90deg 将不可见。

image

article div:nth-child(2) {
  transform: rotateY(180deg);
}

#open in new windowrotateZ

没 Z 轴旋转元素,效果就是沿 X/Y 轴的平面旋转。

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
        list-style: none;
    }

    body {
        width: 100vw;
        height: 100vh;
        background: #34495e;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        width: 200px;
        height: 200px;
        background: #f1c40f;
        perspective: 600px;
        transform: perspective(600px) rotateY(35deg);
        transition: 2s;
    }

    body:hover main {
        transform: perspective(600px) rotateY(35deg) rotateZ(160deg);
    }
</style>

<main>
    <div></div>
</main>


#open in new windowrotate

在 X 与 Y 轴平面旋转,效果与使用 rotateZ 相同。

image

article div:nth-child(2) {
  transform: rotate(90deg);
}

#open in new windowrotate3d

同时设置 X/Y/Z 轴的旋转向量值来控制元素的旋转。

需要同时设置如下四个参数

rotate3d(tx,ty,tz,angle)

#open in new window只转 X 轴

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
        list-style: none;
    }

    body {
        width: 100vw;
        height: 100vh;
        background: #34495e;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        width: 200px;
        height: 200px;
        background: #f1c40f;
        perspective: 600px;
        transform: perspective(600px) rotateY(35deg);
        transition: 2s;
    }

    body:hover main {
        transform: perspective(600px) rotateY(35deg) rotate3d(1, 0, 0, -645deg);
    }
</style>

<main>
    <div></div>
</main>

#open in new window只转 Y 轴

image

body:hover main {
  transform: perspective(600px) rotateY(-645deg);
}

#open in new window只转 Z 轴

image

#open in new windowXY 旋转

image

body:hover main {
  transform: perspective(600px) rotateY(35deg) rotate3d(1, 1, 0, -645deg);
}

#open in new windowXZ 转换

加入适当的 Z 向量值,可增加元素沿 Z 轴旋转的力度。

image

body:hover main {
  transform: perspective(600px) rotateY(35deg) rotate3d(1, 0, 0.5, -245deg);
}

#open in new window参数顺序

可以同时设置多个旋转规则,顺序不同结果也会不同。

image

article div:nth-child(2) {
  transform: rotateX(30deg) rotateY(30deg);
}

#open in new window旋转文字

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        height: 100vh;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }

    main {
        margin: 0 auto;
        width: 400px;
        height: 50vh;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        background: #535c68;
    }

    main div {
        color: #c7ecee;
        cursor: pointer;
    }

    main div strong {
        display: inline-block;
        width: 25px;
        height: 25px;
        margin: 0 3px;
        background: #000;
        border-radius: 50%;
        transition: 2s;
        color: white;
        text-align: center;
        box-shadow: 0 2px 10px rgba(0, 0, 0, .3);
    }

    main div strong:nth-of-type(1) {
        background: #f0932b;
    }

    main div strong:nth-of-type(2) {
        background: #6ab04c;
    }

    main div:hover strong:nth-of-type(1) {
        transform: rotate(360deg);
    }

    main div:hover strong:nth-of-type(2) {
        transform: rotate(-360deg);
    }
</style>

<main>
    <div>
        <strong>h</strong>ou<strong>d</strong>unren.com
    </div>
</main>

#open in new window电子时钟

image

<style>
    body {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        background: #34495e;
    }

    main {
        position: relative;
        width: 400px;
        height: 400px;
        background: #34495e;
        border-radius: 50%;
        box-shadow: 0 0 10px rgba(0, 0, 0, .7);
    }

    main::before {
        position: absolute;
        left: 0;
        top: 0;
        content: '';
        width: 100%;
        height: 100%;
        border-radius: 50%;
        transform: scale(1.2);
        background: radial-gradient(at right, #27ae60, #e67e22, #e74c3c, #e67e22, #27ae60);
        z-index: -1;
    }

    main .line>div {
        position: absolute;
        left: 50%;
        top: 50%;
        width: 10px;
        height: 95%;
        background: white;
    }

    main .line>div:nth-child(1) {
        transform: translate(-50%, -50%) rotate(0deg);
    }

    main .line>div:nth-child(2) {
        transform: translate(-50%, -50%) rotate(30deg);
    }

    main .line>div:nth-child(3) {
        transform: translate(-50%, -50%) rotate(60deg);
    }

    main .line>div:nth-child(4) {
        transform: translate(-50%, -50%) rotate(90deg);
    }

    main .line>div:nth-child(5) {
        transform: translate(-50%, -50%) rotate(120deg);
    }

    main .line>div:nth-child(6) {
        transform: translate(-50%, -50%) rotate(150deg);
    }

    main>div[class="mark"] {
        position: absolute;
        width: 100%;
        height: 100%;
        left: 0%;
        top: 0%;
        background: #34495e;
        border-radius: 50%;
        transform: scale(.8);
    }

    main>.point {
        width: 20px;
        height: 20px;
        background: #e74c3c;
        border-radius: 50%;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        z-index: 2;
    }

    main .hour {
        width: 15px;
        position: absolute;
        height: 25%;
        background: #95a5a6;
        left: 50%;
        bottom: 50%;
        transform: translate(-50%, 0);
    }

    main .minute {
        width: 8px;
        position: absolute;
        height: 35%;
        background: #3498db;
        left: 50%;
        bottom: 50%;
        transform-origin: left bottom;
        transform: translate(-50%, 0) rotate(60deg);
    }

    main .second {
        width: 2px;
        position: absolute;
        height: 35%;
        background: #f1c40f;
        left: 50%;
        bottom: 50%;
        transform-origin: left bottom;
        transform: translate(-50%, 0) rotate(90deg);
    }

    main:hover .second {
        transition: 10s;
        transform: rotate(260deg);
    }

    main .text {
        font-size: 1.2em;
        color: white;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, 20px);
        text-transform: uppercase;
        opacity: .5;
        text-align: center;
    }
</style>

<main>
    <section class="line">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
    </section>
    <div class="mark"></div>
    <div class="point"></div>
    <div class="hour"></div>
    <div class="minute"></div>
    <div class="second"></div>
    <div class="text">
        houdunren.com <br>
        大军大叔
    </div>
</main>

#open in new window倾斜操作

#open in new windowskewX

没 X 轴倾斜元素

image

article div:nth-child(2) {
  transform: skewX(30deg);
}

#open in new windowskewY

沿 Y 轴倾斜元素

image

article div:nth-child(2) {
  transform: skewY(30deg);
}

#open in new windowskew

同时设置 X/Y 轴倾斜操作,不指定第二个参数时 Y 轴倾斜为零。

image

article div:nth-child(2) {
  transform: skew(30deg, 30deg);
}

#open in new window按钮特效

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #34495e;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
    }

    main .btn {
        display: block;
        height: 30px;
        width: 150px;
        border: solid 2px #e74c3c;
        background: none;
        color: white;
        position: relative;
        text-align: center;
        display: flex;
        justify-content: center;
        align-items: center;
        overflow: hidden;
        cursor: pointer;
        box-shadow: 0 3px 8px rgba(0, 0, 0, .3);
    }

    main .btn::before {
        transition: all .8s;
        align-self: center;
        content: '';
        position: absolute;
        width: 0;
        height: 100%;
        background: #e74c3c;
        z-index: -1;
        transform: skewX(-45deg);
    }

    main .btn:hover::before {
        width: 200%;
    }
</style>

<main>
    <a class="btn">
        HOUDUNREN
    </a>
</main>

#open in new window立体按钮

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    body {
        background: #2c3e50;
        width: 100vw;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .btn {
        color: #ecf0f1;
        text-decoration: none;
        width: 200px;
        height: 40px;
        background: #e74c3c;
        display: flex;
        justify-content: center;
        align-items: center;
        position: relative;
        transform: skewX(25deg) rotate(-15deg);
        letter-spacing: .5em;
        text-transform: uppercase;
        font-weight: bold;
    }

    .btn::before {
        content: '';
        width: 10px;
        height: 100%;
        left: -10px;
        background: #000;
        position: absolute;
        transform: skewY(-45deg) translate(0, 5px);
    }

    .btn::after {
        content: '';
        width: 100%;
        height: 10px;
        bottom: -10px;
        background: #000;
        position: absolute;
        transform: skewX(-45deg) translate(-5px, 0);
    }
</style>

<a href="" class="btn"> houdunren</a>

#open in new window变形基点

使用 transform-origin 设置元素的 X/YZ 操作的基点,用于控制旋转、倾斜等操作。

  • 旋转默认以元素中心进行旋转,改变基点后可控制旋转点位置
  • 元素移动不受变形基点所影响
  • 基点是元素原始空间位,而不是 translate 移动后的空间位

#open in new window平面旋转

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -200px;
        margin-top: -200px;
        width: 400px;
        height: 400px;
        border: solid 5px silver;
    }

    div {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -100px;
        margin-top: -100px;
        width: 200px;
        height: 200px;
        transform-origin: right bottom;
    }

    div:nth-child(1) {
        background: #2ecc71;
    }

    div:nth-child(2) {
        background: #e67e22;
        transition: 1s;
    }

    main:hover div:nth-child(2) {
        transform: rotate(-45deg);
    }
</style>

<main>
    <div></div>
    <div></div>
</main>

#open in new window倾斜控制

参考右上角控制倾斜。

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -200px;
        margin-top: -200px;
        width: 400px;
        height: 400px;
        border: solid 5px silver;
    }

    div {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -100px;
        margin-top: -100px;
        width: 200px;
        height: 200px;
        transform-origin: top left;
    }

    div:nth-child(1) {
        background: #fff;
    }

    div:nth-child(2) {
        background: #e67e22;
        transition: 1s;
    }

    main:hover div:nth-child(2) {
        transform: skew(45deg);
    }
</style>

<main>
    <div></div>
    <div></div>
</main>

#open in new window三维旋转

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -200px;
        margin-top: -200px;
        width: 400px;
        height: 400px;
        border: solid 5px silver;
        transform-style: preserve-3d;
        transform: perspective(900px) rotateY(95deg);
    }

    div {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -100px;
        margin-top: -100px;
        width: 200px;
        height: 200px;
        transform-origin: center center 200px;
    }

    div:nth-child(1) {
        background: #2ecc71;
    }

    div:nth-child(2) {
        background: #e67e22;
        transition: 1s;
    }

    main:hover div:nth-child(2) {
        transform: rotateY(360deg);
    }
</style>

<main>
    <div></div>
    <div></div>
</main>

#open in new window变形顺序的影响

设置 transform 变形的前后顺序对变形结果是有影响

我们通过下面的示例来说明这个问题

  • 下面先写 rotate 后写 translate,即先按原位置的 transform-origin: top left 进行旋转,再按原位置的transform-origin: top left进行移动

image

<style>
  body {
    width: 100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  article {
    width: 200px;
    height: 200px;
    border: solid 2px #ddd;
    position: relative;
    background: #34495e;
  }
  article div {
    width: 5px;
    height: 100px;
    background: #000;
    transition: 2s;
    position: absolute;
    transform-origin: top left;
    transform: rotate(0deg) translate(-50%, -50%);
    background-color: #f1c40f;
  }
  article::after {
    content: 'houdunren.com@大军大叔';
    width: 100%;
    color: #f3f3f3;
    font-size: 12px;
    position: absolute;
    bottom: 5px;
    text-align: center;
  }
  article:hover div {
    transform: rotate(360deg) translate(-50%, -50%);
  }
</style>

<article>
  <div></div>
</article>

现在交换 rotatetranslate的顺序后,表示先移动元素,这时候旋转就是参考移动后的位置的 transform-origin: top left;结果如下

image

<style>
  body {
    width: 100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  article {
    width: 200px;
    height: 200px;
    border: solid 2px #ddd;
    position: relative;
    background: #34495e;
  }
  article div {
    width: 5px;
    height: 100px;
    background: #000;
    transition: 2s;
    position: absolute;
    transform-origin: top left;
    transform: translate(-50%, -50%) rotate(0deg);
    background-color: #f1c40f;
  }
  article::after {
    content: 'houdunren.com@大军大叔';
    width: 100%;
    color: #f3f3f3;
    font-size: 12px;
    position: absolute;
    bottom: 5px;
    text-align: center;
  }
  article:hover div {
    transform: translate(-50%, -50%) rotate(360deg);
  }
</style>

<article>
  <div></div>
</article>

#open in new window新年贺卡

下面是通过设置基点来制作贺卡的效果。

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    body {
        width: 100vw;
        height: 100vh;
        background: #34495e;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    main {
        width: 300px;
        height: 200px;
        transform-style: preserve-3d;
        transform: perspective(600px) rotateX(35deg) rotateY(15deg);
    }

    .card {
        width: 300px;
        height: 200px;
        background: #e67e22;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 3em;
        color: whitesmoke;
        position: relative;

    }

    .card::before,
    .card::after {
        transition: 1s;
        background: #e74c3c;
        line-height: 4em;
    }

    .card::before {
        content: '新年';
        width: 150px;
        height: 100%;
        left: 0px;
        top: 0;
        text-align: right;
        position: absolute;
        transform-origin: left bottom;
    }

    .card::after {
        content: '快乐';
        width: 150px;
        height: 100%;
        left: 150px;
        top: 0;
        position: absolute;
        transform-origin: right bottom;
    }

    .card:hover::before {
        transform: rotateY(-179deg);
    }

    .card:hover::after {
        transform: rotateY(179deg);
    }
</style>

<main>
    <div class="card">houdunren</div>
</main>

#open in new window动感菜单

为了让大家清楚理解,下面把思路给大家解析一下。

image

image

#open in new window父级有宽度

设置父级 ul 有宽度,每层都是居中对齐。

image

<style>
    * {
        padding: 0;
        margin: 0;
        list-style: none;
    }

    body {
        width: 100vw;
        height: 100vh;
        background: #2c3e50;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    nav {
        width: 400px;
        height: 400px;
        background: transparent;
        display: flex;
        justify-content: center;
        align-items: center;
        position: relative;

    }

    nav::after {
        content: '大军老师';
        color: #ecf0f1;
        position: absolute;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 2em;
        font-weight: bold;
        text-shadow: 3px 3px 0px #34495e;
        z-index: 1;
    }

    nav::before {
        content: '';
        width: 200px;
        height: 200px;
        background: #e74c3c;
        border-radius: 50%;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        z-index: 1;
    }

    nav:hover ul {
        transform: scale(1);
    }

    ul {
        width: 300px;
        height: 300px;
        transform: scale(0);
        transition: .5s;
    }

    ul li {
        width: 80px;
        height: 80px;
        background: #e74c3c;
        border-radius: 50%;
        position: absolute;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 2.5em;
        color: white;
        transition: 1s;
        transform-origin: 150px 150px;
        box-shadow: 0 0 15px rgba(0, 0, 0.8);
    }

    ul li span {
        transition: 1s;
    }

    nav:hover li:nth-child(1) {
        transform: rotate(40deg);
    }

    nav:hover li:nth-child(1)>span {
        transform: rotate(1040deg);
    }

    nav:hover li:nth-child(2) {
        transform: rotate(80deg);
    }

    nav:hover li:nth-child(2)>span {
        transform: rotate(1000deg);
    }

    nav:hover li:nth-child(3) {
        transform: rotate(120deg);
    }

    nav:hover li:nth-child(3)>span {
        transform: rotate(960deg);
    }

    nav:hover li:nth-child(4) {
        transform: rotate(160deg);
    }

    nav:hover li:nth-child(4)>span {
        transform: rotate(720deg);
    }

    nav:hover li:nth-child(5) {
        transform: rotate(200deg);
    }

    nav:hover li:nth-child(5)>span {
        transform: rotate(880deg);
    }

    nav:hover li:nth-child(6) {
        transform: rotate(240deg);
    }

    nav:hover li:nth-child(6)>span {
        transform: rotate(1680deg);
    }

    nav:hover li:nth-child(7) {
        transform: rotate(280deg);
    }

    nav:hover li:nth-child(7)>span {
        transform: rotate(1920deg);
    }

    nav:hover li:nth-child(8) {
        transform: rotate(320deg);
    }

    nav:hover li:nth-child(8)>span {
        transform: rotate(2200deg);
    }

    nav:hover li:nth-child(9) {
        transform: rotate(360deg);
    }

    nav:hover li:nth-child(9)>span {
        transform: rotate(2520deg);
    }
</style>

<nav>
    <ul>
        <li><span><i class="fa fa-address-book" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-adjust" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-bars" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-book" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-bug" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-compress" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-ban" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-beer" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-bus" aria-hidden="true"></i></span></li>
    </ul>
</nav>

#open in new window父级无宽度

下面代码父级 UL 没有设置宽度,而是使用边框撑开了空间的效果,基本原理和上面一样。

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
        list-style: none;
    }

    body {
        background: #34495e;
    }

    nav {
        position: absolute;
        margin: 0 auto;
        left: 50%;
        top: 50%;
        width: 180px;
        height: 180px;
        background: #34495e;
        border-radius: 50%;
        text-align: center;
        line-height: 180px;
        color: #2c3e50;
        font-weight: bold;
        font-size: 2em;
        background: #f1c40f;
        box-shadow: 0 0 15px rgba(0, 0, 0, .5);
        cursor: pointer;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    nav strong {
        position: absolute;
    }

    nav:hover ul {
        transform: scale(1.3);
    }

    ul {
        transform: scale(0);
        border: 150px solid transparent;
        transition: .5s;
        cursor: pointer;
        z-index: -1;
    }

    ul li {
        position: absolute;
        top: -100px;
        left: -100px;
        width: 50px;
        height: 50px;
        background: #e67e22;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-content: center;
        line-height: 1.5em;
        transition: all 1s;
        transform-origin: 100px 100px;
        box-shadow: 0 0 15px rgba(0, 0, 0, .8);
    }

    ul li span {
        transition: all 1s;
    }

    nav:hover ul li:nth-child(1) {
        transform: rotate(40deg);
    }

    nav:hover ul li:nth-child(1) span {
        transform: rotate(1040deg);
    }

    nav:hover ul li:nth-child(2) {
        transform: rotate(80deg);
    }

    nav:hover ul li:nth-child(2) span {
        transform: rotate(1000deg);
    }

    nav:hover ul li:nth-child(3) {
        transform: rotate(120deg);
    }

    nav:hover ul li:nth-child(3) span {
        transform: rotate(1680deg);
    }

    nav:hover ul li:nth-child(4) {
        transform: rotate(160deg);
    }

    nav:hover ul li:nth-child(4) span {
        transform: rotate(560deg);
    }

    nav:hover ul li:nth-child(5) {
        transform: rotate(200deg);
    }

    nav:hover ul li:nth-child(5) span {
        transform: rotate(520deg);
    }

    nav:hover ul li:nth-child(6) {
        transform: rotate(240deg);
    }

    nav:hover ul li:nth-child(6) span {
        transform: rotate(480deg);
    }

    nav:hover ul li:nth-child(7) {
        transform: rotate(280deg);
    }

    nav:hover ul li:nth-child(7) span {
        transform: rotate(440deg);
    }

    nav:hover ul li:nth-child(8) {
        transform: rotate(320deg);
    }

    nav:hover ul li:nth-child(8) span {
        transform: rotate(400deg);
    }

    nav:hover ul li:nth-child(9) {
        transform: rotate(360deg);
    }

    nav:hover ul li:nth-child(9) span {
        transform: rotate(720deg);
    }
</style>


<nav>
    大军大叔
    <ul>
        <li><span><i class="fa fa-address-book" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-adjust" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-bars" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-book" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-bug" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-compress" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-ban" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-beer" aria-hidden="true"></i></span></li>
        <li><span><i class="fa fa-bus" aria-hidden="true"></i></span></li>
    </ul>
</nav>

#open in new window透视景深

#open in new windowperspective

  • 使用 perspective 来控制元素的透视景深
  • perspective 规则为舞台元素控制景深, perspective 属性为控制单个元素

#open in new window舞台透视

perspective 规则用于将父级整个做为透视元素,会造成里面的每个子元素的透视是不一样的。就像现实中摆一排杯子,是使用统一透视的,每个杯子的透视不一样,造成有大有小。

image

<style>
    article {
        margin: 0 auto;
        margin-top: 150px;
        width: 400px;
        height: 200px;
        position: relative;
        border: solid 5px silver;
        perspective: 200px;
    }

    article div {
        width: 100px;
        height: 100px;
        background: blueviolet;
        box-sizing: border-box;
        margin-right: 80px;
        float: left;
        transform: rotateY(60deg);
    }
</style>

<article>
    <div></div>
    <div></div>
</article>

#open in new window单独透视

perspective 函数用于为元素设置单独透视,下面是为元素单独设置透视参数,每个元素的透视效果是一样的。

image

article div {
  width: 100px;
  height: 100px;
  background: blueviolet;
  box-sizing: border-box;
  margin-right: 80px;
  float: left;
  transform: perspective(100px) rotateY(60deg);
}

#open in new window3D 透视

#open in new windowtransform-style

使用 transform-style 用于控制 3d 透视。

  • 应用于舞台即变形元素的父级元素
  • 设置 overflow:visiblepreserve-3d 才无效
选项说明
flat2D 平面舞台
preserve-3d3D 透视舞台

#open in new window效果体验

下面是设置3D舞台后看到的效果。

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    body {
        background: #34495e;

    }

    main {
        position: relative;
        width: 100vw;
        height: 100vh;
    }

    div {
        position: absolute;
        left: 50%;
        top: 50%;
        height: 200px;
        width: 200px;
        transition: 1s;
        background: #e67e22;
        transform-style: preserve-3d;

    }

    div img {
        height: 80%;
        transform: perspective(500px) translateZ(100px);
    }

    div:hover {
        transform: perspective(600px) rotateY(50deg);
    }
</style>

<main>
    <div>
        <img src="5.jpg" alt="">
    </div>
</main>

#open in new window三维图集

image

<style>
    body {
        background: #34495e;
    }

    main {
        position: absolute;
        width: 400px;
        height: 200px;
        left: 50%;
        top: 50%;
        transform-style: preserve-3d;
        transform-origin: center center -300px;
        transform: translate(-50%, -50%) rotateX(-45deg);
        transition: 2s;
    }

    body:hover main {
        transform: translate(-50%, -50%) rotateX(-45deg) rotateY(900deg);
    }

    div {
        position: absolute;
        width: 100%;
        height: 100%;
        transform-origin: center center -300px;
        overflow: hidden;
    }

    div img {
        height: 100%;
    }

    div:nth-child(1) {
        transform: rotateY(60deg);
    }

    div:nth-child(2) {
        transform: rotateY(120deg);
    }

    div:nth-child(3) {
        transform: rotateY(180deg);
    }

    div:nth-child(4) {
        transform: rotateY(240deg);
    }

    div:nth-child(5) {
        transform: rotateY(300deg);
    }

    div:nth-child(6) {
        transform: rotateY(360deg);
    }
</style>

<main>
    <div>
        <img src="5.jpg" alt="">
    </div>
    <div>
        <img src="1.jpg" alt="">
    </div>
    <div>
        <img src="3.jpg" alt="">
    </div>
    <div>
        <img src="5.jpg" alt="">
    </div>
    <div>
        <img src="1.jpg" alt="">
    </div>
    <div>
        <img src="3.jpg" alt="">
    </div>
</main>

#open in new window观看视角

#open in new windowperspective-origin

perspective-origin用于控制视线的落点,就像我们眼睛看物体时的聚焦点。可以理解眼镜看物体的位置,比如看一台汽车,是在看车头左边看还是车头右边看。

需要设置 perspective 透视后才可以看到效果。

  • 一般设置在舞台元素上来控制子元素

#open in new window位置参数

取值说明
x-axis定义该视图在 x 轴上的位置。默认值:50%。可能的值:left、center、right、length、%
y-axis定义该视图在 y 轴上的位置。默认值:50%。可能的值:top、center、bottom、length、%

#open in new window效果体验

image

<style>
    body {
        background: #2c3e50;
        display: flex;
        width: 100vw;
        height: 100vh;
        justify-content: center;
        align-items: center;
    }

    main {
        border: solid 2px silver;
        width: 400px;
        height: 200px;
        transform-style: preserve-3d;
        transform: rotateY(65deg);
        perspective-origin: right bottom;
        perspective: 900px;
        transition: 2s;
    }

    body:hover main {
        perspective-origin: 1200% bottom;
        /* transform: rotateY(-65deg); */
    }

    div {
        position: absolute;
        width: 200px;
        height: 200px;
        transform: rotateY(60deg);
        overflow: hidden;
    }

    div>img {
        height: 100%;
    }

    div:nth-child(1) {
        background: #e67e22;
    }

    div:nth-child(2) {
        background: #27ae60;
        transform: rotateY(60deg) translateZ(-200px);
    }
</style>
<main>
    <div><img src="3.jpg" alt=""></div>
    <div><img src="5.jpg" alt=""></div>
</main>

#open in new window立方体

image

效果如下

image

<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
        list-style: none;
    }

    body {
        background: #34495e;
    }

    main {
        position: absolute;
        left: 50%;
        top: 50%;
        width: 200px;
        height: 200px;
        transform-style: preserve-3d;
        transform-origin: 50% 50% 50px;
        transform: translate(-50%, -50%) rotateY(0deg);
        transition: 2s;
    }

    main:hover {
        transform: translate(-50%, -50%) rotate3d(1, 1, 0, 180deg);
    }

    div {
        position: absolute;
        width: 200px;
        height: 200px;
        background: #000;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 4em;
    }

    div:nth-child(1) {
        transform-origin: right;
        background: #1abc9c;
        transform-origin: bottom;
        transform: translateY(-200px) rotateX(-90deg);
        opacity: .8;
    }

    div:nth-child(2) {
        transform-origin: right;
        background: #27ae60;
        transform-origin: top;
        transform: translateY(200px) rotateX(90deg);
        opacity: .8;
    }

    div:nth-child(3) {
        transform-origin: bottom;
        background: #e67e22;
        transform-origin: right;
        transform: translateX(-200px) rotateY(90deg);
        opacity: .8;
    }

    div:nth-child(4) {
        transform-origin: top;
        background: #8e44ad;
        transform-origin: left;
        transform: translateX(200px) rotateY(-90deg);
        opacity: .8;
    }

    div:nth-child(5) {
        transform-origin: left bottom;
        background: #ecf0f1;
        opacity: .8;
    }

    div:nth-child(6) {
        transform-origin: left bottom;
        background: #ecf0f1;
        opacity: .5;
        transform: translateZ(200px);
    }
</style>

<main>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>厚道人</div>
</main>

#open in new window隐藏背面

#open in new windowbackface-visibility

使用 backface-visibility 用于控制是否可以看到元素的背面。

  • 一般设置在元素上而不是舞台元素上
  • 需要舞台元素(父级元素)设置 transform-style: preserve-3d
选项说明
visible背面可见
hidden背面隐藏

#open in new window翻转卡片

下面使用隐藏背面与透视技术制作的翻转卡片效果。

image

<script src='https://code.jquery.com/jquery-3.3.1.slim.min.js'></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    main {
        position: absolute;
        width: 100vw;
        height: 100vh;
        transition: 2s;
        transform-style: preserve-3d;
    }

    main.login {
        transform: perspective(900px) rotateY(0deg);
    }

    main.register {
        transform: perspective(900px) rotateY(180deg);
    }

    div {
        position: absolute;
        width: 100%;
        height: 100%;
        font-size: 5em;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        backface-visibility: hidden;
        transition: 2s;
        text-transform: uppercase;
        color: white;
    }

    div span {
        text-transform: lowercase;
        letter-spacing: .2em;
        font-size: .2em;
        color: #2c3e50;
    }

    div:nth-child(1) {
        background: #2ecc71;
        transform: rotateY(0deg);
    }

    div:nth-child(2) {
        background: #e74c3c;
        transform: rotateY(180deg);
    }

    nav {
        position: absolute;
        width: 100%;
        height: 100%;
        z-index: 99;
        text-align: center;
        display: flex;
        align-items: flex-end;
        justify-content: center;
        padding-bottom: 30px;
    }

    nav a {
        padding: 10px;
        text-decoration: none;
        font-size: 1em;
        background: #000;
        color: white;
        margin-right: 10px;
        cursor: pointer;
        left: 0;
        top: 0;
    }
</style>

<main>
    <div>
        <i class="fa fa-home" aria-hidden="true"></i>
        login
        <span>houdunren.com</span>
    </div>
    <div>
        <i class="fa fa-user" aria-hidden="true"></i>
        register
        <span>houdunren.com</span>
    </div>
</main>
<nav>
    <a href="javascript:;" onclick="change('login')">登录</a>
    <a href="javascript:;" onclick="change('register')">注册</a>
</nav>
<script>
    function change(t) {
        switch (t) {
            case 'login':
                $("main").removeClass().addClass('login');
                break;
            case 'register':
                $("main").removeClass().addClass('register');
                break;
        }
    }
</script>

#open in new window常见问题

如果发现元素不能点击,可能是父级设置了 transform-style: preserve-3d 属性,且同级元素设置了 3D 变化特性,造成对点击元素有遮挡。有以下两种方式解决

  1. 对变形元素设置 pointer-events: none; 使用其不接受点击事件
  2. 删除父级的 transform-style: preserve-3d 属性

基础知识

houdunren.com (opens new window)open in new window

默认情况下 CSS 属性的变化是瞬间完成的(其实也有时间只是毫秒级的,人眼很难感知到),而使用本章节学习的 CSS 过渡可以控制让变化过程平滑。

有关变形动画已经讲的很丰富了,请在 厚道人 (opens new window)open in new window查看相应章节。

#open in new window动画属性

不是所有 css 属性都有过渡效果,查看支持动画的 CSS 属性 (opens new window)open in new window,一般来讲有中间值的属性都可以设置动画如宽度、透明度等。

案例分析

下面例子中边框的变化是没有中间值的,所以没有过渡效果。但线宽度是数值类型有中间值所以会有过渡效果。

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 150px;
        height: 150px;
        background-color: #fff;
        border: solid 20px #ddd;
        transition: 2s;
    }

    div:hover {
        border-radius: 50%;
        border: dotted 60px #ddd;
        background-color: #e67e22;
    }
</style>

<main>
    <div></div>
</main>

#open in new window元素状态

#open in new window初始形态

指当页面加载后的样式状态,下面是表单设置的初始样式。

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 20px;
    }

    input {
        border: solid 5px #e67e22;
        height: 60px;
        width: 100%;
        margin-bottom: 20px;
    }

    input:checked {
        position: relative;
        width: 60px;
        height: 60;
        border: none;
    }

    input:checked::before {
        content: '⩗';
        color: white;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 3em;
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        box-sizing: border-box;
        background: #3498db;
    }
</style>

<input type="text">
<input type="checkbox" checked>

#open in new window变化形态

指元素由初始状态变化后的状态,比如鼠标放上、表单获得焦点后的形态。

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
         padding: 20px;
    }

    input {
        border: solid 5px #e67e22;
        height: 60px;
        width: 100%;
        margin-bottom: 20px;
        transition: 2s;
    }

    input:hover {
        border: solid 5px #000 !important;
    }

    input:focus {
        background: #e67e22;
    }

    input:checked {
        position: relative;
        width: 60px;
        height: 60;
        border: none;
    }

    input:checked::before {
        content: '⩗';
        color: white;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 3em;
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        box-sizing: border-box;
        background: #3498db;
    }
</style>

<input type="text">
<input type="checkbox" checked>

#open in new windowtransition-property

用于设置哪些属性应用过渡效果。

  • 默认值为all 即所有属性都发生过渡效果
  • 多个属性使用逗号分隔

#open in new window属性设置

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 150px;
        height: 150px;
        background-color: #e67e22;
        border-radius: 50%;
        transition-property: background-color, transform, opacity, border-radius;
        transition-duration: 3s;
    }

    main:hover div {
        border-radius: 0;
        transform: scale(2) rotate(180deg);
        background-color: #e67e22;
    }
</style>

<main>
    <div></div>
</main>

#open in new window禁用属性

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 200px;
        height: 200px;
        background: #e74c3c;
        transition-property: background, transform;
        transition-duration: 2s;
        margin-bottom: 50px;
    }

    main:hover div{
        transform: scale(1.5) rotate(180deg);
        background: #9b59b6;
    }

    div:last-child {
        transition-property: none;
    }
</style>

<main>
    <div></div>
    <div></div>
</main>

#open in new windowtransitionend

用于控制过渡结束后执行的 JS 事件,简写属性会触发多次如 border-radius 会触发四次事件,不难理解因为可以为border-bottom-left-radius 等四个属性独立设置过渡,所以就会有四次事件。

属性说明
propertyName结束过渡样式
elapsedTime过渡需要的时间
pseudoElement过渡的伪元素
isTrustedtrue:用户触发,false:脚本触发

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        width: 100vw;
        height: 100vh;
        background: #34495e;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 200px;
        height: 200px;
        position: relative;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        flex-wrap: nowrap;
    }

    div::before {
        content: '厚道人';
        font-size: 3em;
        color: #2c3e50;
        background: #95a5a6;
        width: 200px;
        height: 200px;
        display: flex;
        justify-content: center;
        align-items: center;
        border-radius: 10%;
        transition-duration: 2s;
        cursor: pointer;
    }

    div:hover::before {
         transition-duration: 1.5s;
                 border-radius: 50%;
                 background: #f1c40f;
         transform: rotate(360deg);
    }

    div::after {
        content: 'houdunren.com';
        text-transform: uppercase;
        position: absolute;
        bottom: -60px;
        font-size: 2em;
        color: #95a5a6;
        text-align: center;
        transform: translateX(-999px) skew(45deg);
        transition-duration: 1s;
    }

    div.move::after {
        transform: translateX(0px) skew(0deg);
    }
</style>

<main>
    <div>

    </div>
</main>
<script>
    document.querySelector('div').addEventListener('transitionend', function (e) {
        console.log(e);
        document.querySelector('div').className = 'move';
    })
</script>

#open in new windowtransition-duration

用于设置过渡时间,需要注意以下几点

  • 可使用单位为 ms 毫秒、s 秒
  • 默认值为 0s 不产生过渡效果
  • 一个值时,所有属性使用同样的时间
  • 二个值时,奇数属性使用第一个,偶数属性使用第二个
  • 变化属性数量大于时间数量时,后面的属性再从第一个时间开始重复使用

#open in new window统一时间

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 150px;
        height: 150px;
        background-color: #34495e;
        border-radius: 50%;
        opacity: 0.2;
        transition-property: background-color, transform, opacity, border-radius;
        transition-duration: 3s;
    }

    div:hover {
        opacity: 1;
        border-radius: 0;
        transform: scale(2) rotate(180deg);
        background-color: #e67e22;
    }
</style>

<main>
    <div></div>
</main>

#open in new window两个时间

下面共有四个属性并设置了两个时间值,1,3 属性使用第一个值,2,4 属性使用第二个值。

... div {
  width: 150px;
  height: 150px;
  background-color: #34495e;
  border-radius: 50%;
  opacity: 0.2;
  transition-property: background-color, transform, opacity, border-radius;
  transition-duration: 200ms, 5s;
}
...;

#open in new window多个时间

下面共有四个属性并设置了三个时间值,1,2,3 属性使用 1,2,3 时间值,第四个属性再从新使用第一个时间值。

... div {
  width: 150px;
  height: 150px;
  background-color: #34495e;
  border-radius: 50%;
  opacity: 0.2;
  transition-property: background-color, transform, opacity, border-radius;
  transition-duration: 200ms, 5s, 2s;
}
...;

#open in new window不同时间

可以为初始与变化状态设置不同的时间。

下面是将hover 设置为 3s,当鼠标放上时变化时间为 3s。为初始设置为 1s 即表示变化到初始状态需要 1s。

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 150px;
        height: 150px;
        background-color: #e67e22;
        border-radius: 50%;
        transition-property: background-color, transform, opacity, border-radius;
        transition-duration: 1s;
    }

    div:hover {
        border-radius: 0;
        transform: scale(2) rotate(180deg);
        background-color: #e67e22;
        transition-duration: 3s;
    }
</style>

<main>
    <div></div>
</main>

#open in new windowtransition-timing-function

用于设置过渡效果的速度,可在 https://cubic-bezier.com (opens new window)open in new window网站在线体验效果差异。

#open in new window默认参数

描述
linear规定以相同速度开始至结束的过渡效果(等于 cubic-bezier(0,0,1,1))。
ease开始慢,然后快,慢下来,结束时非常慢(cubic-bezier(0.25,0.1,0.25,1))
ease-in开始慢,结束快(等于 cubic-bezier(0.42,0,1,1))
ease-out开始快,结束慢(等于 cubic-bezier(0,0,0.58,1))
ease-in-out中间快,两边慢(等于 cubic-bezier(0.42,0,0.58,1))
cubic-bezier(n,n,n,n)在 cubic-bezier 函数中定义自己的值
<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 150px;
        height: 150px;
        background-color: #e67e22;
        border-radius: 50%;
        transition-property: background-color, transform, opacity, border-radius;
        transition-duration: 3s;
        transition-timing-function: ease;
    }

    div:hover {
        border-radius: 0;
        transform: scale(2) rotate(180deg);
        background-color: #e67e22;
    }
</style>

<main>
    <div></div>
</main>

#open in new window贝塞尔曲线

需要设置四个值 cubic-bezier(<x1>, <y1>, <x2>, <y2>),来控制曲线速度,可在 https://cubic-bezier.com (opens new window)open in new window网站在线体验效果。

image

... div {
  width: 150px;
  height: 150px;
  background-color: #e67e22;
  border-radius: 50%;
  transition-property: background-color, transform, opacity, border-radius;
  transition-duration: 3s;
  transition-timing-function: cubic-bezier(0.17, 0.67, 0.86, 0.49);
}
...;

#open in new window步进速度

过渡使用阶梯化呈现,有点像现实生活中的机械舞,下面是把过渡分五步完成。

选项说明
steps(n,start)设置 n 个时间点,第一时间点变化状态
steps(n,end)设置 n 个时间点,第一时间点初始状态
step-start等于 steps(1,start),可以理解为从下一步开始
step-end等于 steps(1,end),可以理解为从当前步开始

#open in new windowsteps

image

<head>
    <style>
        body {
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background: #34495e;
        }

        ul {
            width: 800px;
            height: 300px;
            list-style: none;
            display: flex;
            justify-content: space-between;
            position: relative;
        }

        li {
            flex: 1;
            border: solid 1px #ddd;
            text-align: center;
            padding-top: 20px;
        }

        li::before {
            content: 'houdunren.com';
            font-size: 1.2em;
            text-align: center;
            color: white;
            opacity: .3;
        }

        ul::before,
        ul::after {
            text-align: center;
            font-size: 2em;
            line-height: 100px;
            color: white;
            z-index: 2;
        }

        ul::before {
            content: 'start';
            position: absolute;
            width: 200px;
            height: 100px;
            background: #e67e22;
            transition-duration: 2s;
            transition-timing-function: steps(4, start);
            box-sizing: border-box;
            border-left: solid 10px #fff;
        }

        ul::after {
            content: 'end';
            position: absolute;
            bottom: 0;
            width: 200px;
            height: 100px;
            background: #9b59b6;
            transition-duration: 2s;
            transition-timing-function: steps(4, end);
            box-sizing: border-box;
            border-right: solid 10px #fff;
        }

        ul:hover::before {
            transform: translateX(800px);
        }

        ul:hover::after {
            transform: translateX(800px);
        }
    </style>
</head>

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

#open in new window时钟效果

image

<head>
    <style>
        body {
            width: 100vw;
            height: 100vh;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            background: #34495e;
        }

        main {
            width: 400px;
            height: 400px;
            background: #ecf0f1;
            border-radius: 50%;
            position: relative;
        }

        main::before {
            content: '';
            width: 20px;
            height: 20px;
            background: #333;
            position: absolute;
            left: 50%;
            top: 50%;
            border-radius: 50%;
            transform: translate(-50%, -50%)
        }

        main::after {
            content: '';
            width: 5px;
            height: 50%;
            background: #333;
            position: absolute;
            left: 50%;
            bottom: 50%;
            transform: translateX(-50%);
            transform-origin: bottom;
            transition-duration: 60s;
            transition-timing-function: steps(60, end);
        }

        body:hover main::after {
            transform: translateX(-50%) rotate(360deg);
        }
    </style>
</head>

<body>
    <main>
    </main>
    <h3>houdunren.com</h3>
</body>

#open in new windowstep-start/end

image

<head>
    <style>
        body {
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background: #34495e;
        }

        ul {
            width: 400px;
            height: 300px;
            list-style: none;
            display: flex;
            justify-content: space-between;
            position: relative;
        }

        li {
            flex: 1;
            border: solid 1px #ddd;
            text-align: center;
            padding-top: 20px;
        }

        li::before {
            content: 'houdunren.com';
            font-size: 1.2em;
            text-align: center;
            color: white;
            opacity: .3;
        }

        ul::before,
        ul::after {
            text-align: center;
            font-size: 2em;
            line-height: 100px;
            color: white;
            z-index: 2;
        }

        ul::before {
            content: 'start';
            position: absolute;
            width: 200px;
            height: 100px;
            background: #e67e22;
            transition-duration: 1s;
            transition-timing-function: step-start;
            box-sizing: border-box;
            border-left: solid 10px #fff;
        }

        ul::after {
            content: 'end';
            position: absolute;
            bottom: 0;
            width: 200px;
            height: 100px;
            background: #9b59b6;
            transition-duration: 1s;
            transition-timing-function: step-end;
            box-sizing: border-box;
            border-right: solid 10px #fff;
        }

        ul:hover::before {
            transform: translateX(200px);
        }

        ul:hover::after {
            transform: translateX(200px);
        }
    </style>
</head>

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

#open in new window步进形态

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 150px;
        height: 150px;
        background-color: #e67e22;
        border-radius: 50%;
        transition-property: background-color, transform, opacity, border-radius;
        transition-duration: 3s;
        transition-timing-function: steps(5, end);
    }

    div:hover {
        border-radius: 0;
        transform: scale(2) rotate(180deg);
        background-color: #e67e22;
    }
</style>

<main>
    <div></div>
</main

#open in new window变化广告

image

<head>
    <style>
        body {
            width: 100vw;
            height: 100vh;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            background: #34495e;
        }

        main {
            width: 400px;
            height: 200px;
            position: relative;
            overflow: hidden;
        }

        section {
            width: 800px;
            height: 200px;
            display: flex;
            transition-duration: 1s;
            transition-timing-function: step-start;
        }

        div {
            width: 400px;
            height: 200px;
            overflow: hidden;
        }

        main:hover section {
            transform: translateX(-400px);
        }
    </style>
</head>

<body>
    <main>
        <section>
            <div><img src="3.jpg" alt=""></div>
            <div><img src="5.jpg" alt=""></div>
        </section>
    </main>
</body>

#open in new windowtransition-delay

用于设置延迟过渡的时间。

  • 默认为 0s 即立刻开始过渡
  • 值可以为负数
  • 变化属性数量大于时间数量时,后面的属性再从第一个时间开始重复使用

#open in new window基本使用

下面设置了延迟时间为 1s,当鼠标放上

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 150px;
        height: 150px;
        background-color: #e67e22;
        border-radius: 50%;
        transition-property: background-color, transform, opacity, border-radius;
        transition-duration: 1s;
        transition-delay: 1s;
    }

    div:hover {
        border-radius: 0;
        transform: scale(2) rotate(180deg);
        background-color: #e67e22;
    }
</style>

<main>
    <div></div>
</main>

#open in new window多值延迟

可以设置不同属性的延迟时间。

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 150px;
        height: 150px;
        background-color: #fff;

        transition-property: background-color, transform, border-radius;
        transition-duration: 1s, 2s, 3s;
        transition-delay: 1s, 3s, 5s;
    }

    div:hover {
        border-radius: 50%;
        transform: scale(2) rotate(180deg);
        background-color: #e67e22;
    }
</style>

<main>
    <div></div>
</main>

#open in new window使用负值

下例圆角属性的过渡时间为 4s,设置延迟为 -4s,表示鼠标放上时直接显示在 4s 上的效果。如果设置为-2s 显示圆角变形一半的效果。

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 150px;
        height: 150px;
        background-color: #fff;

        transition-property: background-color, transform, border-radius;
        transition-duration: 1s, 2s, 4s;
        transition-delay: 1s, 2s, -4s;
    }

    div:hover {
        border-radius: 50%;
        transform: scale(2) rotate(180deg);
        background-color: #e67e22;
    }
</style>

<main>
    <div></div>
</main>

#open in new windowtransition

可以使用transition 指令将过渡规则统一设置,需要注意以下几点。

  • 必须设置过渡时间
  • 延迟时间放在逗号或结束前
transition: border-radius linear 2s 0s, background 2s 2s, width linear 2s 4s, height
    linear 2s 4s;

#open in new window点赞案例

image

 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src='https://code.jquery.com/jquery-3.3.1.slim.min.js'></script>
<style>
    body {
        width: 100vw;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        background: #ecf0f1;
    }

    div {
        position: relative;
        width: 100px;
        height: 100px;
        cursor: pointer;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    div i.fa {
        font-size: 100px;
        position: absolute;
        transition: all .5s;
        color: #ddd;
    }

    div.heart i.fa {
        font-size: 400px;
        color: #e74c3c;
        opacity: 0;
    }

    div.heart i.fa:nth-child(2) {
        font-size: 80px;
        color: #e74c3c;
        opacity: 1;
    }
</style>

<body>
    <div onclick="heart()">
        <i class="fa fa-heart" aria-hidden="true"></i>
        <i class="fa fa-heart" aria-hidden="true"></i>
    </div>
    <script>
        function heart() {
            $("div").toggleClass('heart');
        }
    </script>
</body>

基础知识

houdunren.com (opens new window)open in new window

通过定义一段动画中的关键点、关键状态来创建动画。Keyframes 相比 transition 对动画过程和细节有更强的控制。

过渡动画是两个状态间的变化,帧动画可以处理动画过程中不同时间的细节变化,不过对过渡动画理解后再不习帧动画会非常容易,也可以把帧动画理解为多个帧之间的过渡动画。

#open in new window关键帧

使用@keyframes 规则配置动画中的各个帧

  • from 表示起始点
  • to 表示终点
  • 可以使用百分数如 20%动画运行到 20%时间时

#open in new window基本使用

下面使用 @keyframes 定义了动画叫 hd 并配置了两个帧动作from/to ,然后在 div 元素中使用animation-name 引用了动画并使用animation-duration声明执行三秒。

  • 动画命名不要使用 CSS 关键字如 none

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
    }

    div {
        width: 150px;
        height: 150px;
        background-color: #fff;
        border: solid 20px #ddd;
        animation-name: hd;
        animation-duration: 3s;
    }

    @keyframes hd {
        from {
            opacity: 0;
            transform: scale(.1);
        }

        to {
            opacity: 1;
        }
    }
</style>

<main>
    <div></div>
</main>

#open in new window时间点

帧动画需要定义在不同时间执行的动作,开始与结束可以使用 form/to0%/100% 声明。

  • 必须添加百分号,25%是正确写法
  • 时间点没有顺序要求,即 100%写在 25%前也可以
  • 未设置0%100% 时将使用元素原始状态

#open in new window物体移动

下面定义不同时间点来让物体元素移动一圈,下例中可以不设置from/to 系统将定义为元素初始状态。

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
        border: solid 2px white;
    }

    div {
        width: 100px;
        height: 100px;
        background-color: #e67e22;
        animation-name: hd;
        animation-duration: 3s;
    }

    @keyframes hd {
        0% {}

        25% {
            transform: translateX(300%);
        }

        50% {
            transform: translate(300%, 300%);
        }

        75% {
            transform: translate(0, 300%);
        }

        to {}
    }
</style>

<main>
    <div></div>
</main>

#open in new window同时声明

时间点可以动画样式一样时可以一起声明,下面将 25%/75%背景一起声明。

image

<style>
    * {
        padding: 0;
        margin: 0;
    }

    body {
        background: #2c3e50;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
        width: 100vw;
        height: 100vh;
        padding: 80px;
    }

    main {
        width: 400px;
        height: 400px;
        border: solid 2px white;
    }

    div {
        width: 100px;
        height: 100px;
        background-color: #e67e22;
        animation-name: hd;
        animation-duration: 3s;
    }

    @keyframes hd {
        25% {
            transform: translateX(300%);
        }

        50% {
            transform: translate(300%, 300%);
        }

        75% {
            transform: translate(0, 300%);
        }

        25%,
        75% {
            background: #9b59b6;
            border-radius: 50%;
        }

        50%,
        100% {
            background: #e67e22;
        }
    }
</style>

<main>
    <div></div>
</main>

#open in new window使用动画

使用animation-name 规则可以在元素身上同时使用多个动画。

  • 使用多个动画时用逗号分隔
  • 多个动画有相同属性时,后面动画的属性优先使用

#open in new window基本使用

image

<style>
    main {
        width: 400px;
        height: 400px;
        border: solid 5px #95a5a6;
    }

    div {
        width: 100px;
        height: 100px;
        background-color: #e67e22;
        animation-name: hd, scale;
        animation-duration: 3s;
    }

    @keyframes hd {
        25% {
            transform: translateX(300%);
        }

        50% {
            transform: translate(300%, 300%);
        }

        75% {
            transform: translate(0, 300%);
        }

        25%,
        75% {
            background: #9b59b6;
        }

        50%,
        100% {
            background: #e67e22;
        }

    }

    @keyframes scale {
        from {
            border-radius: 0;
        }

        75% {
            border-radius: 50%;
        }

        to {
            border-radius: 0;
        }
    }
</style>

<main>
    <div></div>
</main>

#open in new window动画时间

使用 animation-duration 可以声明动画播放的时间,即把所有帧执行一遍所需要的时间。

  • 可以使用 m 秒,ms 毫秒时间单位
  • 可为不同动画单独设置执行时间
  • 如果动画数量大于时间数量,将重新从时间列表中计算

#open in new window炫彩背景

下面实例声明三个动画,使用 animation-duration为每个动画设置不同执行的时间。

image

<style>
    main {
        background: #34495e;
        animation-name: scale, colors, rotate;
        animation-duration: 1s, 5s, 1s;
        animation-fill-mode: forwards;
    }

    @keyframes scale {
        from {
            width: 0;
            height: 0;
        }

        to {
            width: 100vw;
            height: 100vh;
        }
    }

    @keyframes colors {
        0% {
            background: #e67e22;
        }

        50% {
            background: #34495e;
        }

        100% {
            background: #16a085;
        }
    }

    @keyframes rotate {
        0% {
            transform: rotate(0deg);
        }

        50% {
            transform: rotate(-360deg);
        }

        100% {
            transform: rotate(360deg);
        }
    }
</style>

<body>
    <main></main>
</body>

#open in new window属性重叠

如果多个帧动画设置了相同的属性,不同浏览器的对待方式略有不同。比如 chrome/edge 最新版本对动画的计算就有变化。

我们先来看代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>厚道人</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }

      body {
        width: 100vw;
        height: 100vh;
        background: #34495e;
        display: flex;
        justify-content: center;
        align-items: center;
      }

      main {
        width: 400px;
        height: 400px;
        border: solid 1px #ddd;
      }

      div {
        width: 100px;
        height: 100px;
        background: #f1c40f;
        animation-name: translate, background;
        animation-duration: 4s, 4s;
      }

      @keyframes translate {
        25% {
          transform: translateX(300px);
        }

        50% {
          transform: translate(300px, 300px);
        }

        75% {
          transform: translateY(300px);
        }
      }

      @keyframes background {
        25% {
          background: #2ecc71;
          transform: translateX(300px);
        }

        50% {
          background: #e67e22;
        }

        75% {
          background: #9b59b6;
        }
      }
    </style>
  </head>

  <body>
    <main>
      <div></div>
    </main>
  </body>
</html>

上面的示例在早期 chrome 与 safari 浏览器效果是相同的。

  • 后面的 background 动画优先级高,4 秒时长的动画都用 background 动画来控制 translate 属性

image

在最新版本的 chrome/edge 中执行过程将两个帧动画结合处理

  • 前 25%帧使用 background 的动画
  • 25%帧后综合使用 background 与 translate 动画

image

所以建议尽量不要在两个动画中控制相同的属性

#open in new window动画属性

不是所有 css 属性都有过渡效果,查看支持动画的 CSS 属性 (opens new window)open in new window,一般来讲有中间值的属性都可以设置动画如宽度、透明度等。

#open in new window属性体验

下例中的边框变化没有中间值,所以是瞬间改变也没有产生动画效果。

image

<head>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        h2 {
            color: #f39c12;
        }

        body {
            width: 100vw;
            height: 100vh;
            background: #34495e;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
        }

        main {
            width: 100px;
            height: 100px;
            background: white;
            animation-name: hd;
            animation-duration: 2s;
        }

        @keyframes hd {
            0% {
                background: #9b59b6;
                border: solid 10px #000;
            }

            100% {
                width: 200px;
                height: 200px;
                background: #e74c3c;
                border: double 10px #000;
            }
        }
    </style>
</head>

<body>
    <main></main>
    <h2>houdunren.com</h2>
</body>

#open in new window中间值

下面是例子尺寸没有产生动画,因为0%帧设置的尺寸单位与 100% 设置的尺寸没有中间值,解析器没有办法计算,最终效果如下:

image

正确效果应该是这样

image

<head>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        h2 {
            color: #f39c12;
        }

        body {
            width: 100vw;
            height: 100vh;
            background: #34495e;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
        }

        main {
            width: 100px;
            height: 100px;
            background: white;
            animation-name: hd;
            animation-duration: 2s;
        }

        @keyframes hd {
            0% {
                width: auto;
                height: auto;
                background: #9b59b6;
            }

            100% {
                width: 200px;
                height: 200px;
                background: #e74c3c;
            }
        }
    </style>
</head>

<body>
    <main></main>
    <h2>houdunren.com</h2>
</body>

#open in new window重复动画

使用animation-iteration-count 规则设置动画重复执行次数,设置值为 infinite 表示无限循环执行。

  • 可同时设置元素的多个动画重复,使用逗号分隔
  • 如果动画数量大于重复数量定义,后面的动画将重新计算重复

#open in new window心动感觉

下面是画心的步骤

image

使用循环动画绘制心动效果

image

<style>
    .heart {
        width: 200px;
        height: 200px;
        background: #e74c3c;
        transform: rotate(45deg);
        position: relative;
        animation-name: heart;
        animation-duration: 1s;
        animation-iteration-count: 100;
    }

    .heart::before {
        content: '';
        width: 200px;
        height: 200px;
        border-radius: 50%;
        background: #e74c3c;
        position: absolute;
        transform: translate(-50%, 0px);
    }

    .heart::after {
        content: '';
        width: 200px;
        height: 200px;
        border-radius: 50%;
        background: #e74c3c;
        position: absolute;
        transform: translate(0%, -50%);
    }

    @keyframes heart {
        from {
            transform: scale(.3) rotate(45deg);
        }

        to {
            transform: scale(1) rotate(45deg);
        }
    }
</style>

<main>
    <div class="heart"></div>
</main>

#open in new window动画方向

使用 animation-direction 控制动画运行的方向。

选项说明
normal从 0%到 100%运行动画
reverse从 100%到 0%运行动画
alternate先从 0%到 100%,然后从 100%到 0%
alternate-reverse先从 100%到 0%,然后从 0%到 100%

#open in new window效果比较

image

<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        h2 {
            color: #f39c12;
        }

        body {
            width: 100vw;
            height: 100vh;
            background: #34495e;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
        }

        ul {
            width: 400px;
            height: 100px;
            display: flex;
        }

        li {
            list-style: none;
            text-align: center;
            display: flex;
            flex-direction: column;
            flex: 1;
            justify-content: space-between;
        }

        li span {
            font-size: 10px;
            color: #ecf0f1;
        }

        i.fa {
            font-size: 30px;
            margin: 5px;
            color: #e74c3c;
            animation-name: hd;
            animation-duration: 2s;
            animation-iteration-count: infinite;
        }

        li:nth-child(1)>i.fa {
            animation-direction: normal;
        }

        li:nth-child(2)>i.fa {
            animation-direction: reverse;
        }

        li:nth-child(3)>i.fa {
            animation-direction: alternate;
        }

        li:nth-child(4)>i.fa {
            animation-direction: alternate-reverse;
        }

        @keyframes hd {
            from {}

            to {
                opacity: 1;
                transform: scale(3);
            }
        }
    </style>
</head>

<body>
    <ul>
        <li>
            <i class="fa fa-heart" aria-hidden="true"></i>
            <span>normal</span>
        </li>
        <li>
            <i class="fa fa-heart" aria-hidden="true"></i>
            <span>reverse</span>
        </li>
        <li>
            <i class="fa fa-heart" aria-hidden="true"></i>
            <span>alternate</span>
        </li>
        <li>
            <i class="fa fa-heart" aria-hidden="true"></i>
            <span>alternate-reverse</span>
        </li>
    </ul>
</body>

#open in new windowreverse

根据上面的心动例子改变方向为 100%~0%

image

#open in new windowalternate

根据上面的心动例子改变方向为 0%~~100%然后 100%~~0%

image

animation-direction: alternate-reverse;

#open in new windowalternate-reverse

通过使用合适的运动方向 alternate-reverse 制作跳动的小球

image

<style>
    main {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }

    div {
        width: 200px;
        height: 200px;
        border-radius: 50%;
        background: #e67e22;
        animation-name: ball;
        animation-duration: 2s;
        animation-iteration-count: infinite;
        animation-direction: alternate-reverse;
    }

    @keyframes ball {
        0% {}

        100% {
            transform: translateY(-600px);
        }
    }

    section {
        width: 400px;
        height: 10px;
        border-radius: 50%;
        animation-name: shadow;
        animation-duration: 2s;
        animation-iteration-count: infinite;
        animation-direction: alternate;
    }

    @keyframes shadow {
        from {
            background: #000;
            transform: scale(1);
            filter: blur(35px);
        }

        to {
            background: #aaa;
            filter: blur(10px);
        }
    }
</style>

<main>
    <div></div>
    <section></section>
</main>

#open in new window延迟动画

使用 animation-delay 规则定义动画等待多长时间后执行。

#open in new window微场景

image

<style>
    body {
        width: 100vw;
        height: 100vh;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
    }

    header {
        width: 100vw;
        height: 10vh;
        font-size: 2.5em;
        color: white;
        background: #e74c3c;
        text-align: center;
        line-height: 10vh;
        animation-name: hd-translate;
        animation-duration: 500ms;
    }

    main {
        flex: 1;
        width: 100vw;
        height: 300px;
        left: 0;
        bottom: 0;
        background: url("5.jpg") no-repeat right bottom;
        background-size: cover;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        transform: translateX(-100vw);
        animation-name: hd-rotate;
        animation-duration: 1s;
        animation-fill-mode: forwards;
    }

    main>* {
        opacity: .8;
        font-size: 1.2em;
        line-height: 2em;
        color: #f3f3f3;
        padding: 20px;
        border-radius: 10px;
        box-shadow: 0 0 5px rgba(0, 0, 0, .6);
    }

    main>.lesson {
        width: 80vw;
        height: 40vw;
        background: #8e44ad;
        transform: translate(-100vw, -100vh);
        animation-name: hd-rotate;
        animation-duration: 1s;
        animation-delay: 1s;
        animation-fill-mode: forwards;
    }

    main>.video {
        margin-top: 20px;
        width: 60vw;
        height: 40vw;
        background: #2980b9;
        animation-name: hd-translate;
        animation-duration: 1s;
        animation-delay: 2s;
        transform: translate(-100vw, -100vh);
        animation-fill-mode: forwards;
    }

    footer {
        width: 100vw;
        height: 10vh;
        font-size: 1.5em;
        color: white;
        background: #27ae60;
        text-align: center;
        line-height: 10vh;
        animation-name: hd-skew;
        animation-duration: 500ms;
        animation-delay: 3s;
        transform: translateX(-100vw);
        animation-fill-mode: forwards;
    }

    @keyframes hd-translate {
        from {
            transform: translate(-100vw, -100vh);
        }

        to {
            transform: translateY(0);
        }
    }

    @keyframes hd-rotate {
        from {
            transform: translate(-100%, -100%);
        }

        to {
            transform: translateX(0) rotate(360deg);
        }
    }

    @keyframes hd-skew {
        from {
            transform: translateX(-100%) skew(-45deg);
        }

        to {
            transform: skewX(0deg);
        }
    }
</style>

<body>
    <header>
        厚道人
    </header>
    <main>
        <div class="lesson">
            系统课程是多个实战课程的组合,用来全面掌握一门语言或软件的使用,尤其适合刚入门的新手系统牢固的掌握知识。
        </div>
        <div class="video hd-translate">
            系统课程是多个实战课程的组合,用来全面掌握一门语言或软件的使用,尤其适合刚入门的新手系统牢固的掌握知识。
        </div>
    </main>
    <footer>
        houdunren.com
    </footer>
</body>

#open in new window动画速率

#open in new window系统属性

描述
linear规定以相同速度开始至结束的过渡效果(等于 cubic-bezier(0,0,1,1))。
ease开始慢,然后快,慢下来,结束时非常慢(cubic-bezier(0.25,0.1,0.25,1))
ease-in开始慢,结束快(等于 cubic-bezier(0.42,0,1,1))
ease-out开始快,结束慢(等于 cubic-bezier(0,0,0.58,1))
ease-in-out中间快,两边慢(等于 cubic-bezier(0.42,0,0.58,1))
cubic-bezier(n,n,n,n)在 cubic-bezier 函数中定义自己的值
  • 可以在帧中单独定义,将影响当前帧的速率

#open in new window贝塞尔曲线

需要设置四个值 cubic-bezier(<x1>, <y1>, <x2>, <y2>),来控制曲线速度,可在 https://cubic-bezier.com (opens new window)open in new window网站在线体验效果。

image

#open in new window体验效果

image

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>厚道人</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        body {
            width: 100vw;
            height: 100vh;
            background: #2c3e50;
            display: grid;
            grid-template-columns: 1fr;
        }

        body::before {
            content: 'houdunren.com';
            color: white;
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translateX(-50%);
            opacity: .5;
        }

        ul {
            box-sizing: border-box;
            list-style: none;
            display: grid;
            grid-template-columns: repeat(5, 1fr);
            gap: 10px;
        }

        li {
            box-sizing: border-box;
            background: #e67e22;
            animation-name: move;
            animation-duration: 3s;
            animation-iteration-count: infinite;
            color: #333333;
        }

        li:nth-child(1) {
            animation-timing-function: ease;
        }

        li:nth-child(2) {
            animation-timing-function: ease-in;
        }

        li:nth-child(3) {
            animation-timing-function: ease-out;
        }

        li:nth-child(4) {
            animation-timing-function: ease-in-out;
        }

        li:nth-child(5) {
            animation-timing-function: linear;
        }

        @keyframes move {
            to {
                transform: translateY(90vh);
            }
        }
    </style>
</head>

<body>
    <ul>
        <li>ease</li>
        <li>ease-in</li>
        <li>ease-out</li>
        <li>ease-in-out</li>
        <li>linear</li>
    </ul>
</body>

#open in new window弹跳小球

image

<head>
    <style>
        body {
            width: 100vw;
            height: 100vh;
            display: flex;
            flex-direction: column;
            justify-content: flex-end;
            align-items: flex-start;
            background: #2c3e50;
        }

        div {
            position: absolute;
            width: 100px;
            height: 100px;
            left: 30%;
            top: 0px;
            transform: translate(0vw, 0);
            background: radial-gradient(at right top, #f39c12, #d35400);
            border-radius: 50%;
            animation-name: jump;
            animation-duration: 2s;
            animation-iteration-count: infinite;
            animation-timing-function: ease-in;
        }

        div:nth-child(2) {
            animation-delay: .2s;
            left: 60%;
        }

        @keyframes jump {
            0% {
                transform: translateY(0);
                animation-timing-function: ease-in;
            }

            30% {
                transform: translateY(10vh);
                animation-timing-function: ease-in;
            }

            60% {
                transform: translateY(40vh);
                animation-timing-function: ease-in;
            }

            80% {
                transform: translateY(60vh);
                animation-timing-function: ease-in;
            }

            95% {
                transform: translateY(75vh);
                animation-timing-function: ease-in;
            }

            15%,
            45%,
            70%,
            85%,
            100% {
                transform: translateY(80vh);
                animation-timing-function: ease-out;
            }
        }
    </style>
</head>

<body>
    <div></div>
    <div></div>
</body>

#open in new window魔术小球

image

<style>
    body {
        width: 100vw;
        height: 100vh;
        display: flex;
        flex-direction: column;
        justify-content: flex-end;
        align-items: flex-start;
        background: #2c3e50;
    }

    div {
        position: absolute;
        width: 100px;
        height: 100px;
        transform: translate(-20vw, -300%);
        background: radial-gradient(at right top, #f39c12, #d35400);
        border-radius: 50%;
        animation-name: jump;
        animation-duration: 1.5s;
        animation-iteration-count: infinite;
        animation-timing-function: ease-in;
    }

    div:nth-child(2) {
        animation-delay: .2s;
    }

    div:nth-child(3) {
        animation-delay: 1s;
    }

    @keyframes jump {
        0% {
            transform: translate(-20vw, -300%);
        }

        10% {
            transform: scaleY(.9) translate(15vw, 0%);
        }

        20% {
            transform: translate(20vw, -200%);
        }

        30% {
            transform: scaleY(.9) translate(30vw, 0%);
        }

        40% {
            transform: translate(40vw, -120%);
        }

        50% {
            transform: scaleY(.9) translate(50vw, 0%);
        }

        60% {
            transform: translate(60vw, -70%);
        }

        70% {
            transform: scaleY(.9) translate(70vw, 0%);
        }

        80% {
            transform: translate(80vw, -50%);
        }

        90% {
            transform: scaleY(.9) translate(90vw, 0%);
        }

        95% {
            transform: translate(95vw, -30%);
        }

        100% {
            transform: scaleY(.9) translate(100vw, 0%);
        }
    }

    @keyframes move {
        0% {
            /* transform: translateY(-400%); */
        }

        100% {
            /* right: 100px; */
        }
    }
</style>

<body>
    <div></div>
    <div></div>
    <div></div>
</body>

#open in new window按钮提交

image

<head>
    <style>
        body {
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background: #34495e;
        }

        button {
            padding: 10px 50px;
            outline: none;
            background: #e67e22;
            font-size: 2em;
            border: solid 5px white;
            color: white;
        }

        button::after {
            content: '';
            display: inline-block;
            height: 3px;
            width: 3px;
            box-shadow: 3px 0 currentColor, 9px 0 currentColor, 15px 0 currentColor;
            animation-name: point;
            animation-duration: 1s;
            animation-iteration-count: infinite;
            animation-timing-function: linear;
            margin-left: 5px;
        }

        @keyframes point {
            from {
                box-shadow: none;
            }

            30% {
                box-shadow: 3px 0 currentColor;
            }

            60% {
                box-shadow: 3px 0 currentColor, 9px 0 currentColor;
            }

            90% {
                box-shadow: 3px 0 currentColor, 9px 0 currentColor, 15px 0 currentColor;
            }
        }
    </style>
</head>

<body>
    <button>
        <i class="fa fa-code" aria-hidden="true"></i>
        提交
    </button>
</body>

#open in new window步进速度

过渡使用阶梯化呈现,有点像现实生活中的机械舞,下面是把过渡分五步完成。

选项说明
steps(n,start)设置 n 个时间点,第一时间点变化状态
steps(n,end)设置 n 个时间点,第一时间点初始状态
step-start等于 steps(1,start),可以理解为从下一步开始
step-end等于 steps(1,end),可以理解为从当前步开始

#open in new windowsteps

steps(n,start) 可以简单理解为从第二个开始,steps(n,end) 从第一个开始。

image

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>厚道人</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        body {
            width: 100vw;
            height: 100vh;
            background: #2c3e50;
            display: grid;
            /* justify-content: center;
            align-content: center; */
        }

        main {
            justify-self: center;
            align-self: center;
            width: 400px;
            height: 200px;
            display: grid;
            grid-template: repeat(2, 1fr)/repeat(4, 1fr);
        }

        div {
            background: #f1c40f;
            text-align: center;
            position: relative;
            border-right: solid 1px #2c3e50;
            border-bottom: solid 1px #2c3e50;
            box-sizing: border-box;
        }

        div:nth-child(5)::before {
            content: 'END';
            position: absolute;
            width: 100px;
            height: 100px;
            background: #e67e22;
            left: 0;
            animation-name: move;
            animation-duration: 2s;
            z-index: 2;
            animation-timing-function: steps(4, end);
            animation-iteration-count: infinite;
        }

        div:nth-child(1)::after {
            content: 'START';
            position: absolute;
            width: 100px;
            height: 100px;
            background: #9b59b6;
            animation-name: move;
            animation-duration: 2s;
            animation-timing-function: steps(4, start);
            animation-iteration-count: infinite;
            z-index: 2;
            left: 0;
            top: 0;
        }

        @keyframes move {
            to {
                transform: translateX(400px);
            }
        }
    </style>
</head>

<body>
    <main>
        <div>1 <small>houdunren.com</small></div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
        <div>5</div>
        <div>6</div>
        <div>7</div>
        <div>8</div>
    </main>
</body>

#open in new windowstep-start

step-start 效果等于 steps(1,start) ,step-end 效果等同于 steps(1,end)

image

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>厚道人</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        body {
            width: 100vw;
            height: 100vh;
            background: #2c3e50;
            display: grid;
        }

        main {
            align-self: center;
            justify-self: center;
            width: 400px;
            height: 200px;
            display: grid;
            grid-template: repeat(2, 1fr)/repeat(4, 1fr);
        }

        div {
            text-align: center;
            background: #f1c40f;
            border: solid 1px #2c3e50;
            box-sizing: border-box;
            position: relative;
        }

        div:nth-child(1)::before,
        div:nth-child(5)::before {
            animation-name: hd;
            animation-iteration-count: infinite;
            animation-duration: .5s;
            z-index: 2;
        }

        div:nth-child(1)::before {
            content: 'START';
            width: 100px;
            height: 100px;
            background: #8e44ad;
            position: absolute;
            left: 0;
            top: 0;
            animation-timing-function: step-start;
        }

        div:nth-child(5)::before {
            content: 'END';
            width: 100px;
            height: 100px;
            background: #27ae60;
            position: absolute;
            left: 0;
            top: 0;
            animation-timing-function: step-end;
        }

        @keyframes hd {
            50% {
                transform: translateX(100px);
            }

            to {
                transform: translateX(0px);
            }
        }
    </style>
</head>

<body>
    <main>
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
        <div>5</div>
        <div>6</div>
        <div>7</div>
        <div>8</div>
    </main>
</body>

#open in new window播放状态

使用 animation-play-state 可以控制动画的暂停与运行。

选项说明
paused暂停
running运行

#open in new window幻灯片

下面是使用无 JS 脚本参与的图片轮换效果,图片切换使用steps 步进与animation-play-state播放状态技术。

image

<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
    <script src='https://code.jquery.com/jquery-3.3.1.slim.min.js'></script>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        body {
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background: #2c3e50;
        }

        main {
            width: 400px;
            border: solid 5px #ddd;
            border-width: 5px 0 5px 0;
            overflow: hidden;
            position: relative;
        }

        main:hover section {
            animation-play-state: paused;
        }

        main:hover ul::before {
            animation-play-state: paused;
        }

        section {
            width: 1600px;
            height: 200px;
            display: flex;
            flex-direction: row;
            animation-name: slide;
            animation-duration: 4s;
            animation-iteration-count: infinite;
            animation-timing-function: steps(4, end);
        }

        section div {
            width: 400px;
            height: 200px;
            overflow: hidden;
        }

        section div img {
            width: 100%;
        }

        ul {
            width: 200px;
            position: absolute;
            list-style: none;
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 3;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
        }

        ul li {
            font-size: 2em;
            font-weight: bold;
            color: white;
            width: 50px;
            height: 50px;
            border-radius: 50%;
            border: solid 3px transparent;
            box-sizing: border-box;
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 2;
            background: rgba(0, 0, 0, .3);
            box-shadow: 0 0 3px rgba(0, 0, 0, 1);
        }

        ul::before {
            content: '';
            width: 50px;
            height: 50px;
            border-radius: 50%;
            position: absolute;
            background: #e74c3c;
            left: 0;
            animation-name: num;
            animation-duration: 4s;
            animation-iteration-count: infinite;
            animation-timing-function: steps(4, end);
            z-index: 1;
        }

        @keyframes slide {
            from {
                transform: translateX(0px);
            }

            to {
                transform: translateX(-100%);
            }
        }

        @keyframes num {
            100% {
                transform: translateX(200px);
            }
        }
    </style>
</head>

<body>
    <main>
        <section>
            <div>
                <img src="1.jpg" alt="">
            </div>
            <div>
                <img src="2.jpg" alt="">
            </div>
            <div>
                <img src="3.jpg" alt="">
            </div>
            <div>
                <img src="5.jpg" alt="">
            </div>
        </section>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
    </main>
</body>

#open in new window填充模式

animation-fill-mode 用于定义动画播放结束后的处理模式,是回到原来状态还是停止在动画结束状态。

选项说明
none需要等延迟结束,起始帧属性才应用
backwards动画效果在起始帧,不等延迟结束
forwards结束后停留动画的最后一帧
both包含 backwards 与 forwards 规则,即动画效果在起始帧,不等延迟结束,并且在结束后停止在最后一帧

#open in new window效果对比

image

<head>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        body {
            width: 100vw;
            height: 100vh;
            background: #34495e;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
        }

        ul {
            display: flex;
            justify-content: center;
            align-items: center;
        }

        li {
            list-style: none;
            width: 200px;
            height: 200px;
            background: #ecf0f1;
            border-radius: 50%;
            animation-name: hd;
            animation-delay: 2s;
            animation-duration: 2s;
            text-align: center;
            font-size: 2em;
            line-height: 200px;
            margin: 10px;
        }

        li:nth-child(1) {
            animation-fill-mode: none;
        }

        li:nth-child(2) {
            animation-fill-mode: backwards;
        }

        li:nth-child(3) {
            animation-fill-mode: forwards;
        }

        li:nth-child(4) {
            animation-fill-mode: both;
        }

        @keyframes hd {
            0% {
                border-radius: 0;
                background: #9b59b6;
            }

            100% {
                border-radius: 50%;
                background: #e74c3c;
            }
        }
    </style>
</head>

<body>
    <ul>
        <li>none</li>
        <li>backwards</li>
        <li>forwards</li>
        <li>both</li>
    </ul>
    <h2>houdunren.com</h2>
</body>

#open in new window组合定义

和 CSS 中的其他属性一样,可以使用animation组合定义帧动画。animation 属性是一个简写属性,用于设置六个动画属性:

  • animation-name
  • animation-duration
  • animation-timing-function
  • animation-delay
  • animation-iteration-count
  • animation-direction

必须存在 animation-duration属性,否则过渡时间为 0 没有动画效果。

媒体查询

houdunren.com (opens new window)open in new window

Media Queries 能在不同的条件下使用不同的样式,使页面在不同在终端设备下达到不同的渲染效果。

#open in new windowviewport

手机是在电脑后出现的,早期网页设置没有考虑到手机的存在。把一个电脑端访问的网页拿到手机上浏览,我们需要告诉手机该怎么做。

我们不能让手机浏览器使用 PC 端的分辨率来展示网页,这会让高分辨率的手机上造成文字过小。

使用 viewport 可以将手机物理分辨率合理转为浏览器分辨率。

viewport 是虚拟窗口,虚拟窗口大于手机的屏幕尺寸。手机端浏览器将网页放在这个大的虚拟窗口中,我们就可以通过拖动屏幕看到网页的其他部分。

但有时需要控制 viewport 虚拟窗口的尺寸或初始的大小,比如希望 viewport 完全和屏幕尺寸一样宽。就需要学习 viewport 的知识了。

#open in new window媒体设备

下面是常用媒体类型,当然主要使用的还是 screen

选项说明
all所有媒体类型
screen用于电脑屏幕,平板电脑,智能手机等
print打印设备
speech应用于屏幕阅读器等发声设备

注:tty, tv, projection, handheld, braille, embossed, aural 设备类型已经被废弃

  • 可以使用 link 与 style 中定义媒体查询
  • 也可以使用 @import url(screen.css) screen 形式媒体使用的样式
  • 可以用逗号分隔同时支持多个媒体设备
  • 未指定媒体设备时等同于 all

#open in new windowstyle

下面是在屏幕显示与打印设备上不同的 CSS 效果

image

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>厚道人</title>
    <style media="screen">
        h1 {
            font-size: 3em;
            color: blue;
        }
    </style>
    <style media="print">
        h1 {
            font-size: 8em;
            color: red;
        }

        h2,
        hr {
            display: none;
        }
    </style>
</head>

<body>
    <h1>houdunren.com</h1>
    <hr>
    <h2>厚道人</h2>
</body>

link 标签中通过 media 属性可以设置样式使用的媒体设备。

  • common.css 没有指定媒体所以全局应用
  • screen.css 应用在屏幕设备
  • print.css 应用在打印设备
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>厚道人</title>
    <link rel="stylesheet" href="common.css">
    <link rel="stylesheet" href="screen.css" media="screen">
    <link rel="stylesheet" href="print.css" media="print">
</head>

<body>
    <h1>houdunren.com</h1>
    <hr>
    <h2>厚道人</h2>
</body>

common.css

h1 {
  outline: solid 5px #e74c3c;
}

screen.css

h1 {
  font-size: 3em;
  color: blue;
}

print.css

h1 {
  font-size: 8em;
  color: red;
}

h2,
hr {
  display: none;
}

可以在 CSS 文件中使用 @media 再定义媒体样式

#open in new window@import

使用@import 可以引入指定设备的样式规则。文件中引入一个样式文件,在这个文件中再引入其他媒体的样式文件。

<link rel="stylesheet" href="style.css">

style.css

@import url(screen.css) screen;
@import url(print.css) print;

具体的 screen.css 与 print.css 与上面介绍的一样,在这里就不重复罗列了

#open in new window@media

可以使用 @media 做到更细的控制,即在一个样式表中为多个媒体设备定义样式。

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>厚道人</title>
    <style>
        @media screen {
            h1 {
                font-size: 3em;
                color: blue;
            }
        }

        @media print {
            h1 {
                font-size: 8em;
                color: red;
            }

            h2,
            hr {
                display: none;
            }
        }
    </style>
</head>

<body>
    <h1>houdunren.com</h1>
    <hr>
    <h2>厚道人</h2>
</body>

#open in new window多设备支持

可以用逗号分隔同时支持多个媒体设备。

@import url(screen.css) screen, print;

<link rel="stylesheet" href="screen.css" media="screen,print" > @media screen,
print {
  ...;
}

#open in new window设备方向

使用 orientation 属性可以定义设备的方向

说明
portrait竖屏设备即高度大于宽度
landscape横屏设备即宽度大于高度

下面是尺寸小于 768px 或是横屏时使用蓝色字体

<style media="screen and (min-width: 768px),screen and (orientation:landscape)">
  body {
    color: blue;
  }
</style>
<h1>baidu</h1>

#open in new window查询条件

可以使用不同条件限制使用的样式

  • 条件表达式需要放在扩号中

#open in new window逻辑与

需要满足多个条件时才使用样式,多个条件使用and 连接。下例中满足以下要求才使用样式。

  • 横屏显示
  • 宽度不能超过 600px

image

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>厚道人</title>
    <style>
        @media screen and (orientation: landscape) and (max-width: 600px) {
            body {
                background: #8e44ad;
            }

            h1 {
                font-size: 3em;
                color: white;
            }
        }
    </style>
</head>

<body>
    <h1>houdunren.com</h1>
</body>

#open in new window逻辑或

多个 条件查询使用逗号连接,不像其他程序中使用 or 语法。

下面的示例中如果设备是横屏显示或宽度不超 600px 时就使用样式规则。

image

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>厚道人</title>
    <style>
        @media screen and (orientation: landscape),
        screen and (max-width: 600px) {
            body {
                background: #8e44ad;
            }

            h1 {
                font-size: 3em;
                color: white;
            }
        }
    </style>
</head>

<body>
    <h1>houdunren.com</h1>
</body>

#open in new window不应用

not 表示不应用样式,即所有条件都满足不应用样式。

  • 必须将 not 写在查询的最前面

image

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>厚道人</title>
    <style>
        @media not screen and (orientation: landscape) and (max-width:600px) {
            body {
                background: #8e44ad;
            }

            h1 {
                font-size: 3em;
                color: white;
            }
        }
    </style>
</head>

<body>
    <h1>houdunren.com</h1>
</body>

#open in new windowonly

用来排除不支持媒体查询的浏览器。

  • 对支持媒体查询的设备,正常调用样式,此时就当 only 不存在
  • 对不支持媒体查询的设备不使用样式
  • only 和 not 一样只能出现在媒体查询的开始
@media only screen and (orientation: landscape) and (max-width: 600px) {
  ...;
}

#open in new window查询特性

根据查询特性筛选出使用样式的设备。

#open in new window常用特性

下面列出常用的媒体查询特性

| 特性 | 说明 | | ---------------------- | -------- | ----------------------------- | | orientation: landscape | portrait | landscape 横屏,portrait 竖屏 | | width | 设备宽度 | | height | 设备高度 | | min-width | 最小宽度 | | max-width | 最大宽度 | | min-height | 最小高度 | | max-height | 最大高度 |

#open in new window使用示例

在设备宽度为 568px 时使用样式

@media only screen and (width: 568px) {
  ...;
}

在设备不小于 569px 时使用样式

@media only screen and (min-width: 569px) {
  ...;
}

橫屏设备并且宽度大于 569px 时使用样式

@media only screen and (orientation: landscape) and (min-width: 569px) {
  ...;
}

#open in new window实战案例

请在版本库查看 https://gitee.com/houdunren/code/tree/master/video/css/media/hdopen in new window

响应计算

houdunren.com (opens new window)open in new window@大军大叔

image

通过本章的学习来掌握开发中针对不同尺寸设备的响应式处理。

#open in new windowviewport

移动端浏览器将网页放置在虚拟的 viewport 中,不同手机分辨率对视口进行缩放即可全屏显示内容。不同浏览器定义的 viewport 尺寸不同。

#open in new window视口概念

所以 viewport 也可以理解为屏幕有多少像素来显示内容,这和电脑端是不同的。

  • 电脑端是显示器的多大分辨率多少就用多少像素来显示
  • 移动端是 viewport 分辨率多少就用多少像素来显示
  • viewport 是可以改变的,就像显示器的分辨率可以改变一样

image

#open in new window查看尺寸

主流浏览器的默认 viewport 大小(因为浏览器间不统一,所以也没有必要关注下面的尺寸,只做为了解就行)

浏览器尺寸
Safari iPhone980px
Opera850px
Android WebKit800px
IE974px

可以在控制台查看到 viewport 大小

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
      厚道人十年来我们录制了大量制作精良的课程,并且依然在不段迭代更新中,首先感谢老朋友们十年来的支持,也欢迎新朋友们观看我们的视频教程。
  </body>
</html>

在浏览器打开上面网页,并通过控制台查看结果如下

image

#open in new window改变视口

使用<meta name="viewport" content="width=2000px" />可以调整视口,这有点像设置相同尺寸桌面显示不同的分辨率。

下面是将视口定义为 2000 与 300 的差别,这类似于同样 27 寸分辨率下 4K 与 1080 显示的区别。

image

#open in new window媒体查询

@media 是根据分辨率来响应式布局的,所以 viewport 尺寸的不同将影响媒体查询的使用。

下面代码用于在分辨率小于 500px 时更改内容颜色,但是因为没有设置 viewport,而使用浏览器默认的视口,这会造成在手机上无法进行响应操作,因为 viewport 尺寸大于 500px。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    <style>
      @media (max-width: 500px) {
        body {
          color: red;
        }
      }
    </style>
    厚道人十年来我们录制了大量制作精良的课程,并且依然在不段迭代更新中,首先感谢老朋友们十年来的支持,也欢迎新朋友们观看我们的视频教程。
  </body>
</html>

面当我们设置好 viewport 后就可以进行响应处理了,下面是将 viewport 设置为 500px

<meta name="viewport" content="width=500"/>

image

#open in new window设备尺寸

像上面通过人为设置像素值,显示是不可取的。如果响应布局当然希望 viewport 与设备尺寸一至,可喜的是,系统为我们提供了device-width变量值用于识别设备宽度。

<meta name="viewport" content="width=device-width" />

#open in new window其他属性

下面介绍其他可用在 meta 标签上的属性

属性说明
initial-scale=1初始缩放比例
minimum-scale=.5允许用户最小缩放比例
_maximum-scale_=2.5允许用户最大缩放比例
user-scalable=yes是否允许用户绽放

mac 用户在 chrome 中使用 option+shift+鼠标按住移动进行缩放

#open in new windowJS 延迟

设置 user-scalable=no 时可以 js 解决 300 延迟的问题,你也可以理解为当设置 user-scalable=yes 时,系统要识别两只手指,所以要有个宽容时间。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=yes" />
  </head>
  <body>
    <style>
      body {
        width: 100vw;
        height: 100vh;
      }
    </style>
    <script>
      let i = 1
      document.body.addEventListener('click', () => console.log(i++))
    </script>
  </body>
</html>

#open in new windowrem/em

em 理解为继承(相对)单位,它需要一个参考的继承属性。

#open in new windowem

我们知道字体大小是可以继承的,我们对下面例子进行说明

  • span 没有设置字体大小,将继续父级 article 标签定义的大小 15px
  • strong 定义了 2em 字体大小,因为使用了 em 单位即是父级 15px X 2=30px

可以通过 edge 或 chrome 浏览器调试工具的已计算标签查看

<style>
  article {
    font-size: 15px;
  }
  strong {
    font-size: 2em;
  }
</style>

<article>
  <span>houdunren.com</span>
  <strong>厚道人</strong>
</article>

#open in new window多级继承

下面代码是多层次的嵌套,如果使用 em 单位定义 font-size 会向上一直查找定义了 font-size 的父级来进行计算。直到找到 html 标签为止。

所以下面的 strong 定义的 2em 计算结果依然是 30px 即 article 标签的 font-size:15px 乘以 2。

<style>
  article {
    font-size: 15px;
  }
  strong {
    font-size: 2em;
  }
</style>

<article>
  <div>
    <span>houdunren.com</span>
    <strong>厚道人</strong>
  </div>
</article>

#open in new windowpadding/margin

font-size 本身是可以继承的,所以 em 参考父级元素定义的 font-size。但 padding/margin 在 CSS 中不会继承父级定义的 padding/margin。

如果 padding/margin 使用 em 单位将参考本元素的 font-size。

下面示例中最终 strong 标签的 padding 与 margin 都是 60px,因为定义了 2em 所以最终结果为当前标签的 font-size*2

<style>
  article {
    font-size: 15px;
  }
  strong {
    font-size: 2em;
    padding: 2em;
    margin: 2em;
  }
</style>

<article>
  <div>
    <span>houdunren.com</span>
    <strong>厚道人</strong>
  </div>
</article>

#open in new windowrem

rem 本向也有 em 的特性即参考继承,只不过它只参考根元素(root)即 html 标签定义的 font-size。我们来通过下面的示例详细说明。

  • 为 html 标签定义了 font-size:30px,页面中使用 rem 单位的元素将 30px 为参考,即 1rem=30px
  • span 标签使用了 font-size:2em,会参考父级 article 定义的 font-size,最后计算结果为 font-size:30px
  • strong 标签定义了 font-size:2rem,会参考 html 标签的 font-size,最后计算结果为 60px
  • strong 标签定义了 padding:2rem,计算结果也是 60px
  • strong 标签定义了 margin:2em,将会参考本身元素的 font-size,上面已经说明 strong 的 font-size 为 60px,所以最终 margin 结果为 120px
<style>
  html {
    font-size: 30px;
  }
  article {
    font-size: 15px;
  }
  span {
    font-size: 2em;
  }
  strong {
    display: block;
    font-size: 2rem;
    padding: 2rem;
    margin: 2em;
  }
</style>

<article>
  <div>
    <span>houdunren.com</span>
    <strong>厚道人</strong>
  </div>
</article>

#open in new window使用建议

em 与 rem 都是不错的响应单位,根据需要进行选择。em 具有继承特性,rem 的参考元素是唯一 HTML,所以 rem 操作简单。em 继承关系会相对复杂。

布局上的 margin/padding 使用 rem 是不错的选择,字体大小等使用 em 与 rem 都可以。

#open in new window尺寸响应

#open in new window问题分析

下面是尺寸为 375x600 的设计稿,绿色区域为 200px 红色为 175px 宽度

image

使用固定像素定义时在 iphone6 与 iphon6 plus 中的显示效果并不相同

image

实例代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css" />
  </head>
  <body>
    <div class="left"></div>
    <div class="right"></div>
  </body>
  <style>
    div {
      height: 600px;
    }
    .left {
      width: 200px;
      background: #76ba65;
      float: left;
    }
    .right {
      width: 175px;
      background: #df0f71;
      float: left;
    }
  </style>
</html>

#open in new window自动响应

实际操作中不同设备只能取宽或高一个尺寸为响应处理,一般情况下我们取宽度响应,高度自动处理。小尺寸时高度产生垂直滚动条,这并不影响什么。

计算公式

使用 rem 单位来处理响应,因为改变 rem 单位会影响所有使用 rem 的元素,这确实非常的方便。

  • rem 是在根元素中定义的 font-size
  • rem 用来在多个设备响应处理时使用
  • html 元素也可以使用:root 选择器选择

下面展示的设计稿为 375px 宽,下面公式表示 1px 所占的屏幕尺寸宽度,有以下几点需要说明

  • 100vw 表示 100%视口宽度
  • 因为使用了 vw 宽度系统会根据不同设备自动计算 rem
:root {
  font-size: calc(100vw / 375);
}

完整代码如下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>houdunren.com</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css" />
  </head>
  <body>
    <div class="left"></div>
    <div class="right"></div>
  </body>
  <style>
    :root {
      font-size: calc(100vw / 375);
    }
    div {
      height: 600rem;
    }
    .left {
      width: 200rem;
      background: #76ba65;
      float: left;
    }
    .right {
      width: 175px;
      background: #df0f71;
      float: left;
    }
  </style>
</html>

现在使用不同设备时宽度已经自动可以响应设置了

字体图标

houdunren.com (opens new window)open in new window@大军大叔

image

网站开发中会使用非常多的小图标,以往使用 png 图来完成,但不方便设置图标颜色、大小等操作。而使用失量的图标字体可以很好的解决这个问题。

常用失量字体

#open in new window阿里图标

iconfont 提供了丰富的图标库,也允许个人上传分享图标,非常复合中文视觉体验。

首先登录图标库网站 https://www.iconfont.cn(opens new window)open in new window

#open in new window添加图标

然后通过关键词搜索图标,并添加到购物车或收藏夹中

image

将购物车中的图标添加到项目

image

#open in new window使用图标

点击顶部菜单 图标管理>我的项目

  1. 首先生成网页 css 代码,然后复制到网页代码中
<link rel="stylesheet" href="//at.alicdn.com/t/font_3434ycaug24x9.css" />

  1. 在项目中复制代码链接

image

  1. 网站中按以下格式使用
<i class="iconfont icongongzhonghao"></i>

#open in new windowfontawesome

fontawesome (opens new window)open in new window图标库是使用非常多的免费图标库

  • 首先推荐在编辑器中安装插件实现代码提示

在页面中引入链接

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />

html 中使用方式如下

<i class="fa fa-user-circle-o" aria-hidden="true"></i>
Last Updated:
Contributors: 刘荣杰