So I'm using a modal that has a video player inside it. Everything works fine, except when I go full screen, the video seems to show up behind every other element.
Here's the video within the modal:
And here's the page after making the video full screen:
I went through and changed everything in the modal's css file until I found a version that works. Turns out it's the entering keyframe animation:
#keyframes rodal-fade-enter {
0% {
opacity: 0;
}
}
.rodal-fade-enter {
animation: rodal-fade-enter both ease-in;
}
When I remove this animation, full screen works fine. However, the entering animation looks super choppy. Is there an alternate animation I can use that does the same thing as fading in, but doesn't mess with the full screen video?
I'm not even sure why this animation messes with full screen in the first place, so any explanations are incredibly welcome.
The modal I'm using is https://github.com/chenjiahan/rodal.
Here's a snippet to replicate the issue:
/* =============================== Rodal v1.6.1 https://chenjiahan.github.com/rodal =============================== */
// env
const inBrowser = typeof window !== 'undefined';
const UA = inBrowser && window.navigator.userAgent.toLowerCase();
const isIE9 = UA && UA.indexOf('msie 9.0') > 0;
const Dialog = props => {
const animation = (
props.animationType === 'enter'
? props.enterAnimation
: props.leaveAnimation) || props.animation;
const className = `rodal-dialog rodal-${animation}-${props.animationType}`;
const CloseButton = props.showCloseButton
? <span className="rodal-close" onClick={props.onClose}/>
: null;
const {width, height, measure, duration, customStyles} = props;
const style = {
width: width + measure,
height: height + measure,
animationDuration: duration + 'ms',
WebkitAnimationDuration: duration + 'ms'
};
const mergedStyles = {
...style,
...customStyles
};
return (<div style={mergedStyles} className={className}>
{props.children}
{CloseButton}
</div>)
};
class Rodal extends React.Component {
static defaultProps = {
width: 400,
height: 240,
measure: 'px',
visible: false,
showMask: true,
closeOnEsc: false,
closeMaskOnClick: true,
showCloseButton: true,
animation: 'zoom',
enterAnimation: '',
leaveAnimation: '',
duration: 300,
className: '',
customStyles: {},
customMaskStyles: {}
};
state = {
isShow: false,
animationType: 'leave'
};
componentDidMount() {
if (this.props.visible) {
this.enter();
}
}
componentWillReceiveProps(nextProps) {
if (!this.props.visible && nextProps.visible) {
this.enter();
} else if (this.props.visible && !nextProps.visible) {
this.leave();
}
}
enter() {
this.setState({isShow: true, animationType: 'enter'});
}
leave() {
this.setState(
isIE9
? {
isShow: false
}
: {
animationType: 'leave'
});
}
onKeyUp = event => {
if (this.props.closeOnEsc && event.keyCode === 27) {
this.props.onClose();
}
}
animationEnd = event => {
if (this.state.animationType === 'leave') {
this.setState({isShow: false});
} else if (this.props.closeOnEsc) {
this.el.focus();
}
if (event.target === this.el) {
const {onAnimationEnd} = this.props;
onAnimationEnd && onAnimationEnd();
}
}
render() {
const {props, state} = this;
const onClick = props.closeMaskOnClick
? props.onClose
: null;
const mask = props.showMask
? <div className="rodal-mask" style={props.customMaskStyles} onClick={onClick}/>
: null;
const style = {
display: state.isShow
? ''
: 'none',
animationDuration: props.duration + 'ms',
WebkitAnimationDuration: props.duration + 'ms'
};
return (<div style={style} className={"rodal rodal-fade-" + state.animationType + ' ' + props.className} onAnimationEnd={this.animationEnd} tabIndex="-1" ref={el => {
this.el = el;
}} onKeyUp={this.onKeyUp}>
{mask}
<Dialog {...props} animationType={state.animationType}>
{props.children}
</Dialog>
</div>)
}
}
class Example extends React.Component {
constructor() {
super();
this.state = {
modalIsOpen: false
}
}
openModal = () => {
this.setState({modalIsOpen: true})
}
closeModal = () => {
this.setState({modalIsOpen: false})
}
render() {
return (<div>
<button onClick={this.openModal}>Open modal</button>
<Rodal visible={this.state.modalIsOpen} onClose={this.closeModal} closeOnEsc={true} animation='door'>
<video id='my-video' src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" controls></video>
</Rodal>
</div>);
}
}
ReactDOM.render(<Example/>, document.getElementById('app'));
.rodal,
.rodal-mask {
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
}
.rodal {
position: fixed;
}
/* -- mask -- */
.rodal-mask {
position: absolute;
background: rgba(0, 0, 0, .3);
}
/* -- dialog -- */
.rodal-dialog {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
z-index: 101;
padding: 15px;
background: #fff;
border-radius: 3px;
box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
}
.rodal-dialog:focus {
outline: none;
}
/* -- close button -- */
.rodal-close {
position: absolute;
cursor: pointer;
top: 16px;
right: 16px;
width: 16px;
height: 16px;
}
.rodal-close:before,
.rodal-close:after {
position: absolute;
content: '';
height: 2px;
width: 100%;
top: 50%;
left: 0;
margin-top: -1px;
background: #999;
border-radius: 100%;
-webkit-transition: background .2s;
transition: background .2s;
}
.rodal-close:before {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
.rodal-close:after {
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
}
.rodal-close:hover:before,
.rodal-close:hover:after {
background: #333;
}
/* -- fade -- */
#-webkit-keyframes rodal-fade-enter {
from {
opacity: 0;
}
}
#keyframes rodal-fade-enter {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.rodal-fade-enter {
-webkit-animation: rodal-fade-enter both ease-in;
animation: rodal-fade-enter both ease-in;
}
#-webkit-keyframes rodal-fade-leave {
to {
opacity: 0
}
}
#keyframes rodal-fade-leave {
to {
opacity: 0
}
}
.rodal-fade-leave {
-webkit-animation: rodal-fade-leave both ease-out;
animation: rodal-fade-leave both ease-out;
}
/* -- zoom -- */
#-webkit-keyframes rodal-zoom-enter {
from {
-webkit-transform: scale3d(.3, .3, .3);
transform: scale3d(.3, .3, .3);
}
}
#keyframes rodal-zoom-enter {
from {
-webkit-transform: scale3d(.3, .3, .3);
transform: scale3d(.3, .3, .3);
}
}
.rodal-zoom-enter {
-webkit-animation: rodal-zoom-enter both cubic-bezier(0.4, 0, 0, 1.5);
animation: rodal-zoom-enter both cubic-bezier(0.4, 0, 0, 1.5);
}
#-webkit-keyframes rodal-zoom-leave {
to {
-webkit-transform: scale3d(.3, .3, .3);
transform: scale3d(.3, .3, .3);
}
}
#keyframes rodal-zoom-leave {
to {
-webkit-transform: scale3d(.3, .3, .3);
transform: scale3d(.3, .3, .3);
}
}
.rodal-zoom-leave {
-webkit-animation: rodal-zoom-leave both;
animation: rodal-zoom-leave both;
}
/* -- slideDown -- */
#-webkit-keyframes rodal-slideDown-enter {
from {
-webkit-transform: translate3d(0, -100px, 0);
transform: translate3d(0, -100px, 0);
}
}
#keyframes rodal-slideDown-enter {
from {
-webkit-transform: translate3d(0, -100px, 0);
transform: translate3d(0, -100px, 0);
}
}
.rodal-slideDown-enter {
-webkit-animation: rodal-slideDown-enter both cubic-bezier(0.4, 0, 0, 1.5);
animation: rodal-slideDown-enter both cubic-bezier(0.4, 0, 0, 1.5);
}
#-webkit-keyframes rodal-slideDown-leave {
to {
-webkit-transform: translate3d(0, -100px, 0);
transform: translate3d(0, -100px, 0);
}
}
#keyframes rodal-slideDown-leave {
to {
-webkit-transform: translate3d(0, -100px, 0);
transform: translate3d(0, -100px, 0);
}
}
.rodal-slideDown-leave {
-webkit-animation: rodal-slideDown-leave both;
animation: rodal-slideDown-leave both;
}
/* -- slideLeft -- */
#-webkit-keyframes rodal-slideLeft-enter {
from {
-webkit-transform: translate3d(-150px, 0, 0);
transform: translate3d(-150px, 0, 0);
}
}
#keyframes rodal-slideLeft-enter {
from {
-webkit-transform: translate3d(-150px, 0, 0);
transform: translate3d(-150px, 0, 0);
}
}
.rodal-slideLeft-enter {
-webkit-animation: rodal-slideLeft-enter both cubic-bezier(0.4, 0, 0, 1.5);
animation: rodal-slideLeft-enter both cubic-bezier(0.4, 0, 0, 1.5);
}
#-webkit-keyframes rodal-slideLeft-leave {
to {
-webkit-transform: translate3d(-150px, 0, 0);
transform: translate3d(-150px, 0, 0);
}
}
#keyframes rodal-slideLeft-leave {
to {
-webkit-transform: translate3d(-150px, 0, 0);
transform: translate3d(-150px, 0, 0);
}
}
.rodal-slideLeft-leave {
-webkit-animation: rodal-slideLeft-leave both;
animation: rodal-slideLeft-leave both;
}
/* -- slideRight -- */
#-webkit-keyframes rodal-slideRight-enter {
from {
-webkit-transform: translate3d(150px, 0, 0);
transform: translate3d(150px, 0, 0);
}
}
#keyframes rodal-slideRight-enter {
from {
-webkit-transform: translate3d(150px, 0, 0);
transform: translate3d(150px, 0, 0);
}
}
.rodal-slideRight-enter {
-webkit-animation: rodal-slideRight-enter both cubic-bezier(0.4, 0, 0, 1.5);
animation: rodal-slideRight-enter both cubic-bezier(0.4, 0, 0, 1.5);
}
#-webkit-keyframes rodal-slideRight-leave {
to {
-webkit-transform: translate3d(150px, 0, 0);
transform: translate3d(150px, 0, 0);
}
}
#keyframes rodal-slideRight-leave {
to {
-webkit-transform: translate3d(150px, 0, 0);
transform: translate3d(150px, 0, 0);
}
}
.rodal-slideRight-leave {
-webkit-animation: rodal-slideRight-leave both;
animation: rodal-slideRight-leave both;
}
/* -- slideUp -- */
#-webkit-keyframes rodal-slideUp-enter {
from {
-webkit-transform: translate3d(0, 100px, 0);
transform: translate3d(0, 100px, 0);
}
}
#keyframes rodal-slideUp-enter {
from {
-webkit-transform: translate3d(0, 100px, 0);
transform: translate3d(0, 100px, 0);
}
}
.rodal-slideUp-enter {
-webkit-animation: rodal-slideUp-enter both cubic-bezier(0.4, 0, 0, 1.5);
animation: rodal-slideUp-enter both cubic-bezier(0.4, 0, 0, 1.5);
}
#-webkit-keyframes rodal-slideUp-leave {
to {
-webkit-transform: translate3d(0, 100px, 0);
transform: translate3d(0, 100px, 0);
}
}
#keyframes rodal-slideUp-leave {
to {
-webkit-transform: translate3d(0, 100px, 0);
transform: translate3d(0, 100px, 0);
}
}
.rodal-slideUp-leave {
-webkit-animation: rodal-slideUp-leave both;
animation: rodal-slideUp-leave both;
}
/* -- flip -- */
#-webkit-keyframes rodal-flip-enter {
from {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 60deg);
transform: perspective(400px) rotate3d(1, 0, 0, 60deg);
}
70% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -15deg);
transform: perspective(400px) rotate3d(1, 0, 0, -15deg);
}
to {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
}
#keyframes rodal-flip-enter {
from {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 60deg);
transform: perspective(400px) rotate3d(1, 0, 0, 60deg);
}
70% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -15deg);
transform: perspective(400px) rotate3d(1, 0, 0, -15deg);
}
to {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
}
.rodal-flip-enter {
-webkit-animation: rodal-flip-enter both ease-in;
animation: rodal-flip-enter both ease-in;
-webkit-backface-visibility: visible !important;
backface-visibility: visible !important;
}
#-webkit-keyframes rodal-flip-leave {
from {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
30% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -15deg);
transform: perspective(400px) rotate3d(1, 0, 0, -15deg);
}
to {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 45deg);
transform: perspective(400px) rotate3d(1, 0, 0, 45deg);
}
}
#keyframes rodal-flip-leave {
from {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
30% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -15deg);
transform: perspective(400px) rotate3d(1, 0, 0, -15deg);
}
to {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 45deg);
transform: perspective(400px) rotate3d(1, 0, 0, 45deg);
}
}
.rodal-flip-leave {
-webkit-animation: rodal-flip-leave both;
animation: rodal-flip-leave both;
-webkit-backface-visibility: visible !important;
backface-visibility: visible !important;
}
/* -- rotate -- */
#-webkit-keyframes rodal-rotate-enter {
from {
-webkit-transform: rotate3d(0, 0, 1, -180deg) scale3d(.3, .3, .3);
transform: rotate3d(0, 0, 1, -180deg) scale3d(.3, .3, .3);
}
}
#keyframes rodal-rotate-enter {
from {
-webkit-transform: rotate3d(0, 0, 1, -180deg) scale3d(.3, .3, .3);
transform: rotate3d(0, 0, 1, -180deg) scale3d(.3, .3, .3);
}
}
.rodal-rotate-enter {
-webkit-animation: rodal-rotate-enter both;
animation: rodal-rotate-enter both;
-webkit-transform-origin: center;
transform-origin: center;
}
#-webkit-keyframes rodal-rotate-leave {
to {
-webkit-transform: rotate3d(0, 0, 1, 180deg) scale3d(.3, .3, .3);
transform: rotate3d(0, 0, 1, 180deg) scale3d(.3, .3, .3);
}
}
#keyframes rodal-rotate-leave {
to {
-webkit-transform: rotate3d(0, 0, 1, 180deg) scale3d(.3, .3, .3);
transform: rotate3d(0, 0, 1, 180deg) scale3d(.3, .3, .3);
}
}
.rodal-rotate-leave {
-webkit-animation: rodal-rotate-leave both;
animation: rodal-rotate-leave both;
-webkit-transform-origin: center;
transform-origin: center;
}
/* -- door -- */
#-webkit-keyframes rodal-door-enter {
from {
-webkit-transform: scale3d(0, 1, 1);
transform: scale3d(0, 1, 1);
}
}
#keyframes rodal-door-enter {
from {
-webkit-transform: scale3d(0, 1, 1);
transform: scale3d(0, 1, 1);
}
}
.rodal-door-enter {
-webkit-animation: rodal-door-enter both cubic-bezier(0.4, 0, 0, 1.5);
animation: rodal-door-enter both cubic-bezier(0.4, 0, 0, 1.5);
}
#-webkit-keyframes rodal-door-leave {
60% {
-webkit-transform: scale3d(.01, 1, 1);
transform: scale3d(.01, 1, 1);
}
to {
-webkit-transform: scale3d(0, 1, .1);
transform: scale3d(0, 1, .1);
}
}
#keyframes rodal-door-leave {
60% {
-webkit-transform: scale3d(.01, 1, 1);
transform: scale3d(.01, 1, 1);
}
to {
-webkit-transform: scale3d(0, 1, .1);
transform: scale3d(0, 1, .1);
}
}
.rodal-door-leave {
-webkit-animation: rodal-door-leave both;
animation: rodal-door-leave both;
}
#my-video {
width: 100%;
height: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'></div>
Related
I have an animation which makes text change by sliding vertically (similar to the one on groupebouchersports.com's homepage). The problem is, I want the text to stop longer (delay) before sliding out, but I cant seem to find how to do it. Here is my html / css / javascript code. Thanks in advance.
document.addEventListener('DOMContentLoaded', initTextAnimSlider);
function initTextAnimSlider() {
var textAnimHolder = document.querySelector('[data-words]');
var textAnimItem = document.querySelectorAll('.text-anim-item');
var textAnimItems = document.querySelector('.text-anim-items');
var animIn = 'anim-in';
var animOut = 'anim-out';
var lineActiveClass = 'line-active';
var animNextItem = null;
var animPrevItem = null;
var animFirstLoad = false;
var animDuration = textAnimHolder.getAttribute('data-delay');
var animCounter = 0;
var setTimeAnim;
var setTimeAnimResize;
animFunc();
getHolderWidth();
function animFunc() {
clearTimeout(setTimeAnim);
setTimeAnim = setTimeout(function () {
animFirstLoad = true;
if (animPrevItem !== null) {
animPrevItem.classList.add(animOut);
}
animNextItem = textAnimItems.children[animCounter];
animNextItem.classList.remove(animOut);
animNextItem.classList.add(animIn);
animPrevItem = animNextItem;
if (animCounter === textAnimItem.length - 1) {
animCounter = 0;
} else {
animCounter++;
}
animFunc();
}, animFirstLoad ? animDuration : 100);
}
function getHolderWidth() {
var itemsWidth = [];
for(var i =0; i < textAnimItem.length; i++) {
itemsWidth.push(textAnimItem[i].clientWidth);
console.log(textAnimItem[i].clientWidth);
}
textAnimHolder.style.width = '450px';
}
function resizeHandler() {
clearTimeout(setTimeAnim);
clearTimeout(setTimeAnimResize);
getHolderWidth();
setTimeAnimResize = setTimeout(function() {
animFunc();
}, 50);
}
window.addEventListener('resize', resizeHandler);
window.addEventListener('orientationchange', resizeHandler);
}
.text-anim-item {
white-space: nowrap;
position: absolute;
left: 0;
right:auto;
bottom: 0;
-webkit-transform: translate3d(0, -120%, 0);
transform: translate3d(0, -120%, 0);
}
.text-anim-item.anim-in {
-webkit-transform: translate3d(0, -120%, 0);
transform: translate3d(0, -120%, 0);
-webkit-animation: textAnimIn .6s .3s forwards;
animation: textAnimIn .6s .3s forwards;
}
.text-anim-item.anim-out {
-webkit-transform: translate3d(0, 0%, 0);
transform: translate3d(0, 0%, 0);
-webkit-animation: textAnimOut .6s .3s forwards;
animation: textAnimOut .6s .3s forwards;
}
#-webkit-keyframes textAnimIn {
0% {
-webkit-transform: translate3d(0, -120%, 0);
transform: translate3d(0, -120%, 0);
}
100% {
-webkit-transform: translate3d(0, 0%, 0);
transform: translate3d(0, 0%, 0);
}
}
#keyframes textAnimIn {
0% {
-webkit-transform: translate3d(0, -120%, 0);
transform: translate3d(0, -120%, 0);
}
100% {
-webkit-transform: translate3d(0, 0%, 0);
transform: translate3d(0, 0%, 0);
}
}
#-webkit-keyframes textAnimOut {
0% {
-webkit-transform: translate3d(0, 0%, 0);
transform: translate3d(0, 0%, 0);
}
100% {
-webkit-transform: translate3d(0, 120%, 0);
transform: translate3d(0, 120%, 0);
}
}
#keyframes textAnimOut {
0% {
-webkit-transform: translate3d(0, 0%, 0);
transform: translate3d(0, 0%, 0);
}
100% {
-webkit-transform: translate3d(0, 120%, 0);
transform: translate3d(0, 120%, 0);
}
}
#-webkit-keyframes textAnimInCenter {
0% {
-webkit-transform: translate3d(-50%, -120%, 0);
transform: translate3d(-50%, -120%, 0);
}
100% {
-webkit-transform: translate3d(-50%, 10%, 0);
transform: translate3d(-50%, 10%, 0);
}
}
#keyframes textAnimInCenter {
0% {
-webkit-transform: translate3d(-50%, -120%, 0);
transform: translate3d(-50%, -120%, 0);
}
100% {
-webkit-transform: translate3d(-50%, 10%, 0);
transform: translate3d(-50%, 10%, 0);
}
}
#-webkit-keyframes textAnimOutCenter {
0% {
-webkit-transform: translate3d(-50%, 0%, 0);
transform: translate3d(-50%, 0%, 0);
}
100% {
-webkit-transform: translate3d(-50%, 120%, 0);
transform: translate3d(-50%, 120%, 0);
}
}
#keyframes textAnimOutCenter {
0% {
-webkit-transform: translate3d(-50%, 0%, 0);
transform: translate3d(-50%, 0%, 0);
}
100% {
-webkit-transform: translate3d(-50%, 120%, 0);
transform: translate3d(-50%, 120%, 0);
}
}
<section class="bg-img intro-module">
<div class="block-center">
<div class="block-caption py-4 text-center text-md-left">
<h1 style="text-align:left;" class="display-1 mb-0">
<u class="mb-0" data-delay="1200" data-words>
<span style="text-align:left;" class="text-anim-items">
<span class="text-anim-item"><span>text</span></span>
<span class="text-anim-item"><span>text 2</span></span>
<span class="text-anim-item"><span>text 3</span></span>
</span>
<span class="anim-line"></span>
</u>
<br>
<span>lorem</span>
<br>
<span>ipsum</span>
<br>
<br>
<span><p>caption text</p></span>
</h1>
</div>
</div>
</section>
Adding a snippet to explain what I was referring to in the comments. The block id is only to have something for the text to hide behind as I think your intention is to have them scroll off screen.
span {
position: absolute;
left: 0;
right:auto;
top: 0;
font-size: 15pt;
}
#block {
position:absolute;
top: 100px;
left:0;
width: 300px;
height: 300px;
background: white;
}
#one {
animation: move 6s linear infinite;
color: red;
}
#two {
animation: move 6s linear -2s infinite;
color: blue;
}
#three {
animation: move 6s linear -4s infinite;
color: green;
}
#keyframes move {
0% {transform: translate(0, 0)}
33% {transform: translate(0, 0)}
66% {transform: translate(0, 200px)}
100% {transform: translate(0, 200px)}
}
<span id="one">Hello World</span>
<span id="two">World Hello</span>
<span id="three">No No No</span>
<div id="block"></div>
I use a script in which elements fade in from the left and right as soon as the respective element has been scrolled completely into view. The problem is, the fade-in remains until the element has completely disappeared from the field of view. I try to implement it in such a way that it fades out as soon as it is no longer completely in sight. Otherwise, all elements are shown at the same time when scrolling.
function Utils() {}
Utils.prototype = {
constructor: Utils,
isElementInView: function(element, fullyInView) {
var pageTop = $(window).scrollTop();
var pageBottom = pageTop + $(window).height();
var elementTop = $(element).offset().top;
var elementBottom = elementTop + $(element).height();
if (fullyInView === true) {
return ((pageTop < elementTop) && (pageBottom > elementBottom));
} else {
return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
}
}
};
var Utils = new Utils();
$(window).on('load', addFadeIn());
$(window).scroll(function() {
addFadeIn(true);
});
function addFadeIn(repeat) {
var classToFadeIn = ".will-fadeIn";
$(classToFadeIn).each(function(index) {
var isElementInView = Utils.isElementInView($(this), false);
if (isElementInView) {
if (!($(this).hasClass('fadeInRight')) && !($(this).hasClass('fadeInLeft'))) {
if (index % 2 == 0) $(this).addClass('fadeInRight');
else $(this).addClass('fadeInLeft');
}
} else if (repeat) {
$(this).removeClass('fadeInRight');
$(this).removeClass('fadeInLeft');
}
});
}
#locations-mobile {
height: auto;
display: block;
}
#loc1, #loc2, #loc3, #loc4 {
height: 300px;
background-size: cover;
}
.locimg {
width: 100%;
background-size: cover;
background-repeat: no-repeat;
}
.loc {
cursor: pointer;
height: 100%;
width: 100%;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
position: relative;
overflow: hidden;
text-align: center;
}
.loc .fadedbox, .loc-selected {
background-color: #202020;
position: absolute;
top: 0;
left: 0;
color: #fff;
-webkit-transition: all 300ms ease-out;
-moz-transition: all 300ms ease-out;
-o-transition: all 300ms ease-out;
-ms-transition: all 300ms ease-out;
transition: all 300ms ease-out;
opacity: 0;
width: 100%;
height: 100%;
}
.loc:hover .fadedbox, .loc-selected {
opacity: 0.8;
}
.loc .text, .loc .text a, .will-fadeIn .text, .will-fadeIn .text p, .will-fadeIn .text p a {
top: 0%;
left: 0%;
position: relative;
text-align: center;
color: #fff;
text-decoration: none;
-webkit-transition: all 300ms ease-out;
-moz-transition: all 300ms ease-out;
-o-transition: all 300ms ease-out;
-ms-transition: all 300ms ease-out;
transition: all 300ms ease-out;
transform: translateY(50px);
-webkit-transform: translateY(50px);
}
.loc .text, .loc .text a, .will-fadeIn .text, .will-fadeIn .text p, .will-fadeIn .text p a {
transform: translateY(30px);
-webkit-transform: translateY(30px);
}
.loc .title {
font-size: 2.5em;
text-align: center;
text-transform: uppercase;
opacity: 0;
transition-delay: 0.2s;
transition-duration: 0.3s;
}
.will-fadeIn .text .title a {
color: #fff;
font-size: 2.5em;
}
#loc1 {
grid-area: 1 / 1 / 2 / 2;
background-image: url(https://images.pexels.com/photos/380769/pexels-photo-380769.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260)
}
#loc2 {
grid-area: 1 / 2 / 2 / 3;
background-image: url(https://images.pexels.com/photos/380769/pexels-photo-380769.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260)
}
#loc3 {
grid-area: 1 / 3 / 2 / 4;
background-image: url(https://images.pexels.com/photos/380769/pexels-photo-380769.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260)
}
#loc4 {
grid-area: 1 / 4 / 2 / 5;
background-image: url(https://images.pexels.com/photos/380769/pexels-photo-380769.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260)
}
.doing {
transform: rotate(-35deg);
display: block;
position: absolute;
top: 0;
left: -90px;
margin-top: 25px;
text-align: center;
width: 300px;
color: #fff;
}
.will-fadeIn {
display: block;
width: 100%;
max-width: 640px;
margin: 0px auto;
height: 100%;
background-color: #202020;
}
.fadeInRight {
-webkit-animation: fadeInRight .5s ease .4s both;
-moz-animation: fadeInRight .5s ease .4s both;
-ms-animation: fadeInRight .5s ease .4s both;
-o-animation: fadeInRight .5s ease .4s both;
animation: fadeInRight .5s ease .4s both;
}
#media (prefers-reduced-motion) {
.fadeInRight .animated {
-webkit-animation: unset !important;
animation: unset !important;
-webkit-transition: none !important;
transition: none !important;
}
}
.fadeInLeft {
-webkit-animation: fadeInLeft .5s ease .4s both;
-moz-animation: fadeInLeft .5s ease .4s both;
-ms-animation: fadeInLeft .5s ease .4s both;
-o-animation: fadeInLeft .5s ease .4s both;
animation: fadeInLeft .5s ease .4s both;
}
#media (prefers-reduced-motion) {
.fadeInLeft .animated {
-webkit-animation: unset !important;
animation: unset !important;
-webkit-transition: none !important;
transition: none !important;
}
}
#-webkit-keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(100%, 0, 0);
-moz-transform: translate3d(100%, 0, 0);
-ms-transform: translate3d(100%, 0, 0);
-o-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-moz-keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(100%, 0, 0);
-moz-transform: translate3d(100%, 0, 0);
-ms-transform: translate3d(100%, 0, 0);
-o-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-ms-keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(100%, 0, 0);
-moz-transform: translate3d(100%, 0, 0);
-ms-transform: translate3d(100%, 0, 0);
-o-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-o-keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(100%, 0, 0);
-moz-transform: translate3d(100%, 0, 0);
-ms-transform: translate3d(100%, 0, 0);
-o-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(100%, 0, 0);
-moz-transform: translate3d(100%, 0, 0);
-ms-transform: translate3d(100%, 0, 0);
-o-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-webkit-keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
-ms-transform: translate3d(-100%, 0, 0);
-o-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-moz-keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
-ms-transform: translate3d(-100%, 0, 0);
-o-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-ms-keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
-ms-transform: translate3d(-100%, 0, 0);
-o-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-o-keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
-ms-transform: translate3d(-100%, 0, 0);
-o-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
-ms-transform: translate3d(-100%, 0, 0);
-o-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section id="locations-mobile">
<div id="loc1">
<div class="fadedbox will-fadeIn">
<div class="text">
<p class="title">#</p>
<p>
<a href="#" target="_blank">
<i class="fas fa-map-marker-alt"></i>#<br /> #
</a>
</p>
<p><i class="fas fa-phone"></i>#</p>
</div>
</div>
</div>
<div id="loc2">
<div class="fadedbox will-fadeIn">
<div class="text">
<p class="title">#</p>
<p>
<a href="#" target="_blank">
<i class="fas fa-map-marker-alt"></i>#<br /> #
</a>
</p>
<p><i class="fas fa-phone"></i>#</p>
</div>
</div>
</div>
<div id="loc3">
<div class="fadedbox will-fadeIn">
<div class="text">
<p class="title">#</p>
<p>
<a href="#" target="_blank">
<i class="fas fa-map-marker-alt"></i>#<br /> #
</a>
</p>
<p><i class="fas fa-phone"></i>#</p>
</div>
</div>
</div>
<div id="loc4">
<div class="fadedbox will-fadeIn">
<div class="text">
<p class="title">#</p>
<p>
<a href="#" target="_blank">
<i class="fas fa-map-marker-alt"></i>#<br /> #
</a>
</p>
<p><i class="fas fa-phone"></i>#</p>
</div>
</div>
</div>
</section>
Use the deltaY attribute in the wheel event to detect scrolling up vs down.
window.onwheel = function(event) {
let div = document.querySelector('div');
let opacity = getComputedStyle(div).opacity;
(event.deltaY <= 0) ? (div.style.opacity = +opacity-0.1) : (div.style.opacity = +opacity+0.1);
document.querySelector('p').innerHTML = 'deltaY: ' + event.deltaY;
};
div {
position: absolute;
top: 50%;
left: 50%;
height: 10em;
width: 10em;
transform: translate(-50%,-50%);
border-radius: 50%;
background: black;
transition: opacity 0.2s;
}
<div></div>
<p>deltaY: 0</p>
To try the example above, enter the full page mode for the snippet. Otherwise it will work, but still scroll on the page causing a not ideal effect. Scroll up for a higher opacity and scroll down for a lower opacity.
You can use Animate On Scroll Library
Its easy to use and its more efficient, hope this helped you
I've updated your code, will need some major cleanup but it demonstrates the solution: (i've changed the #loc containers height to 150px to make my solution reproducable in the small 'run code' preview here)
function Utils() {}
Utils.prototype = {
constructor: Utils,
isElementInView: function(element, fullyInView) {
var pageTop = $(window).scrollTop();
var pageBottom = pageTop + $(window).height();
var elementTop = $(element).offset().top;
var elementBottom = elementTop + $(element).height();
if (fullyInView === true) {
return ((pageTop < elementTop) && (pageBottom > elementBottom));
} else {
return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
}
}
};
var Utils = new Utils();
$(window).on('load', addFadeIn());
$(window).scroll(function() {
addFadeIn(true);
});
function addFadeIn(repeat) {
var classToFadeIn = ".will-fadeIn";
$(classToFadeIn).each(function(index) {
var isElementInView = Utils.isElementInView($(this), true);
if (isElementInView) {
if (!($(this).hasClass('fadeInRight')) && !($(this).hasClass('fadeInLeft'))) {
if (index % 2 == 0) $(this).addClass('fadeInRight');
else $(this).addClass('fadeInLeft');
}
} else if (repeat) {
$(this).removeClass('fadeInRight');
$(this).removeClass('fadeInLeft');
}
});
}
#locations-mobile {
height: auto;
display: block;
}
#loc1, #loc2, #loc3, #loc4 {
height: 150px;
background-size: cover;
}
.locimg {
width: 100%;
background-size: cover;
background-repeat: no-repeat;
}
.loc {
cursor: pointer;
height: 100%;
width: 100%;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
position: relative;
overflow: hidden;
text-align: center;
}
.fadedbox{
transition:all 1s;
transform:translateX(-100%);
}
#locations-mobile>div:nth-child(even)>.fadedbox{
transform:translateX(100%);
}
.loc .fadedbox, .loc-selected {
background-color: #202020;
position: absolute;
top: 0;
left: 0;
color: #fff;
-webkit-transition: all 300ms ease-out;
-moz-transition: all 300ms ease-out;
-o-transition: all 300ms ease-out;
-ms-transition: all 300ms ease-out;
transition: all 300ms ease-out;
opacity: 0;
width: 100%;
height: 100%;
}
.loc:hover .fadedbox, .loc-selected {
opacity: 0.8;
}
.loc .text, .loc .text a, .will-fadeIn .text, .will-fadeIn .text p, .will-fadeIn .text p a {
top: 0%;
left: 0%;
position: relative;
text-align: center;
color: #fff;
text-decoration: none;
-webkit-transition: all 300ms ease-out;
-moz-transition: all 300ms ease-out;
-o-transition: all 300ms ease-out;
-ms-transition: all 300ms ease-out;
transition: all 300ms ease-out;
transform: translateY(50px);
-webkit-transform: translateY(50px);
}
.loc .text, .loc .text a, .will-fadeIn .text, .will-fadeIn .text p, .will-fadeIn .text p a {
transform: translateY(30px);
-webkit-transform: translateY(30px);
}
.loc .title {
font-size: 2.5em;
text-align: center;
text-transform: uppercase;
opacity: 0;
transition-delay: 0.2s;
transition-duration: 0.3s;
}
.will-fadeIn .text .title a {
color: #fff;
font-size: 2.5em;
}
#loc1 {
grid-area: 1 / 1 / 2 / 2;
background-image: url(https://images.pexels.com/photos/380769/pexels-photo-380769.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260)
}
#loc2 {
grid-area: 1 / 2 / 2 / 3;
background-image: url(https://images.pexels.com/photos/380769/pexels-photo-380769.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260)
}
#loc3 {
grid-area: 1 / 3 / 2 / 4;
background-image: url(https://images.pexels.com/photos/380769/pexels-photo-380769.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260)
}
#loc4 {
grid-area: 1 / 4 / 2 / 5;
background-image: url(https://images.pexels.com/photos/380769/pexels-photo-380769.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260)
}
.doing {
transform: rotate(-35deg);
display: block;
position: absolute;
top: 0;
left: -90px;
margin-top: 25px;
text-align: center;
width: 300px;
color: #fff;
}
.will-fadeIn {
display: block;
width: 100%;
max-width: 640px;
margin: 0px auto;
height: 100%;
background-color: #202020;
}
.old_fadeInRight {
-webkit-animation: fadeInRight .5s ease .4s both;
-moz-animation: fadeInRight .5s ease .4s both;
-ms-animation: fadeInRight .5s ease .4s both;
-o-animation: fadeInRight .5s ease .4s both;
animation: fadeInRight .5s ease .4s both;
}
.fadeInRight{
transform:translateX(0) !important;
}
#media (prefers-reduced-motion) {
.fadeInRight .animated {
-webkit-animation: unset !important;
animation: unset !important;
-webkit-transition: none !important;
transition: none !important;
}
}
.old_fadeInLeft {
-webkit-animation: fadeInLeft .5s ease .4s both;
-moz-animation: fadeInLeft .5s ease .4s both;
-ms-animation: fadeInLeft .5s ease .4s both;
-o-animation: fadeInLeft .5s ease .4s both;
animation: fadeInLeft .5s ease .4s both;
}
.fadeInLeft{
transform:translateX(0) !important;
}
#media (prefers-reduced-motion) {
.fadeInLeft .animated {
-webkit-animation: unset !important;
animation: unset !important;
-webkit-transition: none !important;
transition: none !important;
}
}
#-webkit-keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(100%, 0, 0);
-moz-transform: translate3d(100%, 0, 0);
-ms-transform: translate3d(100%, 0, 0);
-o-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-moz-keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(100%, 0, 0);
-moz-transform: translate3d(100%, 0, 0);
-ms-transform: translate3d(100%, 0, 0);
-o-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-ms-keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(100%, 0, 0);
-moz-transform: translate3d(100%, 0, 0);
-ms-transform: translate3d(100%, 0, 0);
-o-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-o-keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(100%, 0, 0);
-moz-transform: translate3d(100%, 0, 0);
-ms-transform: translate3d(100%, 0, 0);
-o-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(100%, 0, 0);
-moz-transform: translate3d(100%, 0, 0);
-ms-transform: translate3d(100%, 0, 0);
-o-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-webkit-keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
-ms-transform: translate3d(-100%, 0, 0);
-o-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-moz-keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
-ms-transform: translate3d(-100%, 0, 0);
-o-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-ms-keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
-ms-transform: translate3d(-100%, 0, 0);
-o-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-o-keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
-ms-transform: translate3d(-100%, 0, 0);
-o-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
-ms-transform: translate3d(-100%, 0, 0);
-o-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
to {
opacity: .8;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section id="locations-mobile">
<div id="loc1">
<div class="fadedbox will-fadeIn">
<div class="text">
<p class="title">#</p>
<p>
<a href="#" target="_blank">
<i class="fas fa-map-marker-alt"></i>#<br /> #
</a>
</p>
<p><i class="fas fa-phone"></i>#</p>
</div>
</div>
</div>
<div id="loc2">
<div class="fadedbox will-fadeIn">
<div class="text">
<p class="title">#</p>
<p>
<a href="#" target="_blank">
<i class="fas fa-map-marker-alt"></i>#<br /> #
</a>
</p>
<p><i class="fas fa-phone"></i>#</p>
</div>
</div>
</div>
<div id="loc3">
<div class="fadedbox will-fadeIn">
<div class="text">
<p class="title">#</p>
<p>
<a href="#" target="_blank">
<i class="fas fa-map-marker-alt"></i>#<br /> #
</a>
</p>
<p><i class="fas fa-phone"></i>#</p>
</div>
</div>
</div>
<div id="loc4">
<div class="fadedbox will-fadeIn">
<div class="text">
<p class="title">#</p>
<p>
<a href="#" target="_blank">
<i class="fas fa-map-marker-alt"></i>#<br /> #
</a>
</p>
<p><i class="fas fa-phone"></i>#</p>
</div>
</div>
</div>
</section>
Most relevant change is switching from css animations to css transitions, making it easier to fade elements in once the are fully in view, and out once they leave.
Come back to me in case you need further explanation here.
I was trying to make a "bounce-in" effect where the circle isn't there before the animation, then the animation is executed on scroll, and the circle remains there after the animation is over. But for some reason it's there even before the animation, then disappears (since first frame opacity is 0) then appears again. I'm not sure what I'm doing wrong.
if (browser.canUse('transition')) {
var on = function() {
// Circles
$('.circle')
.scrollex({
mode: 'bottom',
delay: 50,
initialize: function() {
$(this).addClass('bounceIn');
},
terminate: function() {
$(this).removeClass('bounceIn');
},
enter: function() {
$(this).removeClass('bounceIn');
},
leave: function() {
$(this).addClass('bounceIn');
}
});
.circle {
position: absolute;
border-radius: 50%;
}
.circle.circle1 {
top: 80px;
left: 120px;
width: 100px;
height: 100px;
background: white;
opacity: 0;
}
/* ----------- BOUNCE IN ------------*/
#-webkit-keyframes bounceIn {
from,
20%,
40%,
60%,
80%,
to {
-webkit-animation-timing-function: cubic-bezier(0.315, 0.71, 0.455, 1);
animation-timing-function: cubic-bezier(0.315, 0.71, 0.455, 1);
}
0% {
opacity: 0;
-webkit-transform: scale(0.3);
transform: scale(0.3);
}
20% {
-webkit-transform: scale(1.03);
transform: scale(1.03);
}
40% {
-webkit-transform: scale(0.9);
transform: scale(0.9);
}
60% {
opacity: 1;
-webkit-transform: scale(1.03);
transform: scale(1.03);
}
80% {
-webkit-transform: scale(0.97);
transform: scale(0.97);
}
to {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
}
#keyframes bounceIn {
from,
20%,
40%,
60%,
80%,
to {
-webkit-animation-timing-function: cubic-bezier(0.315, 0.71, 0.455, 1);
animation-timing-function: cubic-bezier(0.315, 0.71, 0.455, 1);
}
0% {
opacity: 0;
-webkit-transform: scale(0.3);
transform: scale(0.3);
}
20% {
-webkit-transform: scale(1.03);
transform: scale(1.03);
}
40% {
-webkit-transform: scale(0.9);
transform: scale(0.9);
}
60% {
opacity: 1;
-webkit-transform: scale(1.03);
transform: scale(1.03);
}
80% {
-webkit-transform: scale(0.97);
transform: scale(0.97);
}
to {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
}
.bounceIn {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-name: bounceIn;
animation-name: bounceIn;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
<div class="circle circle1"></div>
I went through dozens of questions here, but nothing answers my problem.
Basically I want to have the same feature as on this website: http://madebyheart.co.uk/work/thrively/ - when you load the page the [X] and MENU buttons slide from top, and when you click [X] to close the page they slide back up...
I tried looking at their code but it gives me headache.
I assume that's done with CSS + JS, but I have no clue where to start.
Check this out.
#-webkit-keyframes fadeInDown {
from {
opacity: 0;
-webkit-transform: translate3d(0, -100%, 0);
transform: translate3d(0, -100%, 0);
}
to {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#keyframes fadeInDown {
from {
opacity: 0;
-webkit-transform: translate3d(0, -100%, 0);
transform: translate3d(0, -100%, 0);
}
to {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-webkit-keyframes fadeInUp {
from {
opacity: 0;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
to {
opacity: 1;
-webkit-transform: translate3d(0, -200%, 0);
transform: translate3d(0, -200%, 0);
}
}
#keyframes fadeInUp {
from {
opacity: 0;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
to {
opacity: 1;
-webkit-transform: translate3d(0, -200%, 0);
transform: translate3d(0, -200%, 0);
}
}
.fadeInUp {
-webkit-animation-name: fadeInUp;
animation-name: fadeInUp;
}
.fadeInDown {
-webkit-animation-name: fadeInDown;
animation-name: fadeInDown;
}
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.site__title.mega {
text-align: center;
font-size: 60px;
}
.ji:hover {
cursor: pointer;
}
.ji {
padding: 2px 14px;
border: 1px solid black;
}
<html>
<head>
<title>Bootstrap</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="setest_style.css">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$(".ji").click(function(){
$("#animationSandbox").removeClass("fadeInDown");
$("#animationSandbox").addClass("fadeInUp");
});
});
</script>
</head>
<body>
<span id="animationSandbox" style="display: block;" class="fadeInDown animated">
<h1 class="site__title mega"><span class="ji">X</span></h1>
</span>
</body>
</html>
EDIT:
For achieving fadein animation with display:inline-block; , you have to use fadein classes in inner divs as shown below.
#-webkit-keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(200%, 0, 0);
transform: translate3d(200%, 0, 0);
}
to {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#keyframes fadeInLeft {
from {
opacity: 0;
-webkit-transform: translate3d(200%, 0, 0);
transform: translate3d(200%, 0, 0);
}
to {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-webkit-keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
to {
opacity: 1;
-webkit-transform: translate3d(200%, 0, 0);
transform: translate3d(200%, 0, 0);
}
}
#keyframes fadeInRight {
from {
opacity: 0;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
to {
opacity: 1;
-webkit-transform: translate3d(-200%, 0, 0);
transform: translate3d(-200%, 0, 0);
}
}
.fadeInLeft {
-webkit-animation-name: fadeInLeft;
animation-name: fadeInLeft;
}
.fadeInRight {
-webkit-animation-name: fadeInRight;
animation-name: fadeInRight;
}
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
body {
background: #f9f9f9;
margin: 0;
}
a {
text-decoration:underline;
color:#000;
position: relative;
}
/* ABOUT + CONTACT */
.hlinks {
writing-mode: vertical-rl;
position: fixed;
right: 10%;
top: 15px;
display: inline;
color: #000;
font-size: 13px;
}
.hlinks2 {
writing-mode: vertical-rl;
position: fixed;
right: 10%;
top: 100px;
display: inline;
color: #000;
font-size: 13px;
}
<span style="display: inline-block;" >
<div id="animationSandbox" class="hlinks fadeInLeft animated">
<span>
ABOUT —
CONTACT
</span>
</div>
</span>
animate.css is good library , Should meet your needs
DEMO:
https://daneden.github.io/animate.css/
I'm just making a loading screen using CSS and I want it to have physically accurate behavior. I'm trying with the animation-timing-function: cubic-bezier(1, 0, 1, 1), looks fine but not as real like I want, at first because I don't know how do cubic-bezier parameters really work, I found this site and just played around with them until I got something nice.
To sum up, how can I add physically accurate behavior to my animation?
I am looking for a CSS-only solution, but JavaScript is fine too if it's impossible.
Here you have an example:
body{
background-color: #02a2bb;
}
.wrapper {
padding: 50px;
text-align: center;
}
.content {
height: 125px;
margin: 0 auto;
position: relative;
display: inline-block;
}
.ball {
width: 25px;
height: 25px;
display: inline-block;
border-radius: 50%;
bottom: 0;
position: relative;
background-color: #fff;
z-index: 1;
}
.ball-shadow {
width: 20px;
height: 6px;
border-radius: 50%;
position: absolute;
bottom: 9px;
left: 50%;
-webkit-transform: translateX(-50%);
-moz-transform: translateX(-50%);
transform: translateX(-50%);
}
.animated {
-webkit-animation-duration: 1s;
-moz-animation-duration: 1s;
-ms-animation-duration: 1s;
-o-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
-moz-animation-fill-mode: both;
-ms-animation-fill-mode: both;
-o-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-iteration-count: infinite;
-moz-animation-iteration-count: infinite;
-ms-animation-iteration-count: infinite;
-o-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
.animated.jump, .animated.displace, .animated.diffuse-scale {
-webkit-animation-duration: 3s;
-moz-animation-duration: 3s;
-ms-animation-duration: 3s;
-o-animation-duration: 3s;
animation-duration: 3s;
}
#-webkit-keyframes jump {
0% {
opacity: 1;
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: translate(0, 0);
}
15% {
opacity: 1;
-webkit-transform: translate(0, 100px) scale(1.1, 0.9);
}
30% {
opacity: 1;
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: translate(0, 15px);
}
45% {
opacity: 1;
-webkit-transform: translate(0, 100px) scale(1.08, 0.92);
}
60% {
opacity: 1;
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: translate(0, 45px);
}
70% {
opacity: 1;
-webkit-transform: translate(0, 100px) scale(1.05, 0.95);
}
80% {
opacity: 1;
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: translate(0, 65px);
}
85% {
opacity: 1;
-webkit-transform: translate(0, 100px) scale(1.03, 0.97);
}
90% {
opacity: 1;
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: translate(0, 80px);
}
95% {
opacity: 1;
-webkit-transform: translate(0, 100px) scale(1.01, 0.99);
}
97% {
opacity: 1;
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: translate(0, 95px);
}
100% {
opacity: 0;
-webkit-transform: translate(0, 100px);
}
}
#keyframes jump {
0% {
opacity: 1;
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: translate(0, 0);
transform: translate(0, 0);
}
15% {
opacity: 1;
-moz-transform: translate(0, 100px) scale(1.1, 0.9);
transform: translate(0, 100px) scale(1.1, 0.9);
}
30% {
opacity: 1;
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: translate(0, 15px);
transform: translate(0, 15px);
}
45% {
opacity: 1;
-moz-transform: translate(0, 100px)scale(1.08, 0.92);
transform: translate(0, 100px)scale(1.08, 0.92);
}
60% {
opacity: 1;
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: translate(0, 45px);
transform: translate(0, 45px);
}
70% {
opacity: 1;
-moz-transform: translate(0, 100px)scale(1.05, 0.95);
transform: translate(0, 100px)scale(1.05, 0.95);
}
80% {
opacity: 1;
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: translate(0, 65px);
transform: translate(0, 65px);
}
85% {
opacity: 1;
-moz-transform: translate(0, 100px) scale(1.03, 0.97);
transform: translate(0, 100px) scale(1.03, 0.97);
}
90% {
opacity: 1;
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: translate(0, 80px);
transform: translate(0, 80px);
}
95% {
opacity: 1;
-moz-transform: translate(0, 100px) scale(1.01, 0.99);
transform: translate(0, 100px) scale(1.01, 0.99);
}
97% {
opacity: 1;
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: translate(0, 95px);
transform: translate(0, 95px);
}
100% {
opacity: 0;
-moz-transform: translate(0, 100px);
transform: translate(0, 100px);
}
}
#-webkit-keyframes diffuse-scale {
0% {
box-shadow: 0 14px 8px rgba(0, 0, 0, 0.5);
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: scale(1.5, 1) translateX(-50%);
}
15% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-webkit-transform: scale(1, 1) translateX(-50%);
}
30% {
box-shadow: 0 14px 7px rgba(0, 0, 0, 0.5);
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: scale(1.4, 1) translateX(-50%);
}
45% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-webkit-transform: scale(1, 1) translateX(-50%); }
60% {
box-shadow: 0 14px 5px rgba(0, 0, 0, 0.5);
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: scale(1.3, 1) translateX(-50%); }
70% {
box-shadow: 0 14 2px rgba(0, 0, 0, 0.5);
-webkit-transform: scale(1, 1) translateX(-50%);
}
80% {
box-shadow: 0 14px 4px rgba(0, 0, 0, 0.5);
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: scale(1.2, 1) translateX(-50%);
}
85% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-webkit-transform: scale(1, 1) translateX(-50%);
}
90% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: scale(1.1, 1) translateX(-50%);
}
95% {
box-shadow: 0 14px 3px rgba(0, 0, 0, 0.5);
-webkit-transform: scale(1, 1) translateX(-50%);
}
97% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 1);
-webkit-transform: scale(1.05, 1) translateX(-50%);
}
100% {
-webkit-transform: scale(1, 1) translateX(-50%);
}
}
#keyframes diffuse-scale {
0% {
box-shadow: 0 14px 8px rgba(0, 0, 0, 0.5);
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: scale(1.5, 1) translateX(-50%);
transform: scale(1.5, 1) translateX(-50%);
}
15% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-moz-transform: scale(1, 1) translateX(-50%);
transform: scale(1, 1) translateX(-50%);
}
30% {
box-shadow: 0 14px 7px rgba(0, 0, 0, 0.5);
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: scale(1.4, 1) translateX(-50%);
transform: scale(1.4, 1) translateX(-50%);
}
45% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-moz-transform: scale(1, 1) translateX(-50%);
transform: scale(1, 1) translateX(-50%);
}
60% {
box-shadow: 0 14px 5px rgba(0, 0, 0, 0.5);
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: scale(1.3, 1) translateX(-50%);
transform: scale(1.3, 1) translateX(-50%);
}
70% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-moz-transform: scale(1, 1) translateX(-50%);
transform: scale(1, 1) translateX(-50%);
}
80% {
box-shadow: 0 14px 4px rgba(0, 0, 0, 0.5);
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: scale(1.2, 1) translateX(-50%);
transform: scale(1.2, 1) translateX(-50%);
}
85% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-webkit-transform: scale(1, 1) translateX(-50%);
-moz-transform: scale(1, 1) translateX(-50%);
transform: scale(1, 1) translateX(-50%);
}
90% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: scale(1.1, 1) translateX(-50%);
transform: scale(1.1, 1) translateX(-50%);
}
95% {
box-shadow: 0 14px 3px rgba(0, 0, 0, 0.5);
-moz-transform: scale(1, 1) translateX(-50%);
transform: scale(1, 1) translateX(-50%);
}
97% {
box-shadow: 0 14px 2px rgba(0, 0, 0, 0.5);
-moz-animation-timing-function: cubic-bezier(1, 0, 1, 1);
animation-timing-function: cubic-bezier(1, 0, 1, 1);
-moz-transform: scale(1.05, 1) translateX(-50%);
transform: scale(1.05, 1) translateX(-50%);
}
100% {
-moz-transform: scale(1, 1) translateX(-50%);
transform: scale(1, 1) translateX(-50%);
}
}
#-webkit-keyframes displace {
from {
-webkit-animation-timing-function: linear;
-webkit-transform: translateX(0);
}
to {
-webkit-transform: translateX(100px);
}
}
#keyframes displace {
from {
-moz-animation-timing-function: linear;
animation-timing-function: linear;
-moz-transform: translateX(0);
transform: translateX(0);
}
to {
-moz-transform: translateX(100px);
transform: translateX(100px);
}
}
.jump {
-webkit-animation-name: jump;
-moz-animation-name: jump;
-ms-animation-name: jump;
-o-animation-name: jump;
animation-name: jump;
}
.diffuse-scale {
-webkit-animation-name: diffuse-scale;
-moz-animation-name: diffuse-scale;
-ms-animation-name: diffuse-scale;
-o-animation-name: diffuse-scale;
animation-name: diffuse-scale;
}
.displace {
-webkit-animation-name: displace;
-moz-animation-name: displace;
-ms-animation-name: displace;
-o-animation-name: displace;
animation-name: displace;
}
<div class="wrapper">
<div class="content animated infinite displace">
<span class="ball animated infinite jump"></span>
<span class="ball-shadow animated infinite diffuse-scale"></span>
</div>
</div>
Suggestion
Something like a less or SCSS with constant physical variables that are defined, or values that you can add to the function and sumule the physical behavior may even have already mixins that simulates certain behavior, I do not know something simple and only CSS.
You can use CSS-only but you will spend a lot of time figuring out the numbers for the Bezier, keyframe positions, scale and so on, and on top of that: a slight change in your layout, "gravity", dimensions, distance and you have to start "all over" (for the above part at least).
CSS animations are nice, but you will gain a better result with a little JavaScript code, not to mention have a lot more flexibility if you need to change something -
Define a vector for the ball
Define a arbitrary gravity
Calculate the vector and bounce
Bind resulting values to DOM element using transforms (gives smoother result compared to position).
Animate using requestAnimationFrame which syncs to monitor and gives just as smooth animations as CSS animations does.
Example
This example shows the basic, does not include the shadow, but that is left as an exercise for the reader.
var div = document.querySelector("div"),
v = {x: 2.3, y: 1}, // some vector
pos = {x: 100, y: 20}, // some position
g = 0.5, // some gravity
absorption = 0.7, // friction/absorption
bottom = 150, // floor collision
frames = 0; // to reset animation (for demo)
// main calculation of the animation using a particle and a vector
function calc() {
pos.x += v.x; // update position with vector
pos.y += v.y;
v.y += g; // update vector with gravity
if (pos.y > bottom) { // hit da floor, bounce
pos.y = bottom; // force position = max bottom
v.y = -v.y * absorption; // reduce power with absorption
}
if (pos.x < 0 || pos.x > 620) v.x = -v.x;
}
// animate
(function loop() {
calc();
move(div, pos);
if (++frames > 220) { // tweak, use other techniques - just to reset bounce
frames = 0; pos.y = 20;
}
requestAnimationFrame(loop)
})();
function move(el, p) {
el.style.transform = el.style.webkitTransform = "translate("+p.x+"px,"+p.y+"px)";
}
div {
width:20px;
height:20px;
background:rgb(0, 135, 222);
border-radius:50%;
position:fixed;
}
<div></div>
If you want a more accurate bounce of the floor, you can use the diff of actual position to reflect that as well:
if (pos.y > bottom) {
var diff = pos.y - bottom;
pos.y = bottom - diff;
...
And if you need this for several element, just create an instantiate-able object which embeds a reference to the element to animate, the calculations etc.
If you now want to change direction, start point, gravity and so on, you just update the respective values and everything works smooth when replayed.
Example intermediate step to produce CSS key-frames
You can modify the code above to crunch numbers for a CSS-animation.
Use number of frames and normalize the sequence range, run the calculations by counting frames. Then extract values per, lets say every 10 frames as well as every bounce, finally format numbers as key-frames.
Ideally you will always include top and bottom position - you can detect this by monitoring the direction of the vector's y-value (the sign), not shown here.
This will work as an intermediate step to produce the CSS-rule which we will use later:
var v = {x: 2.3, y: 1}, // some vector
pos = {x: 100, y: 20}, // some position
g = 0.5, // some gravity
absorption = 0.7, // friction/absorption
bottom = 150, // floor collision
frames = 0, // to reset animation (for demo)
maxFrames = 220, // so we can normalize
step = 10, // grab every nth + bounce
heights = [], // collect in an array as step 1
css = ""; // build CSS animation
// calc CSS-frames
for(var i = 0; i <= maxFrames; i++) {
var t = i / maxFrames;
pos.x += v.x; // update position with vector
pos.y += v.y;
v.y += g; // update vector with gravity
if (pos.y > bottom) {
pos.y = bottom;
v.y = -v.y * absorption;
heights.push({pst: t * 100, y: pos.y});
}
else if (!(i % step)) {heights.push({pst: t * 100, y: pos.y})}
}
// step 2: format height-array into CSS
css += "#keyframes demo {\n";
for(i = 0; i < heights.length; i++) {
var e = heights[i];
css += " " + e.pst.toFixed(3) + "% {transform: translateY(" + e.y.toFixed(3) + "px)}\n";
}
css += "}";
document.write("<pre>" + css + "</pre>");
If we grab the result from that and uses it as CSS for our final page, we get this result (sorry, non-prefixed version only in this demo):
(You will of course have to tweak and fine-tune this, but you'll get the gist.)
div {
animation: demo 3s linear infinite;
width:20px;
height:20px;
border-radius:50%;
background:rgb(0, 148, 243);
position:fixed;
left:100px;
}
#keyframes demo {
0.000% {transform: translateY(21.000px)}
4.545% {transform: translateY(58.500px)}
9.091% {transform: translateY(146.000px)}
9.545% {transform: translateY(150.000px)}
13.636% {transform: translateY(92.400px)}
18.182% {transform: translateY(75.900px)}
22.727% {transform: translateY(109.400px)}
25.455% {transform: translateY(150.000px)}
27.273% {transform: translateY(127.520px)}
31.818% {transform: translateY(106.320px)}
36.364% {transform: translateY(135.120px)}
37.727% {transform: translateY(150.000px)}
40.909% {transform: translateY(125.563px)}
45.455% {transform: translateY(133.153px)}
47.273% {transform: translateY(150.000px)}
50.000% {transform: translateY(134.362px)}
54.545% {transform: translateY(148.299px)}
55.000% {transform: translateY(150.000px)}
59.091% {transform: translateY(138.745px)}
61.818% {transform: translateY(150.000px)}
63.636% {transform: translateY(141.102px)}
67.727% {transform: translateY(150.000px)}
68.182% {transform: translateY(147.532px)}
72.727% {transform: translateY(150.000px)}
77.273% {transform: translateY(150.000px)}
81.818% {transform: translateY(150.000px)}
86.364% {transform: translateY(150.000px)}
90.909% {transform: translateY(150.000px)}
95.455% {transform: translateY(150.000px)}
100.000% {transform: translateY(150.000px)}
}
<div></div>
Personally I would recommend the JavaScript support though as it is more accurate for these type of animations, and as mentioned, it can easily adopt to new requirements.