前端切图学习-旋转式侧边栏

Rotating Nav Animation

Posted by R1NG on August 18, 2021 Viewed Times

旋转式侧边栏 Rotating-Nav-Animation

1. 概述

该项目本体模拟了一篇博文, 侧边栏可通过左上角的 $1/4$ 圆按钮唤起. 唤起侧边栏后整个页面会逆时针旋转, 而左下角会飞出页面导航.

本项目中将涉及如下知识点:

  1. rotate 动画的使用
  2. 从外部导入 fontAwesome 字体

效果:

20210819110852

20210819111058


2. 结构和切图

网页的基本结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<body>
    <div class="container">
        <div class="circle-container">
            <div class="circle">
                <button id="close">
                    <i class="fas fa-times"></i>
                </button>
                <button id="open">
                    <i class="fas fa-bars"></i>
                </button>
            </div>
        </div>

        <div class="content">
        <!---Your Article Appears Here--->
        </div>
    </div>

    <nav>
        <ul>
            <li><i class="fas fa-home"></i><a href="#"> Home </a></li>
            <li><i class="fas fa-user-alt"></i><a href="#"> About </a></li>
            <li><i class="fas fa-envelope"></i><a href="#"> Contact </a></li>
        </ul>
    </nav>

    <script>
    </script>
</body>

Screen-Recording-2021-08-19-at-11.13.42

总体上网页由三个部分组成: 一个竖向导航栏, 一个包含文章主体和 $1/4$ 圆形按键的 div 容器.


3. 编写 CSS 样式

我们此处只考虑涉及页面切换动画和竖向导航栏的核心 CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
.container{
    background-color: #fafafa;
    transform-origin: top left;
    transition: transform 0.3s ease;
    width: 100vw;
    min-height: 100vh;
    padding: 50px;
}
.container.show-nav{
    transform: rotate(-20deg);
}
.circle-container{
    position: fixed;
    top: -100px;
    left: -100px;
}
.circle{
    background-color: #ff7979;
    height: 200px;
    width: 200px;
    border-radius: 50%;
    position: relative;
    transition: transform 0.3s linear;
}
.container.show-nav .circle{
    transform: rotate(-70deg);
    
}
.circle button {
    cursor: pointer;
    position: absolute;
    top: 45%;
    left: 50%;
    height: 100px;
    background: transparent;
    border: 0;
    font-size: 26px;
    color: #fff;
}

.circle button:focus {
    outline: none;
}
.circle button#open {
    left: 60%;
}
.circle button#close {
    top: 60%;
    transform: rotate(90deg);
    transform-origin: top left;
}
.container.show-nav + nav li {
    transform: translateX(0);
    transition-delay: 0.2s;
}

此处涉及的核心 CSS 语句是 transform: rotate(...deg)transform-origin: top left: 前者控制元素 逆时针 旋转的角度, 后者控制元素旋转中心的位置. 在本项目中, 我们统一规定元素的旋转中心为 页面左上角.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
nav {
    position: fixed;
    bottom: 40px;
    left: 0;
    z-index: 100;
}
nav ul {
    list-style-type: none;
    padding-left: 30px;
}
nav ul li {
    text-transform: uppercase;
    color: #fff;
    margin: 40px 0;
    transform: translateX(-100%);
    transition: transform 0.3s ease-in;    
}
nav ul li i {
    font-size: 20px;
    margin-right: 10px;
}

nav ul li+li {
    margin-left: 15px;
    transform: translateX(-150%);
}

nav ul li + li + li {
    margin-left: 30px;
    transform: translateX(-200%);
}

nav a{
    color: #fafafa;
    text-decoration: none;
    transition: all 0.3s;
}

nav a:hover{
    color: #ff7979;
    font-weight: bold;
}

我们再次回顾 CSS 选择器的 (部分) 选择规则:

选择器 例子 解释
.class1 .class2 .name1 .name2 选择作为类名 name1 元素后代的所有类名 name2 元素
.class1.class2 .name1.name2 选择 class 属性中同时有 name1 和 name2 的所有元素
element+element div + p 选择紧跟 <div> 元素的首个 <p> 元素

不难理解, 上述涉及竖直导航栏的 CSS 样式表分别选择了三行链接并定义了它们的不同样式 (主要的不同在其位置上).

我们可以使用

1
2
3
4
<link rel="stylesheet" 
          href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" 
          integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" 
          crossorigin="anonymous" />

引入 FontAwesome 字体, 并在 <i/> 标签中指定 className 使用不同的图标.

完整的 CSS 样式表如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<style>
     * {
         box-sizing: border-box;
     }

     body {
         font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
         background-color: #323232;
         color: #222;
         overflow-x: hidden;
         margin: 0;
     }
     .container{
         background-color: #fafafa;
         transform-origin: top left;
         transition: transform 0.3s ease;
         width: 100vw;
         min-height: 100vh;
         padding: 50px;
     }
     .container.show-nav{
         transform: rotate(-20deg);
     }
     .circle-container{
         position: fixed;
         top: -100px;
         left: -100px;
     }
     .circle{
         background-color: #ff7979;
         height: 200px;
         width: 200px;
         border-radius: 50%;
         position: relative;
         transition: transform 0.3s linear;
     }
     .container.show-nav .circle{
         transform: rotate(-70deg);
         
     }
     .circle button {
         cursor: pointer;
         position: absolute;
         top: 45%;
         left: 50%;
         height: 100px;
         background: transparent;
         border: 0;
         font-size: 26px;
         color: #fff;
     }

     .circle button:focus {
         outline: none;
     }
     .circle button#open {
         left: 60%;
     }
     .circle button#close {
         top: 60%;
         transform: rotate(90deg);
         transform-origin: top left;
     }
     .container.show-nav + nav li {
         transform: translateX(0);
         transition-delay: 0.2s;
     }

     nav {
         position: fixed;
         bottom: 40px;
         left: 0;
         z-index: 100;
     }
     nav ul {
         list-style-type: none;
         padding-left: 30px;
     }
     nav ul li {
         text-transform: uppercase;
         color: #fff;
         margin: 40px 0;
         transform: translateX(-100%);
         transition: transform 0.3s ease-in;    
     }
     nav ul li i {
         font-size: 20px;
         margin-right: 10px;
     }

     nav ul li+li {
         margin-left: 15px;
         transform: translateX(-150%);
     }

     nav ul li + li + li {
         margin-left: 30px;
         transform: translateX(-200%);
     }

     nav a{
         color: #fafafa;
         text-decoration: none;
         transition: all 0.3s;
     }

     nav a:hover{
         color: #ff7979;
         font-weight: bold;
     }

     .content img{
         max-width: 100%;
     }

     .content {
         max-width: 1000px;
         margin: 50px auto;
     }
     .content h1 {
         margin: 0;
     }
     .content small {
         color: #555;
         font-style: italic;
     }
     .content p {
         color: #333;
         line-height: 1.5;
     }
 </style>


4. JavaScript

最后编写 JavaScript 检查 $1/4$ 圆形按钮的点击状态并修改其 className 以实现旋转切换动画:

1
2
3
4
5
6
const open = document.getElementById('open')
const close = document.getElementById('close')
const container = document.querySelector('.container')

open.addEventListener('click', () => container.classList.add('show-nav'))
close.addEventListener('click', () => container.classList.remove('show-nav'))

最后, 完整的网页演示可见 此处