Faking motion blur with stroke-dasharray.
Colors off in Safari because of filter.
Recreation of this gif from FLRN
A Pen by Jake Albaugh on CodePen.
Faking motion blur with stroke-dasharray.
Colors off in Safari because of filter.
Recreation of this gif from FLRN
A Pen by Jake Albaugh on CodePen.
| // circles to generate | |
| - var _count = 6 | |
| // svg viewbox to set our rotation center for us | |
| svg( | |
| class='svg', | |
| width='400', height='400', | |
| viewBox='-200 -200 400 400' | |
| ) | |
| // defining a blur for reference in our CSS | |
| defs | |
| // centering filter at twice scale to avoid hard edges | |
| filter(id='blur',x='-50%',y='-50%',width='200%',height='200%') | |
| //feGaussianBlur(in='SourceGraphic', stdDeviation="0.5") | |
| feConvolveMatrix(order='3',kernelMatrix='0 1 0 1 0 1 0 1 0') | |
| // creating our circles via a loop | |
| - var i = 0 | |
| while i <= _count | |
| // radius more or less matches gif | |
| - var radius = (18.5 * (_count - i)) | |
| circle(r=radius) | |
| - i++ | |
| // reference image from flrn | |
| img( | |
| class='img', | |
| src='http://31.media.tumblr.com/bfaece2581639138ca5fa4958363bb89/tumblr_nmeogmm5KX1tcuj64o1_400.gif', | |
| title='Original Image') |
| // circles to generate | |
| - var _count = 6 | |
| // svg viewbox to set our rotation center for us | |
| svg( | |
| class='svg', | |
| width='400', height='400', | |
| viewBox='-200 -200 400 400' | |
| ) | |
| // defining a blur for reference in our CSS | |
| defs | |
| // centering filter at twice scale to avoid hard edges | |
| filter(id='blur',x='-50%',y='-50%',width='200%',height='200%') | |
| //feGaussianBlur(in='SourceGraphic', stdDeviation="0.5") | |
| feConvolveMatrix(order='3',kernelMatrix='0 1 0 1 0 1 0 1 0') | |
| // creating our circles via a loop | |
| - var i = 0 | |
| while i <= _count | |
| // radius more or less matches gif | |
| - var radius = (18.5 * (_count - i)) | |
| circle(r=radius) | |
| - i++ | |
| // reference image from flrn | |
| img( | |
| class='img', | |
| src='http://31.media.tumblr.com/bfaece2581639138ca5fa4958363bb89/tumblr_nmeogmm5KX1tcuj64o1_400.gif', | |
| title='Original Image') |
| // props to the most-perfect @thebabydino for the tips :) | |
| // colors array | |
| $colors: ( | |
| 0: #10a0ab, | |
| 1: #f03e32, | |
| 2: #ffae00 | |
| ); | |
| // pi cause we dont need compass for a single value | |
| $pi: 3.141592653; | |
| // difference in size | |
| $size-increment: 2 * 18.5; // should be two times radius value in jade loop | |
| // how many circles | |
| $count: 6; | |
| // timing in ms | |
| $duration: 3000ms; | |
| // width of circle strokes | |
| $stroke-width: 9; | |
| // empty diameters list | |
| $diameters: (); | |
| // creating our list of diameters | |
| @for $i from 1 through $count { | |
| $diameter: $size-increment * ($count - $i) + $size-increment; | |
| $diameters: append($diameters, $diameter); | |
| } | |
| // limiting our svg scope using a class | |
| .svg { | |
| // centering our svg on the page | |
| position: fixed; | |
| top: 50%; left: 50%; | |
| transform: translate3d(-50%, -50%, 0); | |
| // circle elements | |
| circle { | |
| fill: none; | |
| stroke: black; | |
| stroke-width: $stroke-width; | |
| filter: url(#blur); // lightens color in safari ?? | |
| // for each diameter | |
| @each $di in $diameters { | |
| // get position in diameters list | |
| $i: index($diameters,$di); | |
| // calculating circumference | |
| $circ: $pi * $di; | |
| // space before completion = 20% | |
| $offset: $circ * 0.2; | |
| // each circle | |
| &:nth-of-type(#{$i}) { | |
| // stroke color selection from colors map | |
| stroke: map-get($colors, $i % 3); | |
| // position-specific animation | |
| animation: | |
| line-#{$i} $duration linear infinite, | |
| rotation-#{$i} $duration linear infinite; | |
| // setting delays to handle out-of-sync. | |
| // when loop is at FIRST half, previous loop is at ZERO | |
| // when loop is 1/4 finished, previous loop is 2/4 finished | |
| // delay should equal 1/4 | |
| // working this shit out | |
| $half_duration: $duration / 2; | |
| $quarter_duration: $half_duration / 2; | |
| // initial delay = 0 | |
| // second delay = 1/2 + 1/4 | |
| animation-delay: ($i - 1) * ($half_duration + $quarter_duration); | |
| // initial nothingness | |
| stroke-dasharray: 0,$circ; | |
| stroke-dashoffset: 0; | |
| } | |
| // | |
| // fake blurs by adding tiny scaled dasharrays |||| | |
| // | |
| // initial ones, more added the bigger the diameter | |
| $micro-array: (); | |
| // initial zeroes for animation to recognize them even if they dont visually exist | |
| $micro-array-zeroes: (); | |
| // amount of micro dashes to generate | |
| $dash-count: $count - $i + 1; | |
| // relative to diameter scale, append additional dashes | |
| @for $d from 1 through $dash-count { | |
| $dash-size: 3 * (1 - $d/$dash-count); | |
| $dash-size: 1; | |
| $micro-array: append($micro-array,($dash-size,1),comma); | |
| $micro-array-zeroes: append($micro-array-zeroes,(0,0),comma); | |
| } | |
| // line animations | |
| @keyframes line-#{$i} { | |
| 0% { | |
| stroke-dasharray: | |
| // zeroes before line at start | |
| $micro-array-zeroes, | |
| // line at zero at start | |
| 0, | |
| // zeroes after line at start | |
| $micro-array-zeroes, | |
| // circumference space at start = no line | |
| $circ; | |
| stroke-dashoffset: 0; | |
| } | |
| 50% { | |
| stroke-dasharray: | |
| // micro dash array before line at midpoint | |
| $micro-array, | |
| // almost complete circle at midpoint | |
| $circ - $offset, | |
| // micro dash array after segment to achieve motion blur | |
| $micro-array, | |
| // offset spacing for incomplete circle at midpoint | |
| $offset; | |
| stroke-dashoffset: 0; | |
| } | |
| 100% { | |
| stroke-dasharray: | |
| // micro dash array before line at end | |
| $micro-array-zeroes, | |
| // line complete at end (dashoffset moves it invisible) | |
| $circ + $offset, | |
| // zeroes for previous array to animate to | |
| $micro-array-zeroes, | |
| // circumference space at end = no line | |
| $circ; | |
| // dash offset pushes dashes out of visibility | |
| stroke-dashoffset: -$circ - length($micro-array); | |
| } | |
| } | |
| // moving each rotation starting point up 60 degrees | |
| $rotate-offset: (360/6 * ($i - 1)); | |
| @keyframes rotation-#{$i} { | |
| from { transform: rotate($rotate-offset * 1deg) } | |
| to { transform: rotate($rotate-offset + 360deg) } | |
| } | |
| } | |
| } | |
| } | |
| // | |
| // global stuff | |
| // | |
| body { background-color: #262626; } | |
| // example gif in bottom left | |
| .img { | |
| position: fixed; | |
| left: 0; bottom: 0; | |
| width: 15%; | |
| // below centers on screen to scale | |
| //left: 50%; top: 50%; | |
| //transform: translate(-50%, -50%); | |
| //width: 400px; | |
| height: auto; | |
| //opacity: 0.5; | |
| z-index: -1; | |
| } |