简要说明
这是一款基于HTML5 WebGL的图像扭曲变形动画特效。该特效中,通过Three.js来制作从一幅缩略图,扭曲变形为全屏大图的动画特效,共有6种炫酷的动画效果。
该特效提供了一个控制面板来控制图像扭曲的动画,你可以自行调节效果。
实现方法
HTML结构
<div id="app"></div>
<div id="itemsWrapper">
<figure class="grid__item">
<img class="grid__item-img" src="img/1.jpg" alt="An image" />
<img class="grid__item-img grid__item-img--large" src="img/1_large.jpg" />
<figcaption class="grid__item-caption">
<h2 class="grid__item-title">Our Item Title</h2>
<p class="grid__item-text">
Our Item Description
</p>
</figcaption>
</figure>
...
</div>
引入base.css
#cdawrap .carbon-text {
--cda-text-color: #aba1a6;
padding: 0.25rem 0 0.75rem;
display: block;
line-height: 1.4;
font-weight: 700;
font-weight: var(--cda-text-weight);
text-decoration: none;
text-transform: none;
letter-spacing: 0px;
border: 0;
}
body #cdawrap {
--cda-left: 2rem;
--cda-right: auto;
--cda-top: auto;
--cda-bottom: 6rem;
z-index: 1;
}
*,
*::after,
*::before {
box-sizing: border-box;
}
:root {
font-size: 15px;
}
body {
margin: 0;
--color-text: #615d5d;
--color-bg: #121217;
--color-link: #aba1a6;
--color-link-hover: #fff;
--color-info: #f58a4e;
color: var(--color-text);
background-color: var(--color-bg);
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif;
font-weight: 600;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow: hidden;
}
.dg .title {
transition: background-color 300ms ease-out;
}
.shine {
transition: background-color 100ms ease-out !important;
background-color: #fff !important;
}
#app {
top: 0;
left: 0;
position: fixed;
width: 100vw;
height: 100vh;
overflow: hidden;
}
#app:hover {
cursor: pointer;
}
.dg.ac {
z-index: 99999 !important;
}
/* Page Loader */
.js .loading::before {
content: '';
position: fixed;
z-index: 100000;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--color-bg);
}
.js .loading::after {
content: '';
position: fixed;
z-index: 100000;
top: 50%;
left: 50%;
width: 60px;
height: 60px;
margin: -30px 0 0 -30px;
pointer-events: none;
border-radius: 50%;
opacity: 0.4;
background: var(--color-link);
animation: loaderAnim 0.7s linear infinite alternate forwards;
}
@keyframes loaderAnim {
to {
opacity: 1;
transform: scale3d(0.5,0.5,1);
}
}
a {
text-decoration: none;
color: var(--color-link);
outline: none;
}
a:hover,
a:focus {
color: var(--color-link-hover);
outline: none;
}
.frame {
padding: 3rem 5vw;
text-align: center;
position: relative;
z-index: 1000;
}
.frame__title {
font-size: 1rem;
margin: 0 0 1rem;
}
.frame__tagline {
color: var(--color-info);
}
.frame__links {
display: inline;
}
.frame a {
text-transform: lowercase;
}
.frame__links a:not(:last-child),
.frame__demos a:not(:last-child) {
margin-right: 1rem;
}
.frame__demos {
margin: 1rem 0;
}
.frame__demo--current,
.frame__demo--current:hover {
color: var(--color-text);
}
.content {
display: flex;
flex-direction: column;
width: 100vw;
height: calc(100vh - 13rem);
position: relative;
justify-content: flex-start;
align-items: center;
}
.content__img {
width: 500px;
max-width: 100%;
display: block;
cursor: pointer;
}
.content__img--large {
pointer-events: none;
position: fixed;
opacity: 0;
}
@media screen and (min-width: 53em) {
.frame {
position: fixed;
text-align: left;
z-index: 10000;
top: 0;
left: 0;
display: grid;
align-content: space-between;
width: 100%;
max-width: none;
height: 100vh;
padding: 3rem;
pointer-events: none;
grid-template-columns: 50% 50%;
grid-template-rows: auto auto auto;
grid-template-areas: 'title ...'
'... ...'
'links demos';
}
.frame__title-wrap {
grid-area: title;
display: flex;
}
.frame__title {
margin: 0;
}
.frame__tagline {
position: relative;
margin: 0 0 0 1rem;
padding: 0 0 0 1rem;
opacity: 0.5;
}
.frame__demos {
margin: 0;
grid-area: demos;
justify-self: end;
}
.frame__links {
grid-area: links;
padding: 0;
justify-self: start;
}
.frame a {
pointer-events: auto;
}
.content {
height: 100vh;
justify-content: center;
}
}
引入javascript
<script src="js/imagesloaded.pkgd.min.js"></script>
<script src="js/three.min.js"></script>
<script src="js/TweenLite.min.js"></script>
<script src="js/CSSPlugin.min.js"></script>
<script src="js/EasePack.min.js"></script>
<script src="js/dat-gui.min.js"></script>
<script src="js/Configurator.js"></script>
<script src="js/GridToFullscreenEffect.js"></script>
<script src="js/basicDemo.js"></script>
<script>
const itemsWrapper = document.getElementById('items-wrap');
const configurator = createDemoConfigurator({
activation: { type: "side", props: { top: true, bottom: true} },
timing: {
type: "sections",
props: {
sections: 4,
}
},
transformation: {type: 'simplex'},
duration: 1.8,
easings: {
toFullscreen: Cubic.easeInOut,
toGrid: Cubic.easeInOut
}
})
imagesLoaded(document.querySelectorAll("img"), instance => {
//https://www.techrepublic.com/article/preloading-and-the-javascript-image-object/
document.body.classList.remove("loading");
let images = [];
for (var i = 0, imageSet = {}; i < instance.elements.length; i++) {
let image = {
element: instance.elements[i],
image: instance.images[i].isLoaded ? instance.images[i].img : null
};
if (i % 2 === 0) {
imageSet = {};
imageSet.small = image;
}
if (i % 2 === 1) {
imageSet.large = image;
images.push(imageSet);
}
}
configurator.effect.createTextures(images);
});
</script>
作者 | 思齐 | 蚂蚁开源社区大神,资深开发工程师