使用JavaScript練習(xí)動(dòng)畫(huà)最好的方式封面過(guò)渡
引言
首先讓我們來(lái)看一個(gè)鏡頭,這個(gè)鏡頭展示了幾個(gè)過(guò)渡效果,其中之一就是我所說(shuō)的 "封面過(guò)渡",一個(gè)黑色的封面以動(dòng)畫(huà)形式隱藏了一些內(nèi)容,然后新的內(nèi)容在封面上顯現(xiàn)出來(lái)(其顏色與之前的不同)。
我喜歡我們可以在網(wǎng)頁(yè)中使用大量不同的動(dòng)畫(huà)來(lái)展示新內(nèi)容的內(nèi)容。所以我們今天將在一個(gè)簡(jiǎn)短的教程中看一下他的結(jié)構(gòu)和動(dòng)畫(huà)的一些亮點(diǎn)。
我會(huì)使用GreenSock的GSAP作為效果的動(dòng)畫(huà)庫(kù)。
標(biāo)記和樣式
我會(huì)以下面這個(gè)網(wǎng)站來(lái)實(shí)現(xiàn)這個(gè)效果
首先,我們的整個(gè)頁(yè)面將是一個(gè)網(wǎng)格布局
html代碼
<div class="content"> <div class="item"> <span class="item__meta">2020</span> <h3 class="item__title">Alex Moulder</h3> <div class="item__img"><div class="item__img-inner" style="background-image:url(img/1.jpg)"></div></div> <p class="item__desc">I am only waiting for love to give myself up at last into his hands. That is why it is so late and why I have been guilty of such omissions.</p> <a class="item__link">view</a> </div> <div class="item"> <span class="item__meta">2021</span> <h3 class="item__title">Aria Bennett</h3> <div class="item__img"><div class="item__img-inner" style="background-image:url(img/2.jpg)"></div></div> <p class="item__desc">They come with their laws and their codes to bind me fast; but I evade them ever, for I am only waiting for love to give myself up at last into his hands.</p> <a class="item__link">view</a> </div> <div class="item"> <span class="item__meta">2022</span> <h3 class="item__title">Jimmy Hughes</h3> <div class="item__img"><div class="item__img-inner" style="background-image:url(img/3.jpg)"></div></div> <p class="item__desc">Clouds heap upon clouds and it darkens. Ah, love, why dost thou let me wait outside at the door all alone?</p> <a class="item__link">view</a> </div> </div>
CSS代碼
main { padding: 1.5rem 2.5rem 3rem; height: 100vh; display: grid; grid-template-columns: 100%; grid-template-areas: 'frame' 'content'; grid-template-rows: min-content 1fr; grid-row-gap: 8vh; }
內(nèi)容劃分將有以下風(fēng)格,以顯示網(wǎng)格中的項(xiàng)目
.content { grid-area: content; max-width: 400px; } @media screen and (min-width: 53em) { .content { max-width: none; display: grid; grid-template-columns: repeat(3,1fr); grid-template-rows: 100%; grid-column-gap: 5vw; } }
我們只想在大屏幕上并排顯示項(xiàng)目。所以我們添加了一個(gè)媒體查詢(xún)。
對(duì)于項(xiàng)目的內(nèi)部元素,我們將具有以下樣式:
.item { margin-bottom: 5rem; display: grid; grid-template-columns: 100%; grid-template-rows: 1rem auto auto 1fr auto; } .item__title { font-family: kudryashev-d-excontrast-sans, sans-serif; font-weight: 300; font-size: 2rem; margin-bottom: 0.5rem; } .item__img { position: relative; overflow: hidden; width: 100%; aspect-ratio: 500/333; } .item__img-inner { background-position: 50% 45%; background-size: cover; width: 100%; height: 100%; } .item__desc { margin-top: 2.5rem; line-height: 1.1; } .item__link { cursor: pointer; text-transform: lowercase; width: 100%; padding: 1rem; color: var(--color-text); border: 1px solid var(--color-border); border-radius: 2rem; text-align: center; } .item__link:hover { background: var(--color-text); border-color: var(--color-text); color: var(--color-text-alt); } @media screen and (min-width: 53em) { .item { margin-bottom: 0; } .item__title { font-size: clamp(1.25rem,3vw,2rem); } }
圖像元素有一個(gè)嵌套結(jié)構(gòu),可以讓我們做出一點(diǎn)縮放效果。這里有一個(gè)有趣的地方是寬高比屬性,它允許我們?cè)谑褂帽尘皥D像屬性時(shí)根據(jù)其實(shí)際大小設(shè)置響應(yīng)式圖像尺寸。
當(dāng)我們單擊項(xiàng)目按鈕時(shí),我們將顯示一個(gè)封面動(dòng)畫(huà)。這將是動(dòng)畫(huà)其比例變換以覆蓋整個(gè)頁(yè)面的兩個(gè)元素:
<div class="overlay"> <div class="overlay__row"></div> <div class="overlay__row"></div> </div>
讓我們添加以下樣式:
.overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: grid; grid-template-columns: 100%; pointer-events: none; grid-template-rows: repeat(2,1fr); } .overlay__row { background: var(--color-overlay); transform: scaleY(0); will-change: transform; } .overlay__row:first-child { transform-origin: 50% 0%; } .overlay__row:last-child { transform-origin: 50% 100%; }
為每一“行”設(shè)置正確的變換原點(diǎn)將確保它們上下動(dòng)畫(huà),“關(guān)閉”當(dāng)前視圖并隱藏它。
接下來(lái),讓我們看一下我們將看到的視圖。此部分將稱(chēng)為“預(yù)覽”,我們將添加以下內(nèi)容:
<section class="previews"> <div class="preview"> <div class="preview__img"><div class="preview__img-inner" style="background-image:url(img/1_big.jpg)"></div></div> <h3 class="preview__title oh"><span class="oh__inner">Moulder</span></h3> <div class="preview__column preview__column--start"> <span class="preview__column-title preview__column-title--main oh"><span class="oh__inner">Alex Moulder</span></span> <span class="oh"><span class="oh__inner">2020</span></span> </div> <div class="preview__column"> <h4 class="preview__column-title oh"><span class="oh__inner">Location</span></h4> <p>And if it rains, a closed car at four. And we shall play a game of chess, pressing lidless eyes and waiting for a knock upon the door.</p> </div> <div class="preview__column"> <h4 class="preview__column-title oh"><span class="oh__inner">Material</span></h4> <p>At the violet hour, when the eyes and back, turn upward from the desk, when the human engine waits.</p> </div> <button class="unbutton preview__back"><svg width="100px" height="18px" viewBox="0 0 50 9"><path vector-effect="non-scaling-stroke" d="m0 4.5 5-3m-5 3 5 3m45-3h-77"></path></svg></button> </div> <!-- preview --> <!-- preview --> </section>
大圖像將使用本教程中詳細(xì)解釋的顯示/取消顯示動(dòng)畫(huà)進(jìn)行動(dòng)畫(huà)處理。這就是我們使用嵌套結(jié)構(gòu)的原因,就像在項(xiàng)目圖像上一樣。對(duì)于我們想要通過(guò)轉(zhuǎn)變(并被父級(jí)截?cái)啵﹣?lái)顯示的文本,我們將使用 .oh > .oh__inner
結(jié)構(gòu)。這背后的想法是轉(zhuǎn)變oh__inner
元素以隱藏它。對(duì)于多行文本,我們將使用 JavaScript 動(dòng)態(tài)添加此結(jié)構(gòu)。我們 preview__column
分區(qū)中的段落將使用SplitType
分成幾行。
讓我們添加以下樣式以使線(xiàn)條魔術(shù)起作用:
.oh { position: relative; overflow: hidden; } .oh__inner { will-change: transform; display: inline-block; } .line { transform-origin: 0 50%; white-space: nowrap; will-change: transform; }
現(xiàn)在,讓我們把這個(gè)寶貝做成動(dòng)畫(huà)
The JavaScript
讓我們先定義和實(shí)例化一些東西
import { gsap } from 'gsap'; import { Item } from './item'; import { Preview } from './preview'; // body element const body = document.body; // .content element const contentEl = document.querySelector('.content'); // frame element const frameEl = document.querySelector('.frame'); // 頂部和底部疊加的疊加元素 const overlayRows = [...document.querySelectorAll('.overlay__row')]; const previews = []; [...document.querySelectorAll('.preview')].forEach(preview => previews.push(new Preview(preview))); //項(xiàng)目實(shí)例列表 const items = []; [...document.querySelectorAll('.item')].forEach((item, pos) => items.push(new Item(item, previews[pos])));
現(xiàn)在,當(dāng)我們打開(kāi)一個(gè)項(xiàng)目時(shí),我們首先要把我們的內(nèi)容設(shè)置為不能再點(diǎn)擊。用一個(gè)類(lèi)來(lái)完成。
然后,我們?cè)陲@示預(yù)覽內(nèi)容后,隱藏所有那些我們想要?jiǎng)赢?huà)化的線(xiàn)條和元素。preview-visible
類(lèi)幫助我們?cè)O(shè)置一些顏色和指針事件。我們還用它來(lái)隱藏我們?cè)陧?yè)面頂部的小框架,這樣,一旦封面隱藏了初始視圖,我們就可以用動(dòng)畫(huà)再次顯示它。
通過(guò)將圖像元素向一個(gè)方向平移,將內(nèi)部元素(實(shí)際上包含了背景圖像)向相反的方向平移,圖像就不會(huì)被顯示出來(lái)。
我們也最終顯示了所有的線(xiàn)條和oh__inner
元素。
const openItem = item => { gsap.timeline({ defaults: { duration: 1, ease: 'power3.inOut' } }) .add(() => { // 指針事件沒(méi)有指向內(nèi)容 contentEl.classList.add('content--hidden'); }, 'start') .addLabel('start', 0) .set([item.preview.DOM.innerElements, item.preview.DOM.backCtrl], { opacity: 0 }, 'start') .to(overlayRows, { scaleY: 1 }, 'start') .addLabel('content', 'start+=0.6') .add(() => { body.classList.add('preview-visible'); gsap.set(frameEl, { opacity: 0 }, 'start') item.preview.DOM.el.classList.add('preview--current'); }, 'content') // Image animation (reveal animation) .to([item.preview.DOM.image, item.preview.DOM.imageInner], { startAt: {y: pos => pos ? '101%' : '-101%'}, y: '0%' }, 'content') .add(() => { for (const line of item.preview.multiLines) { line.in(); } gsap.set(item.preview.DOM.multiLineWrap, { opacity: 1, delay:0.1 }) }, 'content') // 動(dòng)畫(huà)框架元素 .to(frameEl, { ease: 'expo', startAt: {y: '-100%', opacity: 0}, opacity: 1, y: '0%' }, 'content+=0.3') .to(item.preview.DOM.innerElements, { ease: 'expo', startAt: {yPercent: 101}, yPercent: 0, opacity: 1 }, 'content+=0.3') .to(item.preview.DOM.backCtrl, { opacity: 1 }, 'content') };
當(dāng)我們關(guān)閉預(yù)覽時(shí),我們需要做一些反向動(dòng)畫(huà)
const closeItem = item => { gsap.timeline({ defaults: { duration: 1, ease: 'power3.inOut' } }) .addLabel('start', 0) .to(item.preview.DOM.innerElements, { yPercent: -101, opacity: 0, }, 'start') .add(() => { for (const line of item.preview.multiLines) { line.out(); } }, 'start') .to(item.preview.DOM.backCtrl, { opacity: 0 }, 'start') .to(item.preview.DOM.image, { y: '101%' }, 'start') .to(item.preview.DOM.imageInner, { y: '-101%' }, 'start') // 動(dòng)畫(huà)框架元素 .to(frameEl, { opacity: 0, y: '-100%', onComplete: () => { body.classList.remove('preview-visible'); gsap.set(frameEl, { opacity: 1, y: '0%' }) } }, 'start') .addLabel('grid', 'start+=0.6') .to(overlayRows, { //ease: 'expo', scaleY: 0, onComplete: () => { item.preview.DOM.el.classList.remove('preview--current'); contentEl.classList.remove('content--hidden'); } }, 'grid') };
不要忘記事件監(jiān)聽(tīng)器
for (const item of items) { // 打開(kāi)項(xiàng)目預(yù)覽 item.DOM.link.addEventListener('click', () => openItem(item)); // 關(guān)閉項(xiàng)目預(yù)覽 item.preview.DOM.backCtrl.addEventListener('click', () => closeItem(item)); }
這就是這一切的結(jié)果
在動(dòng)畫(huà)進(jìn)入時(shí)要有流暢的轉(zhuǎn)場(chǎng)動(dòng)畫(huà),并做一個(gè)快速的關(guān)閉動(dòng)畫(huà),這樣用戶(hù)就不必等待很長(zhǎng)時(shí)間來(lái)恢復(fù)最初的視圖了。探索代碼并嘗試做一些其他的動(dòng)畫(huà)、計(jì)時(shí)和緩和,給它另一種感覺(jué),看看哪些是有效的,哪些是無(wú)效的!
以上就是使用JavaScript練習(xí)動(dòng)畫(huà)最好的方式封面過(guò)渡的詳細(xì)內(nèi)容,更多關(guān)于JavaScript動(dòng)畫(huà)封面過(guò)渡的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用preload預(yù)加載頁(yè)面資源時(shí)注意事項(xiàng)
本文主要介紹 preload 的使用,以及與 prefetch 的區(qū)別。然后會(huì)聊聊瀏覽器的加載優(yōu)先級(jí),大家一定要認(rèn)真看完2020-02-02JS前端使用Canvas快速實(shí)現(xiàn)手勢(shì)解鎖特效
這篇文章主要為大家介紹了JS前端使用Canvas快速實(shí)現(xiàn)手勢(shì)解鎖特效,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09微信小程序 action-sheet 反饋上拉菜單簡(jiǎn)單實(shí)例
這篇文章主要介紹了微信小程序 action-sheet 反饋上拉菜單簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05利用js實(shí)現(xiàn)簡(jiǎn)單開(kāi)關(guān)燈代碼
這篇文章主要分享的是如何利用js實(shí)現(xiàn)簡(jiǎn)單開(kāi)關(guān)燈代碼,下面文字圍繞js實(shí)現(xiàn)簡(jiǎn)單開(kāi)關(guān)燈的相關(guān)資料展開(kāi)具體內(nèi)容,需要的朋友可以參考以下,希望對(duì)大家又所幫助2021-11-11ECharts框架分段視覺(jué)映射在移動(dòng)端適配
這篇文章主要介紹了ECharts框架分段視覺(jué)映射在移動(dòng)端適配詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12AngularJS 表達(dá)式詳細(xì)講解及實(shí)例代碼
本文主要介紹AngularJS 表達(dá)式,這里對(duì)AngularJS 表達(dá)式詳細(xì)介紹和實(shí)例代碼,有需要的小伙伴可以參考下2016-07-07LoadRunner調(diào)用JS加密后登錄實(shí)現(xiàn)
這篇文章主要為大家介紹了LoadRunner調(diào)用JS加密后登錄實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06