#flipanim
IS
AWESOME
<body>
<main>
<section>
<article>
<header>
<h1>
Put a rest to nesting.
</h1>
</header>
</article>
</section>
</main>
</body>
you shouldn't be seeing this
Frame-based layout
Constraint-based auto layout
Constraint-based auto layout
var heightConstraint: NSLayoutConstraint!
// ...
heightConstraint.constant = 100
UIView.animate(withDuration: 0.25) {
self.view.layoutIfNeeded()
}
Shared-element activity transitions
<android.support.v7.widget.CardView
...>
<ImageView
android:id="@+id/ivProfile"
android:transitionName="profile"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="160dp" />
...
</android.support.v7.widget.CardView>
<LinearLayout
...>
<ImageView
android:id="@+id/ivProfile"
android:transitionName="profile"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="380dp" />
...
</LinearLayout>
android:transitionName="profile"
opacity & transform
const box = document.querySelector('#box');
const first = getBoundingClientRect(box);
// {
// top: 400,
// left: 100,
// width: 200,
// height: 200,
// ...
// }
A
A
Rect
angle
getBoundingClient
😌
⁉️
// ... execute change
const bigBox = document
.querySelector('#big-box');
const last = getBoundingClientRect(bigBox);
// {
// top: 0,
// left: 0,
// width: 500,
// height: 500,
// ...
// }
B
100px
400px
0.4
0.4
const deltaX = first.left - last.left;
const deltaY = first.top - last.top;
const deltaW = first.width / last.width;
const deltaH = first.height / last.height;
B
// WAAPI
bigBox.animate([
{
transformOrigin: 'top left',
transform: `
scale(deltaW, deltaH)
translate(deltaX, deltaY)
`
},
{
transformOrigin: 'top left',
transform: 'none'
}
], {
duration: 300,
easing: 'ease-in-out',
fill: 'both'
});
// GSAP
TweenLite.fromTo(bigBox, .3, {
transformOrigin: 'top left',
transform: `
scale(deltaW, deltaH)
translate(deltaX, deltaY)
`
}, {
transformOrigin: 'top left',
transform: 'none'
});
const first = getBoundingClientRect(elm);
doSomething();
const last = getBoundingClientRect(elm);
const deltaX = first.left - last.left;
const deltaY = first.top - last.top;
const deltaW = first.width / last.width;
const deltaH = first.height / last.height;
elm.animate([{
transformOrigin: 'top left',
transform: `
translate(${deltaX}px, ${deltaY}px)
scale(${deltaW}, ${deltaH})
`
}, {
transformOrigin: 'top left',
transform: 'none'
}], {
duration: 300,
easing: 'ease-in-out',
fill: 'both'
});
Just don't. Please.
it'll load, I promise
what the flip
const parentBounds = // ...
const childBounds = // ...
const relativeBounds = {
top: childBounds.top - parentBounds.top,
left: childBounds.left - parentBounds.left
}
(and position: relative is your friend)
Choreography + staggering
Curved motion paths
Physics
Interruptible animations
<section class="gallery">
<div class="photo-1" data-flip-key="photo-1">
<img src="/photo-1"/>
</div>
<div class="photo-2" data-flip-key="photo-2">
<img src="/photo-2"/>
</div>
<div class="photo-3" data-flip-key="photo-3">
<img src="/photo-3"/>
</div>
</section>
npm install flipping --save
<section class="details">
<div class="photo" data-flip-key="photo-1">
<img src="/photo-1"/>
</div>
<p class="description">
Lorem ipsum dolor sit amet...
</p>
</section>
data-flip-key="..."
npm install flipping --save
const flipping = new Flipping();
// ...
photo1.addEventListener('click', () => {
// read the shared elements
flipping.read();
// change the UI state
viewPhotoDetail(1);
// FLIP the shared elements
flipping.flip();
});
const flipping = new Flipping();
// ...
photo1.addEventListener('click',
flipping.wrap(() => {
// change the UI state
viewPhotoDetail(1);
}));
npm install flipping --save
{
node: /* active node */,
delta: {
top: -100,
left: 300,
width: 0.5,
height: 2
}
}
const flipping = new Flipping({
onFlip: (state) => {
// create your own animations
animate(state.node, state.delta);
}
});
JAVASCRIPT
FLIP STATE
oh my god conference wifi
actually I'm on the hotel wifi but still
const flip = new FLIP({
element: target,
duration: 2000
});
// First position & opacity.
flip.first();
// Apply the 'end' class and
// snapshot last position/opacity
flip.last('end');
// Move and fade the element
// back to the original position.
flip.invert();
// Play it forwards.
flip.play();
import FlipMove from 'react-flip-move';
class TopArticles extends Component {
renderTopArticles() {
return this.props.articles
.map(article =>
<Article
{...article}
key={article.id}
/>
);
}
render() {
return (
<div className="top-articles">
<FlipMove easing="...">
{ this.renderTopArticles() }
</FlipMove>
</div>
);
}
}
Why are we OK with the user feeling like they are being teleported every time the page changes?
Can be used with FLIP technique
Transitions between pages
Can reduce HTTP requests
Can use JS or CSS animations
#flipanim 5 flipping awesome!
#asdfasdf 1 what the flip is this