Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vertically Align Rect Elements Inside SVG By Center of Rect

Goal:

I found a tutorial online to make a CSS3 infinite loading icon, using rectangles which grow and shrink in height. They end up appearing like:

enter image description here

It uses 5 divs wrapped in an outer div, and works perfectly. I want to try and recreate the effect using an SVG though, so that I can reference it with just an image, not having to add 5 HTML elements.


What I Have:

I started off with the same CSS animation code, and used 5 rects inside the svg tags. The animation works perfect, but I can't get the rectangles to be centered vertically. Since they are placed using x and y coordinates, which correspond to the top/left point of each rectangle, they are fixed to that location.

<svg version="1.1" baseProfile="full" width="250" height="250" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">
  <rect class="rect1" fill="black" height="30" width="6" x="0" />
  <rect class="rect2" fill="black" height="30" width="6" x="10" />
  <rect class="rect3" fill="black" height="30" width="6" x="20" />
  <rect class="rect4" fill="black" height="30" width="6" x="30" />
  <rect class="rect5" fill="black" height="30" width="6" x="40" />
</svg>

rect {
  -webkit-animation: stretchdelay 1.2s infinite ease-in-out;
  animation: stretchdelay 1.2s infinite ease-in-out;
  alignment-baseline:bottom;
}

.rect2 {
  -webkit-animation-delay: -1.1s;
  animation-delay: -1.1s;
}

.rect3 {
  -webkit-animation-delay: -1.0s;
  animation-delay: -1.0s;
}

.rect4 {
  -webkit-animation-delay: -0.9s;
  animation-delay: -0.9s;
}

.rect5 {
  -webkit-animation-delay: -0.8s;
  animation-delay: -0.8s;
}

@-webkit-keyframes stretchdelay {
  0%, 40%, 100% { -webkit-transform: scaleY(0.4) }  
  20% { -webkit-transform: scaleY(1.0) }
}

@keyframes stretchdelay {
  0%, 40%, 100% { 
    transform: scaleY(0.4);
    -webkit-transform: scaleY(0.4);
  }  20% { 
    transform: scaleY(1.0);
    -webkit-transform: scaleY(1.0);
  }
}

See Working Example: http://codepen.io/Kelderic/pen/vuipF

One thing that is odd, it's running in CodePen, the same code doesn't run in JSFiddle. It also doesn't run when I embed the CodePen as an SVG.


Question

Is using CSS animations like this supposed to work for SVG elements, and can I fix them in the center to match the original?


Edit

js1568's answer provides what SHOULD be a fix, and it does make things work in Chrome. It has no effect in Firefox though, and after some research I've found that I'm not the only one who has had the same problem with Firefox.

Setting transform-origin on SVG group not working in FireFox

I think the only answer here is that at this time this won't work in all browsers. (If anyone does know a way, feel free to add an answer though!)


Edit 2

I figured a way to make this work in Firefox, explained in an answer below. Still no IE9-11 though.

like image 611
Andy Mercer Avatar asked Nov 10 '22 02:11

Andy Mercer


1 Answers

Okay, so I figured out the answer to this, and it works in Chrome and Firefox. IE doesn't support CSS transforms on SVG elements (though it does support the transform attribute, and I'm trying to figure out a workaround).

Instead of trying to set the baseline to the center of the rect element, I just use a second animation. I move the element up and down, sync'd up time-wise. This creates the appearance that the element is centered vertically.

I had some issues getting it to sync perfectly when using the 0.4 scale, so I changed over to 0.5, which still looks good.

HTML:

<svg version="1.1" baseProfile="full" width="250" height="250" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">
  <rect class="rect1" fill="black" height="30" transform="translate(2,2)" width="6" x="0" y="0" />
  <rect class="rect2" fill="black" height="30" width="6" x="10" y="0" />
  <rect class="rect3" fill="black" height="30" width="6" x="20" y="0" />
  <rect class="rect4" fill="black" height="30" width="6" x="30" y="0" />
  <rect class="rect5" fill="black" height="30" width="6" x="40" y="0" />
</svg>

CSS:

@-webkit-keyframes stretchdelay {
  0% { 
    -webkit-transform: scaleY(1.0) translate(0,0);
  }  30%,70% { 
    -webkit-transform: scaleY(0.5) translate(0,15px);
  } 100% { 
    -webkit-transform: scaleY(1.0) translate(0,0);
  }
}

@keyframes stretchdelay {
  0% { 
    transform: scaleY(1.0) translate(0,0);
    -webkit-transform: scaleY(1.0) translate(0,0);
  }  30%,70% { 
    transform: scaleY(0.5) translate(0,15px);
    -webkit-transform: scaleY(0.5) translate(0,15px);
  } 100% { 
    transform: scaleY(1.0) translate(0,0);
    -webkit-transform: scaleY(1.0) translate(0,0);
  }
}

rect {
  -webkit-animation: stretchdelay 1.2s infinite ease-in-out;
  animation: stretchdelay 1.2s infinite ease-in-out;
  -ms-animation: stretchdelay 1.2s infinite ease-in-out;
}

.rect2 {
  -webkit-animation-delay: -1.1s;
  animation-delay: -1.1s;
}

.rect3 {
  -webkit-animation-delay: -1.0s;
  animation-delay: -1.0s;
}

.rect4 {
  -webkit-animation-delay: -0.9s;
  animation-delay: -0.9s;
}

.rect5 {
  -webkit-animation-delay: -0.8s;
  animation-delay: -0.8s;
}

Result:

enter image description here

(Note, recently CodePen added a feature allowing you to embed SVGs created inline as SVG images. I found out today as I created this, that all CSS must be placed in <style> tags inside the HTML input box. If it is placed in the CSS box, it won't work.)

like image 78
Andy Mercer Avatar answered Nov 12 '22 17:11

Andy Mercer