JS30 Day05
flex 不愧為排版聖品,簡單易學效果佳。


Flex Panels Image Gallery

完成目標

  • 功能
    • 點擊指定的區塊,產生動畫
    • 再點擊一次,恢復原狀
  • 畫面
    • 標籤 p 中間的字變大
    • 變大之後上下的字要進來



index-START.html

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Flex Panels 💪</title>
<link
href="https://fonts.googleapis.com/css?family=Amatic+SC"
rel="stylesheet"
type="text/css"
/>
</head>
<body>
<style>
html {
box-sizing: border-box;
background: #ffc600;
font-family: "helvetica neue";
font-size: 20px;
font-weight: 200;
}

body {
margin: 0;
}

*,
*:before,
*:after {
box-sizing: inherit;
}

.panels {
min-height: 100vh;
overflow: hidden;
}

.panel {
background: #6b0f9c;
box-shadow: inset 0 0 0 5px rgba(255, 255, 255, 0.1);
color: white;
text-align: center;
align-items: center;
/* Safari transitionend event.propertyName === flex */
/* Chrome + FF transitionend event.propertyName === flex-grow */
transition: font-size 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11), flex
0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11), background 0.2s;
font-size: 20px;
background-size: cover;
background-position: center;
}

.panel1 {
background-image: url(https://source.unsplash.com/gYl-UtwNg_I/1500x1500);
}
.panel2 {
background-image: url(https://source.unsplash.com/rFKUFzjPYiQ/1500x1500);
}
.panel3 {
background-image: url(https://images.unsplash.com/photo-1465188162913-8fb5709d6d57?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&w=1500&h=1500&fit=crop&s=967e8a713a4e395260793fc8c802901d);
}
.panel4 {
background-image: url(https://source.unsplash.com/ITjiVXcwVng/1500x1500);
}
.panel5 {
background-image: url(https://source.unsplash.com/3MNzGlQM7qs/1500x1500);
}

/* Flex Children */
.panel > * {
margin: 0;
width: 100%;
transition: transform 0.5s;
}

.panel p {
text-transform: uppercase;
font-family: "Amatic SC", cursive;
text-shadow: 0 0 4px rgba(0, 0, 0, 0.72), 0 0 14px rgba(0, 0, 0, 0.45);
font-size: 2em;
}

.panel p:nth-child(2) {
font-size: 4em;
}

.panel.open {
font-size: 40px;
}
</style>

<div class="panels">
<div class="panel panel1">
<p>Hey</p>
<p>Let's</p>
<p>Dance</p>
</div>
<div class="panel panel2">
<p>Give</p>
<p>Take</p>
<p>Receive</p>
</div>
<div class="panel panel3">
<p>Experience</p>
<p>It</p>
<p>Today</p>
</div>
<div class="panel panel4">
<p>Give</p>
<p>All</p>
<p>You can</p>
</div>
<div class="panel panel5">
<p>Life</p>
<p>In</p>
<p>Motion</p>
</div>
</div>

<script></script>
</body>
</html>

index-FINISHED.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Flex Panels 💪</title>
<link
href="https://fonts.googleapis.com/css?family=Amatic+SC"
rel="stylesheet"
type="text/css"
/>
</head>
<body>
<style>
html {
box-sizing: border-box;
background: #ffc600;
font-family: "helvetica neue";
font-size: 20px;
font-weight: 200;
}

body {
margin: 0;
}

*,
*:before,
*:after {
box-sizing: inherit;
}

.panels {
min-height: 100vh;
overflow: hidden;
display: flex;
}

.panel {
background: #6b0f9c;
box-shadow: inset 0 0 0 5px rgba(255, 255, 255, 0.1);
color: white;
text-align: center;
align-items: center;
/* Safari transitionend event.propertyName === flex */
/* Chrome + FF transitionend event.propertyName === flex-grow */
transition: font-size 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11), flex
0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11), background 0.2s;
font-size: 20px;
background-size: cover;
background-position: center;
flex: 1;
justify-content: center;
display: flex;
flex-direction: column;
}

.panel1 {
background-image: url(https://source.unsplash.com/gYl-UtwNg_I/1500x1500);
}
.panel2 {
background-image: url(https://source.unsplash.com/rFKUFzjPYiQ/1500x1500);
}
.panel3 {
background-image: url(https://images.unsplash.com/photo-1465188162913-8fb5709d6d57?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&w=1500&h=1500&fit=crop&s=967e8a713a4e395260793fc8c802901d);
}
.panel4 {
background-image: url(https://source.unsplash.com/ITjiVXcwVng/1500x1500);
}
.panel5 {
background-image: url(https://source.unsplash.com/3MNzGlQM7qs/1500x1500);
}

/* Flex Items */
.panel > * {
margin: 0;
width: 100%;
transition: transform 0.5s;
flex: 1 0 auto;
display: flex;
justify-content: center;
align-items: center;
}

.panel > *:first-child {
transform: translateY(-100%);
}
.panel.open-active > *:first-child {
transform: translateY(0);
}
.panel > *:last-child {
transform: translateY(100%);
}
.panel.open-active > *:last-child {
transform: translateY(0);
}

.panel p {
text-transform: uppercase;
font-family: "Amatic SC", cursive;
text-shadow: 0 0 4px rgba(0, 0, 0, 0.72), 0 0 14px rgba(0, 0, 0, 0.45);
font-size: 2em;
}

.panel p:nth-child(2) {
font-size: 4em;
}

.panel.open {
flex: 5;
font-size: 40px;
}

@media only screen and (max-width: 600px) {
.panel p {
font-size: 1em;
}
}
</style>

<div class="panels">
<div class="panel panel1">
<p>Hey</p>
<p>Let's</p>
<p>Dance</p>
</div>
<div class="panel panel2">
<p>Give</p>
<p>Take</p>
<p>Receive</p>
</div>
<div class="panel panel3">
<p>Experience</p>
<p>It</p>
<p>Today</p>
</div>
<div class="panel panel4">
<p>Give</p>
<p>All</p>
<p>You can</p>
</div>
<div class="panel panel5">
<p>Life</p>
<p>In</p>
<p>Motion</p>
</div>
</div>

<script>
const panels = document.querySelectorAll(".panel");

function toggleOpen() {
console.log("Hello");
this.classList.toggle("open");
}

function toggleActive(e) {
console.log(e.propertyName);
if (e.propertyName.includes("flex")) {
this.classList.toggle("open-active");
}
}

panels.forEach(panel => panel.addEventListener("click", toggleOpen));
panels.forEach(panel =>
panel.addEventListener("transitionend", toggleActive)
);
</script>
</body>
</html>



學習筆記


★ Flexbox

CSS3 flexbox 是為了適應不同螢幕尺寸和顯示設備而生的排版模式。利用 flexbox 可以更輕鬆地設計靈活的響應式排版,取代 float 或 position 屬性。

flex 排版的大致定義,是能更改該項目的長與(或)高,以便貼合任何顯示設備的空間。flex container 能針對該元件擴張以便填補可用的空間、或收縮以便阻止空間溢出。block layout 以垂直方向為準、inline layout 以水平方向為準、而 flexbox layout 則同時允許這兩種。


  • Flexbox element

    要開始使用 flexbox ,首先需要定義 flex container 以及 flex items

    • flex container:

      包住 flex item 的父元素。屬性為 display: flexdisplay: inline-flex 的,就是 flex container。

    • flex items:

      所有 flex container 的子元素都會變成 flex items。直接包含在 flex container 內的文字,會被包裝成匿名的 flex items。

    範例:

    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
    <!DOCTYPE html>
    <html>
    <head>
    <style>
    .flex-container {
    display: flex;
    background-color: Blue;
    }

    .flex-container > div {
    background-color: #fff;
    margin: 10px;
    padding: 20px;
    font-size: 30px;
    }
    </style>
    </head>
    <body>

    <div class="flex-container">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    </div>

    </body>
    </html>

  • Axes

    所有 flexbox 的布局都有兩個軸,main axis 是跟隨著 flex items 順序的軸、而 cross axis 是垂直於主軸的軸。

    • flex-direction 屬性啟用主軸。
    • justify-content 屬性定義目前 flex items 的主軸如何擺放。
    • align-items 屬性定義目前 flex items 的 cross axis 如何擺放。
    • align-self 屬性定義目前單一 flex items 如何對齊。這個設定會覆蓋 align-items 的預設值。

  • Directions

    flexbox 的 main start/main end 與 cross start/cross end sides 描述了 flex items flow 的起點與終點。它們跟隨著由 writing-mode 所建立的向量中,flex container 的 main axis 與 cross axis 排列(左至右或右至左等等)。

    • order 將元素按順序排列,並決定哪些元素首先出現。
    • flex-flow 屬性是 flex-directionflex-wrap 屬性的簡寫,描述了 flex items 的整體布局。

  • Lines

    根據 flex-wrap 屬性,可以將 flex items 排列在一行或多行上,該屬性控制橫軸的方向和多行的堆疊方向。


  • Dimensions

    flex items 的高度和寬度分別依據 flex container 的 main axis 和 cross axis。

    • min-height 和 min-width 屬性的初始值為 0。
    • flex 屬性是 flex-growflex-shrinkflex-basis 屬性的簡寫,可以建立 flex items 的靈活性。

★ querySelectorAll()

querySelectorAll() 返回指定的 CSS 選擇器的所有元素(NodeList 物件)。

  • querySelectorAll()querySelector() 的差異:
    • querySelector 只返回匹配的第一個元素,如果沒有匹配項目,返回 null。
    • querySelectorAll 返回匹配的元素集合,如果沒有匹配項,返回空的 NodeList。
    • 這兩個方法都可以接受三種型別的引數:id(#)、class(.)、tag,很像 jQuery 的選擇器。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<body>

<h2 class="test">class="test" 的標題</h2>
<p class="test">class="test" 的段落</p>

<button onclick="myFunction()">點擊</button>

<script>
// 點擊後,class="test"的第一個元素改變顏色。
function myFunction() {
let x = document.querySelectorAll(".test");
x[0].style.backgroundColor = "yellow";
}
</script>

</body>
</html>

★ forEach()

forEach() 方法會將陣列內的每個元素,皆傳入並執行給定的函式一次。

範例:

1
2
3
4
5
const array1 = ['Chai', 'Jay', 'Kawa', 'Annie'];

array1.forEach(x => console.log(`super cute ${x}`));

// "super cute Chai" "super cute Jay" "super cute Kawa" "super cute Annie"

輸出結果看起來似乎有點眼熟,跟 Day04 Array.map() 幾乎一模一樣。

  • forEach()map() 方法有什麼不一樣呢?

    • map() 會分配內存空間儲存新 Array,並返回。

      適用於需要改變數值時。效能較 forEach() 高,且能夠使用複合技:map()filter()reduce() 等組合。

    • forEach() 允許 callback 更改原始 Array 的元素,不會返回新的 Array。

      適用於不打算改變數據的時候,只是想用數據做一些事情,比如存入數據庫或印出來。