Search code examples
htmlcssbackground-imagecss-sprites

Responsive Circle with CSS Sprite background


I'm having issues knowing how to do the right math or formula to make a responsive css sprite. Its a circle with border radius 50%. So its width and padding-bottom are set to 100% to make the circle proportionate.

My issue is getting the sprite to match up and step(16 times) through the animation and work responsively. I can get it work static with px.

.hero_sprite_container {
  width: 100%;
}

.hero_sprite {
  width: 100%;
  padding-bottom: 100%;
  border-radius: 50%;
  background: green url('https://i.imgur.com/F1wpeSB.jpg') no-repeat 0 0;
  background-size: 100%;
  animation: sprite 10s steps(16) infinite;
}

@keyframes sprite {
  to {
    background-position: 0 100%;
  }
}
<div class="hero_image">
  <div class="hero_sprite_container">
    <div class="hero_sprite lazyload"></div>
  </div>
</div>

Here is my code pen so you can see it.

https://codepen.io/gorelegacy/pen/ExxXZge

my sprite - https://i.imgur.com/F1wpeSB.jpg


Solution

  • The issue is related to the use of background-position with percentage value which will not give you the intended result using 16 steps. Instead you can use a pseudo element as background layer and consider translatation:

    .hero_sprite {
      width: 50%; 
      margin:auto;
      border-radius: 50%;
      overflow:hidden;
      position:relative;
      z-index:0;
    }
    /*To maintain the ratio*/
    .hero_sprite:before {
       content:"";
       display:inline-block;
       padding-bottom: 100%;
    }
    /* the background layer */
    .hero_sprite:after {
      content:"";
      position:absolute;
      z-index:-1;
      top:0;
      left:0;
      right:0;
      height:1600%; /* N * 100% */
      background:url('https://i.imgur.com/F1wpeSB.jpg')top/100% 100%;
      animation: sprite 10s steps(16) infinite; /* Steps(N) */
    }
    
    @keyframes sprite {
      to {
        transform: translateY(-100%);
      }
    }
    <div class="hero_sprite lazyload"></div>

    With background, you either need to use pixel values (not scalable)

    .hero_sprite_container {
      width: 100%;
    }
    
    .hero_sprite {
      width: 200px;
      height:200px;
      border-radius: 50%;
      background: green url('https://i.imgur.com/F1wpeSB.jpg') no-repeat 0 0;
      background-size: 100% auto;
      animation: sprite 10s steps(16) infinite;
    }
    
    @keyframes sprite {
      to {
        background-position: 0 -3200px;
      }
    }
    <div class="hero_image">
      <div class="hero_sprite_container">
        <div class="hero_sprite lazyload"></div>
      </div>
    </div>

    Or define 15 in the steps but you will miss one image:

    .hero_sprite_container {
      width: 100%;
    }
    
    .hero_sprite {
      width: 50%;
      padding-top:50%;
      border-radius: 50%;
      background: green url('https://i.imgur.com/F1wpeSB.jpg') no-repeat 0 0;
      background-size: 100% auto;
      animation: sprite 10s steps(15) infinite;
    }
    
    @keyframes sprite {
      to {background-position: 0 100%;}
    }
    <div class="hero_image">
      <div class="hero_sprite_container">
        <div class="hero_sprite lazyload"></div>
      </div>
    </div>

    You can rectify the below issue by adding an empty slot at end then define 16 steps.

    Related to understand how steps works https://stackoverflow.com/a/51843473/8620333

    You can also manually define the different position but it would be tedious:

    .hero_sprite_container {
      width: 100%;
    }
    
    .hero_sprite {
      width: 50%;
      padding-top:50%;
      border-radius: 50%;
      background: green url('https://i.imgur.com/F1wpeSB.jpg') no-repeat 0 0;
      background-size: 100% auto;
      animation: sprite 10s  infinite;
    }
    
    @keyframes sprite {
      0%     , 6.25%  {background-position: 0 calc(0*100%/15);}
      6.26%  , 12.5%  {background-position: 0 calc(1*100%/15);}
      12.51% , 18.75% {background-position: 0 calc(2*100%/15);}
      18.76% , 25%    {background-position: 0 calc(3*100%/15);}
      25.01% , 31.25% {background-position: 0 calc(4*100%/15);}
      31.26% , 37.5%  {background-position: 0 calc(5*100%/15);}
      37.51% , 43.75% {background-position: 0 calc(6*100%/15);}
      43.76% , 50%    {background-position: 0 calc(7*100%/15);}
      50.01% , 56.25% {background-position: 0 calc(8*100%/15);}
      56.26% , 62.5%  {background-position: 0 calc(9*100%/15);}
      62.51% , 68.75% {background-position: 0 calc(10*100%/15);}
      68.76% , 75%    {background-position: 0 calc(11*100%/15);}
      75.01% , 81.25% {background-position: 0 calc(12*100%/15);}
      81.26% , 87.5%  {background-position: 0 calc(13*100%/15);}
      87.51% , 93.75% {background-position: 0 calc(14*100%/15);}
      93.76% , 100%   {background-position: 0 calc(15*100%/15);}
    }
    <div class="hero_image">
      <div class="hero_sprite_container">
        <div class="hero_sprite lazyload"></div>
      </div>
    </div>