关于程序员:练习动画最好的方式封面过渡

11次阅读

共计 7639 个字符,预计需要花费 20 分钟才能阅读完成。

首先让咱们来看一个镜头,这个镜头展现了几个过渡成果,其中之一就是我所说的 “ 封面过渡 ”,一个彩色的封面以动画模式暗藏了一些内容,而后新的内容在封面上显现出来(其色彩与之前的不同)。

我喜爱咱们能够在网页中应用大量不同的动画来展现新内容的内容。所以咱们明天将在一个简短的教程中看一下他的构造和动画的一些亮点。

我会应用 GreenSock 的 GSAP 作为成果的动画库。

标记和款式

我会以上面这个网站来实现这个成果

首先,咱们的整个页面将是一个网格布局

html 代码

<div class="content">
    <div class="item">
        <span class="item__meta">2020</span>
        <h2 class="item__title">Alex Moulder</h2>
        <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>
        <h2 class="item__title">Aria Bennett</h2>
        <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>
        <h2 class="item__title">Jimmy Hughes</h2>
        <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;
}

内容划分将有以下格调,以显示网格中的我的项目

.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;
    }
}

咱们只想在大屏幕上并排显示我的项目。所以咱们增加了一个媒体查问。

对于我的项目的外部元素,咱们将具备以下款式:

.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);
    }
}

图像元素有一个嵌套构造,能够让咱们做出一点缩放成果。这里有一个乏味的中央是宽高比属性,它容许咱们在应用背景图像属性时依据其理论大小设置响应式图像尺寸。

当咱们单击我的项目按钮时,咱们将显示一个封面动画。这将是动画其比例变换以笼罩整个页面的两个元素:

<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%;}

为每一“行”设置正确的变换原点将确保它们高低动画,“敞开”以后视图并暗藏它。

接下来,让咱们看一下咱们将看到的视图。此局部将称为“预览”,咱们将增加以下内容:

<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>
        <h2 class="preview__title oh"><span class="oh__inner">Moulder</span></h2>
        <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">
            <h3 class="preview__column-title oh"><span class="oh__inner">Location</span></h3>
            <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">
            <h3 class="preview__column-title oh"><span class="oh__inner">Material</span></h3>
            <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>

大图像将应用本教程中具体解释的显示 / 勾销显示动画进行动画解决。这就是咱们应用嵌套构造的起因,就像在我的项目图像上一样。对于咱们想要通过转变(并被父级截断)来显示的文本,咱们将应用 .oh > .oh__inner 构造。这背地的想法是转变 oh__inner 元素以暗藏它。对于多行文本,咱们将应用 JavaScript 动静增加此构造。咱们 preview__column 分区中的段落将应用SplitType 分成几行。

让咱们增加以下款式以使线条魔术起作用:

.oh {
    position: relative;
    overflow: hidden;
}

.oh__inner {
    will-change: transform;
    display: inline-block;
}

.line {
    transform-origin: 0 50%;
    white-space: nowrap;
    will-change: transform;
}

当初,让咱们把这个宝贝做成动画

The JavaScript

让咱们先定义和实例化一些货色

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)));

// 我的项目实例列表
const items = [];
[...document.querySelectorAll('.item')].forEach((item, pos) => items.push(new Item(item, previews[pos])));

当初,当咱们关上一个我的项目时,咱们首先要把咱们的内容设置为不能再点击。用一个类来实现。

而后,咱们在显示预览内容后,暗藏所有那些咱们想要动画化的线条和元素。preview-visible类帮忙咱们设置一些色彩和指针事件。咱们还用它来暗藏咱们在页面顶部的小框架,这样,一旦封面暗藏了初始视图,咱们就能够用动画再次显示它。

通过将图像元素向一个方向平移,将外部元素(实际上蕴含了背景图像)向相同的方向平移,图像就不会被显示进去。

咱们也最终显示了所有的线条和 oh__inner 元素。

const openItem = item => {
    
    gsap.timeline({
        defaults: {
            duration: 1, 
            ease: 'power3.inOut'
        }
    })
    .add(() => {
        // 指针事件没有指向内容
        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')
    // 动画框架元素
    .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')

};

当咱们敞开预览时,咱们须要做一些反向动画

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')
    
    // 动画框架元素
    .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')
};

不要遗记事件监听器

for (const item of items) {
    // 关上我的项目预览
    item.DOM.link.addEventListener('click', () => openItem(item));
    // 敞开我的项目预览
    item.preview.DOM.backCtrl.addEventListener('click', () => closeItem(item));
}

这就是这所有的后果

在动画进入时要有晦涩的转场动画,并做一个疾速的敞开动画,这样用户就不用期待很长时间来复原最后的视图了。摸索代码并尝试做一些其余的动画、计时和弛缓,给它另一种感觉,看看哪些是无效的,哪些是有效的!

谢谢你观看到这里,拜拜✌️

本文由 mdnice 多平台公布

正文完
 0