CSS Background color transition/slide over when load

前端 未结 2 1639
Happy的楠姐
Happy的楠姐 2021-01-24 06:05

I\'ve found a CSS transition that works on hover just fine, it slides my background color over, but only on hover. Is there a way with CSS to make this happen on load not hover?

2条回答
  •  故里飘歌
    2021-01-24 06:48

    There is no way, using CSS alone, to delay the execution/application of an animation or transition effect until the exact moment a particular resource has been loaded. However, it can be done using JavaScript, but it's still tricky, as there is no load/onload event for background images loading (afaik).

    But you could take advantage of browser's caching mechanism: it doesn't load a resource more than once if it is used several times in the page (unless under very specific circumstances, which are not default, hence don't apply here).

    So the solution would be to use the background image of your element as src of an , and trigger the animation inside the onload event of that .

    Proof of concept:

    body {
      margin: 0;
      min-height: 100vh;
      background: #ccc url('https://s22849.pcdn.co/wp-content/uploads/2016/10/placeholder-large-1.png') no-repeat center 0;
      transition: background-position 1s cubic-bezier(.4,0,.2,1);
    }
    body.loaded {
      background-position: center center;
    }
    .placeholder {
      height: 0;
    }
    
    

    The key parts are:

    • the URL is exactly the same
    • the has a height of 0 (so it's not displayed).

    A cleaner way to do it is without adding the to DOM at all.

    When changing the src property of an , the browser will load it, even if it hasn't yet been added to the Document Object Model. And the onload event will still fire on that , as soon as the browser is ready to render it (which means right away for already cached images).

    So all you need to do is create an , set its src to your element's current backgroundImage (stripping the surrounding url()) and, in its onload event trigger the animation. In our case, that's done by adding loaded class to the element.

    const element = document.body,
      src = window.getComputedStyle(element).backgroundImage.slice(4, -1).replace(/"/g, "");
    if (src && src.length) {
      const img = document.createElement('img');
      img.onload = () => element.classList.add('loaded');
      img.src = src;
    }
    body {
      margin: 0;
      min-height: 100vh;
      background: #ccc url('https://s22849.pcdn.co/wp-content/uploads/2016/10/placeholder-large-1.png') no-repeat center 0;
      transition: background-position 1s cubic-bezier(.4, 0, .2, 1);
    }
    
    body.loaded {
      background-position: center center;
    }

    If you have trouble implementing the above into your project, provide more code (and I'll show you how to do it for your particular case).

    As you can test, the animation is always performed after the image has loaded. (Test in an incognito window or with cache disabled).

    An even better test would be to use a broken URL (while making it very obvious when the element has loaded class - I added a red border to it). Since the resource is not found, the loaded class should never be applied and the animation should not be performed.

    Finally, after 4 seconds, let's place a valid backgroundImage on the element, run our routine again and see if the background animates correctly:

    function onLoadBackgroundImage(element) {
      const src = window.getComputedStyle(element).backgroundImage.slice(4, -1).replace(/"/g, "");
      if (src && src.length) {
        const img = document.createElement('img');
        img.onload = () => element.classList.add('loaded');
        img.src = src;
      }
    }
    /* 4 seconds later... 
     * we actually load a valid image so we can see 
     * if the animation happens when it loads or it already happened */
    setTimeout(function() {
      const el = document.body;
      el.style.backgroundImage = `url('https://s22849.pcdn.co/wp-content/uploads/2016/10/placeholder-large-1.png')`;
      onLoadBackgroundImage(el);
    }, 4000);
    body {
      margin: 0;
      min-height: 100vh;
      background: #ccc url('https://non-existent-url') no-repeat center 0;
      transition: background-position 1s cubic-bezier(.4, 0, .2, 1);
    }
    
    body.loaded {
      background-position: center center;
      border: 3px solid red; /* let's make the application of .loaded obvious */
      box-sizing: border-box;
    }

提交回复
热议问题