How to prevent css keyframe animation to run on page load?

后端 未结 7 1850
轻奢々
轻奢々 2020-12-07 20:20

I have a div in which I animate the content:

相关标签:
7条回答
  • 2020-12-07 20:37

    Is there a way to do this pure CSS ?

    Yes, absolutely : See the fork http://jsfiddle.net/5r32Lsme/2/ There is really no need for JS.

    and I'd prefer it to run only after a hover event.

    So you need to tell CSS what happens when it is NOT a hover event as well - in your example :

    #container:not(:hover) #content {
      visibility: hidden;
      transition: visibility 0.01s 1s;
    }
    

    But there are two things to note:

    1) The transition delay above should match your animation duration

    2) You can't use the property which you use to hide the animation onLoad in the animation. If you do need visibility in the animation, hide the animation initially like e.g.

    #container:not(:hover) #content {
      top: -8000px;
      transition: top 0.01s 1s;
    }    
    

    A sidenote:

    It is recommended to put native CSS properties after prefixed ones, so it should be

    -webkit-animation-fill-mode: forwards;
    animation-fill-mode: forwards;
    

    and now there is a native transform

    -webkit-transform: translateY(0);
    transform: translateY(0);
    
    0 讨论(0)
  • 2020-12-07 20:41

    Solution 1 - Add down animation on first hover

    Probably the best option is to not put the down animation on until the user has hovered over the container for the first time.

    This involves listening to the mouseover event then adding a class with the animation at that point, and removing the event listener. The main (potential) downside of this is it relies on Javascript.

    ;(function(){
        var c = document.getElementById('container');
        function addAnim() {
            c.classList.add('animated')
            // remove the listener, no longer needed
            c.removeEventListener('mouseover', addAnim);
        };
    
        // listen to mouseover for the container
        c.addEventListener('mouseover', addAnim);
    })();
    #container {
        position:relative;
        width:100px;
        height:100px;
        border-style:inset;
    }
    #content {
        position:absolute;
        top:100px;
        width:100%;
        height:100%;
        background-color:lightgreen;
        opacity:0;
    }
    
    /* This gets added on first mouseover */
    #container.animated #content {
        -webkit-animation:animDown 1s ease;
    }
    
    #container:hover #content {
        -webkit-animation:animUp 1s ease;
        animation-fill-mode:forwards;
        -webkit-animation-fill-mode:forwards;
    }
    
    @-webkit-keyframes animUp {
        0% {
            -webkit-transform:translateY(0);
            opacity:0;
        }
        100% {
            -webkit-transform:translateY(-100%);
            opacity:1;
        }
    }
    @-webkit-keyframes animDown {
        0% {
            -webkit-transform:translateY(-100%);
            opacity:1;
        }
        100% {
            -webkit-transform:translateY(0);
            opacity:0;
        }
    }
    <div id="container">
        <div id="content"></div>
    </div>

    Solution 2 - play animation hidden

    Another way around this is to initially hide the element, make sure the animation plays while it is hidden, then make it visible. The downside of this is that the timing could be slightly off and it is made visible too early, and also the hover isn't available straight away.

    This requires some Javascript which waits for the length of the animation and only then makes #content visible. This means you also need to set the initial opacity to 0 so it doesn't appear on load and also remove the visibility from the keyframes - these aren't doing anything anyway:

    // wait for the animation length, plus a bit, then make the element visible
    window.setTimeout(function() {
        document.getElementById('content').style.visibility = 'visible';
    }, 1100);
    #container {
        position:relative;
        width:100px;
        height:100px;
        border-style:inset;
    }
    
    #content {
        visibility:hidden;
        -webkit-animation:animDown 1s ease;
        position:absolute;
        top:100px;
        width:100%;
        height:100%;
        background-color:lightgreen;
        opacity:0;
    }
    
    #container:hover #content {
        -webkit-animation:animUp 1s ease;
        animation-fill-mode:forwards;
        -webkit-animation-fill-mode:forwards;
    }
    
    @-webkit-keyframes animUp {
        0% {
            -webkit-transform:translateY(0);
            opacity:0;
        }
        100% {
            -webkit-transform:translateY(-100%);
            opacity:1;
        }
    }
    
    @-webkit-keyframes animDown {
        0% {
            -webkit-transform:translateY(-100%);
            opacity:1;
        }
        100% {
            -webkit-transform:translateY(0);
            opacity:0;
        }
    }
    <div id="container">
        <div id="content"></div>
    </div>

    Solution 3 - Use transitions

    In your scenario, you can make this CSS only by replacing the keyframes with a transition instead, so it starts with opacity:0 and just the hover has a change in opacity and the transform:

    #container {
        position:relative;
        width:100px;
        height:100px;
        border-style:inset;
    }
    
    #content {
        position:absolute;
        top:100px;
        width:100%;
        height:100%;
        background-color:lightgreen;
    
        /* initial state - hidden */
        opacity:0;
        /* set properties to animate - applies to hover and revert */
        transition:opacity 1s, transform 1s;
    }
    
    #container:hover #content {
        /* Just set properties to change - no need to change visibility */
        opacity:1;
        -webkit-transform:translateY(-100%);
        transform:translateY(-100%);
    }
    <div id="container">
        <div id="content"></div>
    </div>

    0 讨论(0)
  • 2020-12-07 20:43

    This is not pure CSS but maybe someone will stumble across this thread as I did:

    In React I solved this by setting a temporary class in ComponentDidMount() like so:

    componentDidMount = () => {
        document.getElementById("myContainer").className =
            "myContainer pageload";
    };
    

    and then in css:

    .myContainer.pageload {
        animation: none;
    }
    
    .myContainer.pageload * {
        animation: none;
    }
    

    If you are not familiar the " *" (n.b. the space) above means that it applies to all descendents of the element as well. The space means all descendents and the asterisk is a wildcard operator that refers to all types of elements.

    0 讨论(0)
  • 2020-12-07 20:47

    Building off of Tominator's answer, in React, you can apply it per component like so:

    import React, { Component } from 'react'
    
    export default class MyThing extends Component {
      constructor(props) {
        super(props);
    
        this.state = {
          preloadClassName: 'preload'
        }
      }
    
      shouldComponentUpdate(nextProps, nextState) {
        return nextState.preloadClassName !== this.state.preloadClassName;
      }
    
      componentDidUpdate() {
        this.setState({ preloadClassName: null });
      }
    
      render() {
        const { preloadClassName } = this.state;
    
        return (
          <div className={`animation-class ${preloadClassName}`}>
            <p>Hello World!</p>
          </div>
        )
      }
    }
    

    and the css class:

    .preload * {
      -webkit-animation-duration: 0s !important;
      animation-duration: 0s !important;
      transition: background-color 0s, opacity 0s, color 0s, width 0s, height 0s, padding 0s, margin 0s !important;
    }
    
    0 讨论(0)
  • 2020-12-07 20:53

    I always set preload class to body with animation time value 0 and its working pretty well. I have some back going transitions so I have to remove load animation to them too. I solved this by temporary setting animation time to 0. You can change transitions to match yours.

    HTML

    ... <body class="preload">...

    CSS is setting animation to 0s

    body.preload *{
    animation-duration: 0s !important;
    -webkit-animation-duration: 0s !important;
    transition:background-color 0s, opacity 0s, color 0s, width 0s, height 0s, padding 0s, margin 0s !important;}
    

    JS will remove class after some delay so animations can happen in normal time :)

    setTimeout(function(){
        document.body.className="";
    },500);
    
    0 讨论(0)
  • 2020-12-07 20:57

    If you're looking at this after 2019, a better solution is this:

    let div = document.querySelector('div')
    document.addEventListener('DOMContentLoaded', () => {
        // Adding timeout to simulate the loading of the page
        setTimeout(() => {
            div.classList.remove('prevent-animation')
        }, 2000)
        
        document.querySelector('button').addEventListener('click', () => {
            if(div.classList.contains('after')) {
                div.classList.remove('after')
            } else {
                div.classList.add('after')
            }
        })
    })
    div {
        background-color: purple;
        height: 150px;
        width: 150px;
    }
    
    .animated-class {
        animation: animationName 2000ms;
    }
    
    .animated-class.prevent-animation {
        animation-duration: 0ms;
    }
    
    .animated-class.after {
        animation: animation2 2000ms;
        background-color: orange;
    }
    
    @keyframes animationName {
        0% {
            background-color: red;
        }
        50% {
            background-color: blue;
        }
        100% {
            background-color: purple;
        }
    }
    
    @keyframes animation2 {
        0% {
            background-color: salmon;
        }
        50% {
            background-color: green;
        }
        100% {
          background-color: orange;
        }
    }
    <div class="animated-class prevent-animation"></div>
    <button id="btn">Toggle between animations</button>

    0 讨论(0)
提交回复
热议问题