# 新聞網頁製作(六)- 多媒體元素與動態效果
## 學習大綱:
- [新聞網頁製作 (一) - HTML 標記式語言](https://hackmd.io/svhFYKq4QyaarC_J0WRsig)
- [新聞網頁製作(二) - CSS 串接樣式表](https://hackmd.io/Pekdv0mvT8qD_LXLzUo9iQ)
- [新聞網頁製作(三)- CSS 選擇器與基礎網頁排版](https://hackmd.io/ccO-gvxFR5-49q3ePoNJkg)
- [新聞網頁製作(四)- CSS Position 與 Flexbox 排版](https://hackmd.io/i1uBelrpRv2Uz5emQawIiw)
- [新聞網頁製作(五)- Responsive Web Design 響應式網頁](https://hackmd.io/ojTXG2s0RQaJz85goqIz1w)
- [新聞網頁製作(六)- 多媒體元素與動態效果](https://hackmd.io/J_YYk1YUSum1x3fVo75PXA)
- [新聞網頁製作(七)- 使用 GitHub 部署網頁](https://hackmd.io/P9N34oIwS2G6Mfhag3Rqzg)
# 多媒體網頁製作
多媒體(Multimedia)在維基百科上的解釋如下:
組合兩種或兩種以上媒體的一種人機互動式資訊交流和傳播媒體。
使用的媒體包括文字、圖片、照片、聲音(包含音樂、語音旁白、特殊音效)、動畫和影片,以及程序所提供的互動功能。
前幾堂課,我們已經學習到文字和照片的版型編排。
接下來,我們會將影片(video)、聲音(audio)和其他網站提供的多媒體功能(像是 youtube、infogram ... 等等)放入網頁之中,提供閱聽眾更多不同的媒介與感受。
## 影片 `<video>`
隨著瀏覽器的進步和 HTML5 的推出,我們要在網頁上播放影片檔,是一件非常容易的事情。<br/>
只要使用 `<video>` 標籤就可以輕易辦到。
由於各家瀏覽器支援的影片格式不同([請見 Browser Support 章節](https://www.w3schools.com/html/html5_video.asp)),<br/>
一般來說,我們至少會提供兩種不同檔案格式的影片,webm 或是 MPEG-4/H.264(mp4)。
https://raw.githubusercontent.com/nickhsine/teach-at-nccu/gh-pages/assets/2018-05-03/video.mp4
```
<video width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
<source src="movie.webm" type="video/webm">
Your browser does not support the video tag.
</video>
```
在 `<video>` 裡,有許多屬性可以設定:
`controls`:呈現控制列表
`autoplay`:自動播放
`loop`:輪播
`muted`:靜音
`width`:影片寬度
`height:` 影片高度
請見[範例](https://jsbin.com/timusahuvo/edit?html,output)
```
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<video controls muted loop autoplay>
<source type="video/mp4" src="https://raw.githubusercontent.com/nickhsine/teach-at-nccu/gh-pages/assets/2018-05-03/video.mp4"></source>
</video>
</body>
</html>
```
## 聲音 `<audio>`
`<audio>` 和 `<video>` 的用法非常相似,所以你可以用理解 `<video>` 的方式來理解 `<audio>`,<br/>
基本上,就是把 video tag 換成 audio tag,然後把 `src` 的部分換成 mp3 檔。<br/>
請見[範例](https://jsbin.com/cuwurezudo/edit?html,output)
```
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<audio controls>
<source type="audio/mp3" src="https://raw.githubusercontent.com/nickhsine/teach-at-nccu/gh-pages/assets/2018-05-03/audio.mp3"></source>
</audio>
</body>
</html>
```
## 手機平板上的陷阱:自動播放
根據 Apple 和 Google 影片/聲音播放的政策,在沒有使用者的同意前(透過互動),<br/>
瀏覽器是不支援自動播放(有聲音)影片,<br/>
假設你的設定是 `<video autoplay>` 的話,在手機上看,你會發現影片莫名被停下來。<br/>
因此,你若想要自動播放,你的設定必須是 `<video autoplay muted>`,用靜音的模式來自動播放。
# 鑲入他站服務
網際網路至今如此發達,我們有許多免費的網路資源可以使用,
透過以下的方式,我們可以輕易地把免費的資源鑲嵌在我們的網頁之中。
(1) 找出要鑲嵌的程式碼
(2.1) 若要鑲嵌的程式碼支援 RWD -> done (Ex: Instagram)
(2.2) 若要鑲嵌的程式碼不支援 RWD -> 3) (Ex: Youtube)
(3) 算出要鑲嵌的內容的高寬比
(4) 根據高寬比製造空間來放欲鑲嵌的內容
(5) 將其空間設定成 `position: relative`,欲擺放的程式碼設定成 `position: absolute; width: 100%; height: 100%`。
以下分別以 Instagram 和 Youtube 為例:
### [Instagram 範例](https://jsbin.com/keyagefuzu/1/edit?html,output)
```htmlmixed=false
<!-- 若 Instagram 範例的連結失效,可用此份程式碼 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-permalink="https://www.instagram.com/p/BiRYFLzDNqD/" data-instgrm-version="8" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);"><div style="padding:8px;"> <div style=" background:#F8F8F8; line-height:0; margin-top:40px; padding:33.14814814814815% 0; text-align:center; width:100%;"> <div style=" background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAMUExURczMzPf399fX1+bm5mzY9AMAAADiSURBVDjLvZXbEsMgCES5/P8/t9FuRVCRmU73JWlzosgSIIZURCjo/ad+EQJJB4Hv8BFt+IDpQoCx1wjOSBFhh2XssxEIYn3ulI/6MNReE07UIWJEv8UEOWDS88LY97kqyTliJKKtuYBbruAyVh5wOHiXmpi5we58Ek028czwyuQdLKPG1Bkb4NnM+VeAnfHqn1k4+GPT6uGQcvu2h2OVuIf/gWUFyy8OWEpdyZSa3aVCqpVoVvzZZ2VTnn2wU8qzVjDDetO90GSy9mVLqtgYSy231MxrY6I2gGqjrTY0L8fxCxfCBbhWrsYYAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-22px; width:44px;"></div></div> <p style=" margin:8px 0 0 0; padding:0 4px;"> <a href="https://www.instagram.com/p/BiRYFLzDNqD/" style=" color:#000; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none; word-wrap:break-word;" target="_blank">Image by @beverlyjoubert. Okavango lions are known for their swimming rather than their tree-climbing abilities but we’re seeing this behavior more often at Duba Plains. There are numerous dead trees, uprooted in previous vicious storms that these lions are increasingly using. The lionesses are using them to gain advantages in hunting but this big male just seemed to be watching - perhaps keeping an eye on his territory. Unfortunately for him, his legs are not built like a leopard’s and he went too high to be able to comfortably descend. After a lot of shuffling, he tried to climb down but his weight was too much and he slipped, falling a great height. @dereckjoubert and I rushed over to check on him, thinking he would have hurt himself seriously, but thankfully it was his dignity that suffered and not his bones. It will be interesting to see if he tries to climb any great height again. #okavangolions #tsaropride #bigcats #thisismytrophy</a></p> <p style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;">A post shared by <a href="https://www.instagram.com/natgeo/" style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px;" target="_blank"> National Geographic</a> (@natgeo) on <time style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px;" datetime="2018-05-02T10:21:09+00:00">May 2, 2018 at 3:21am PDT</time></p></div></blockquote> <script async defer src="//www.instagram.com/embed.js"></script>
</body>
</html>
```
#### (1) 找出 Instagram 鑲嵌程式碼
![](https://i.imgur.com/NDsycOl.gif)
#### (2) Instagram 鑲嵌程式碼支援 RWD,所以將鑲嵌程式碼貼在 HTML 裡即可。
---
### [Youtube 範例](https://jsbin.com/cuqulapiho/edit?html,output)
```htmlmixed=fasle
<!-- 若 Youtube 範例的連結失效,可用此份程式碼 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
.youtube-embed {
position: relative;
padding-bottom: calc(315/560*100%);
}
</style>
</head>
<body>
<div class="youtube-embed">
<iframe style="position:absolute" width="100%" height="100%" src="https://www.youtube.com/embed/E6hIhWGyVnE" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
</div>
</body>
</html>
```
#### (1) 找出 Youtube 鑲嵌程式碼
![](https://i.imgur.com/7ctVBLe.gif)
#### (2) Youtube 鑲嵌程式碼不支援 RWD
以下是 Youtube 的鑲嵌程式碼,我們會發現鑲嵌程式碼使用的是`<iframe>`標籤,寬度是560px,高度是315px;寬與高是寫死的,因此影片不會根據不同載具或是不同 viewport 進行調整。
```htmlmixed=false
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/E6hIhWGyVnE" frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
>
</iframe>
```
#### (3) 算出要鑲嵌的內容的高寬比
影片寬度是560px,高度是315px,高寬比是`calc(315 / 560 * 100%)`,意即高度除寬度,再乘上100%。
#### (4) 根據高寬比製造空間來放欲鑲嵌的內容
我們利用 `padding-bottom: calc(315 / 560 * 100%)`的樣式,創造與高寬比一樣的空白區塊。
#### (5) 將其空間設定成 `position: relative`,欲擺放的程式碼設定成 `position: absolute; width: 100%; height: 100%`。
將步驟4.創造出來的空白區塊,加上`position: relative`的樣式。
並將`<iframe>`貼在空白區塊中,並將其撐滿整個空白區塊。
完整程式碼如下:
```htmlmixed=false
<!-- 外層的 div 限制了 youtube 的大小 -->
<!-- 因為 padding-bottom 的設定,讓此 div 隨著瀏覽器 viewport 大小變化而變化。 -->
<div style="padding-bottom: calc(315 / 560 * 100%); position: relative;">
<!-- 請注意我們改寫了 width 和 height 屬性的值 -->
<iframe
style="position: absolute;"
width="100%"
height="100%"
src="https://www.youtube.com/embed/E6hIhWGyVnE" frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
>
</iframe>
</div>
```
---
# 讓網頁動起來
讓網頁動起來有很多種方式,最簡單方便的方式不外乎使用以下兩種辦法:
1) CSS Transition
2) CSS Animation
## CSS Transition
CSS Transition 提供了以下樣式讓我們設定動畫的細節:
1. `transition-property`:動畫要套用的樣式。
2. `transition-duration`: 動畫執行的時間。
3. `transition-delay`:延遲動畫開始的時間。
4. `transition-timing-function`:根據貝茲曲線來決定動畫呈現的速度。
### `transition-property`:動畫要套用的樣式
|樣式值|說明|預設值|
|---|---|---|
|all|所有的樣式都套用動畫效果。|yes|
|none|沒有樣式套用動畫效果。|no|
|*property*|指定要套用動畫效果的樣式。若有多個樣式要套用,則用`,`分隔。|no|
|initial|選擇預設值,也是就是 all 。|no|
|inherit|繼承父母的樣式值。|no|
範例:
```css=1
transition-property: all;
transition-property: none;
transition-property: width, height; /* 指定 width 和 height 要套用動畫效果 */
```
### `transition-duration`:動畫執行的時間
|樣式值|說明|預設值|
|---|---|---|
|*time*|花多少時間完成動畫效果。若沒有給值,預設是 0s。|yes|
|initial|選擇預設值,也是就是 0s 。|no|
|inherit|繼承父母的樣式值。|no|
範例:
```css=1
transition-duration: 5s; /* 5秒 */
transition-duration: 0.3s; /* 0.3 秒 */
transition-duration: 300ms; /* 300毫秒,等同於 0.3s */
```
### `transition-delay`:延遲動畫開始的時間
|樣式值|說明|預設值|
|---|---|---|
|*time*|延遲多少時間開始執行動畫。若沒有給值,預設是 0s。|yes|
|initial|選擇預設值,也是就是 0s 。|no|
|inherit|繼承父母的樣式值。|no|
範例:
```css=1
transition-delay: 5s; /* 延遲 5 秒開始動畫 */
transition-delay: 0.3s; /* 延遲 0.3 秒 */
transition-delay: 300ms; /* 延遲 300 毫秒,等同於 0.3s */
```
### `transition-timing-function`:根據貝茲曲線來決定動畫呈現的速度
|<div style="width:180px">樣式值</div>|說明|預設值|
|---|---|---|
|ease|動畫速度先慢、後快、再慢,效果如同`cubic-bezier(0.25,0.1,0.25,1)`|yes|
|linear|動畫速度由頭到尾都ㄧ樣,效果如同`cubic-bezier(0,0,1,1)`|no|
|ease-in|動畫速度由慢到快,效果如同`cubic-bezier(0.42,0,1,1)`|no|
|ease-out|動畫速度由快到慢,效果如同`cubic-bezier(0,0,0.58,1)`|no|
|ease-in-out|動畫速度的開頭與 ease-in 一樣,而結尾則與 ease-out 一樣,效果如同`cubic-bezier(0.42,0,0.58,1)`|no|
|*cubic-bezier(n,n,n,n)*|動畫速度參考貝茲曲線。|no|
|*steps*|動畫分成多個階段,每個階段會停留一樣的時間。|no|
|initial|選擇預設值,也是就是 ease 。|no|
|inherit|繼承父母的樣式值。|no|
範例:
```css=1
transition-timing-function: ease;
transition-timing-function: ease-in-out;
transition-timing-function: cubic-bezier(0,1,1,0);
transition-timing-function: steps(10);
```
* 可以透過[貝茲曲線產生器](http://roblaplaca.com/examples/bezierBuilder/)產生你想要的動畫速度。
### CSS Transition 範例
透過設定CSS `transition` 屬性,可以在一段時間內,針對不同的 CSS 元素產生動畫。
舉例而言,你想要一個 `div` 被滑鼠的游標 hover 的時候,在一秒內,寬度從 300px 變寬到 500px。
你可以這樣子寫:
```
<html>
<head>
<style>
.width-will-grow {
width: 300px;
height: 100px;
background-color: pink;
}
.width-will-grow:hover {
width: 500px;
transition: width 1s linear 0.5s;
}
</style>
</head>
<body>
<div class="width-will-grow">
</div>
</body>
</html>
```
`transition: width 1s linear 0.5s` 是縮寫,一開始對 `transition` 不熟的話,這行代表的意思是下面這段程式碼
```
transition-property: width;
transition-duration: 1s;
transition-timing-function: linear;
transition-delay: 0.5s;
```
`transition-property` 的值即是你想要有動畫效果的 CSS 屬性。`transition-property: width` 即代表動畫要加在 `width`上。
瀏覽器會根據動畫前 `width` 的值(300px),和動畫後 `width` 的值(500px),算出在一秒之內(`transition-duration: 1s`)要作用的動畫效果(300px -> 500px)。
`transition-delay: 0.5s`,顧名思義,就是延後 0.5 秒才開始動畫。
`transition-timing-function: linear`,動畫從頭到尾都以同一個速度進行。
<img src="">
## CSS Animations
CSS 提供了 `@keyframes` 和 `animation`,讓 HTML 大部分的元素可以動起來。
`@keyframes` 和 `animation` 與 `transition` 的不同在於,
透過 `@keyframes` 的設定,你可以定義動畫的細節,而 `transition` 則是瀏覽器透過運算來規劃動畫。
因此,我們無法仔細地規劃動畫細節。
為了更細緻地規劃我們要的動畫,接下來要示範如何使用 `@keyframes` 和 `animation`。
同樣讓 `div`,寬度從 300px 長到 500px,
我們可以用 `@keyframes` 和 `animation` 的寫法:
```
<html>
<head>
<style>
@keyframes grow-from-300-to-500 {
from {
width: 300px;
}
to {
width: 500px;
}
}
.width-will-grow {
width: 300px;
height: 100px;
background-color: pink;
}
.width-will-grow:hover {
animation-name: grow-from-300-to-500;
animation-duration: 1s;
animation-delay: .5s;
}
</style>
</head>
<body>
<div class="width-will-grow">
</div>
</body>
</html>
```
透過 `from` 和 `to`,我們可以定義動畫的開始和結束,其餘交由瀏覽器規劃執行。<br/>
但如果我們今天想要更細緻地規劃動畫的流程,我們可以用百分比寫法。<br/>
```
@keyframes grow-from-300-to-500 {
0% {
width: 300px;
}
25% {
width: 330px;
}
50% {
width: 450px;
}
75% {
width: 350px;
}
100% {
width: 500px;
}
}
```
瀏覽器會根據我們在百分比裡面的設定執行動畫,所以雖然開頭和結尾一樣(300px -> 500px),<br/>
但中間則多了我們設定好的動畫補間。
`animation` 是縮寫,它代表了許多 `animation-*` 的設定。<br/>
以下的表格介紹了 `animation` 所有可以設定的 CSS 屬性
| 屬性名稱 | 解釋 | 範例 |
|------------|------|------|
| @keyframes | 詳述動畫細節 | `@keyframes { from { width: 300px; } to { width: 500px; } }` |
| animation | 動畫屬性的縮寫 | `animation: grow-from-300-to-500 1s linear .5s 1 normal` |
| animation-delay | 延遲動畫的時間 | `animation-delay: .5s` |
| animation-direction | 動畫播放的順序 | `animation-direction: normal` |
| animation-duration | 動畫播放的時間 | `animation-duration: 1s` |
| animation-fill-mode | 動畫播放前後,欲動畫的元素 style 設定 | `animation-fill-mode: none` |
| animation-iteration-count | 動畫播放的次數 | `animation-iteration-count: 1` |
| animation-name | 動畫的名稱 | `animation-name: grow-from-300-to-500` |
| animation-timing-function | 動畫播放的速度曲線 | `animation-timing-function: linear` |
| animation-play-state | 動畫播放的狀態 | `animation-play-state: running` |
大體上,除了 `animation-fill-mode` 和 `animation-iteration-count`,其他的屬性都跟 `transition` 的差不多。<br/>
`animation-fill-mode` 屬性的值有以下幾項:<br/>
| `animation-fill-mode` 的值 | 說明 |
|----------------------------|------|
| none (預設值)| 在動畫前後,都不特別設定欲動畫的元素的樣式 |
| forwards | 動畫結束後,元素保留動畫最後的(last keyframe) 樣式設定 |
| backwards | 動畫開始前,在 `animation-delay` 的時間內,元素採用動畫最開頭(first keyframe)的樣式設定 |
| both | 採用 forwards 和 backwards 的設定 |
而,`animation-iteration-count` 除了可以設定要動畫重複的次數,例如`animation-iteration-count:5`,即是動畫重複五遍。<br/>
也可以將 `animation-iteration-count: infinite`,動畫將無限地播放下去。
範例一:跳動的魚
<iframe height="300" style="width: 100%;" scrolling="no" title="css: animation - jumping fish" src="https://codepen.io/nickhsine/embed/yLRGrmy?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/nickhsine/pen/yLRGrmy">
css: animation - jumping fish</a> by nickhsine (<a href="https://codepen.io/nickhsine">@nickhsine</a>)
on <a href="https://codepen.io">CodePen</a>.
</iframe>
範例二:飛鳥
<iframe height="300" style="width: 100%;" scrolling="no" title="Untitled" src="https://codepen.io/nickhsine/embed/jOeXoME?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/nickhsine/pen/jOeXoME">
Untitled</a> by nickhsine (<a href="https://codepen.io/nickhsine">@nickhsine</a>)
on <a href="https://codepen.io">CodePen</a>.
</iframe>
#### 延伸閱讀
- [CSS Hover Animation Tutorial](https://tympanus.net/codrops/2011/11/02/original-hover-effects-with-css3/)
- [CSS Hover Animation Demo](https://tympanus.net/Tutorials/OriginalHoverEffects/index.html)
###### tags: `teach-at-nccu`, `css`, `html`, `css animation`