jquery - Ring-shaped process spinner with fading gradient effect around the ring -


i want create ring-shaped process spinner css3 or javascript, similar loading progress spinner in android.

the spinner should rotate continuously , filled solid colour fades out along rim (i.e. conical gradient) in picture:

a thin ring on white background colour fading counter-clockwise opaque cyan transparent.

how can achieve this?

this trivially easy if css or svg had conical gradients! until conic-gradient() notation matures , gains support, can approximate effect slicing gradient , covering seams somehow.

below find 2 solutions. first solution uses embedded svg image; second uses multiple css gradients , pseudo-elements.

both start single div keyframe animation applied make rotate:

html:

<div class="spinner"></div> 

css:

@keyframes rotate {     { transform: rotate(0deg);   }       { transform: rotate(360deg); } }  .spinner {     animation: rotate 1s linear infinite;     height: 200px;     width: 200px; } 

you can use progress element if prefer, find pain style. note unless you're using prefixfree.js, you'll need add vendor-prefixed versions of @keyframes at-rule , transform , animation properties.


the svg solution

@keyframes rotate {  	from { transform: rotate(0deg);   }  	to   { transform: rotate(360deg); }  }    .spinner {  	animation: rotate 1s linear infinite;      background: url('data:image/svg+xml;base64,phn2zyb4bwxucz0iahr0cdovl3d3dy53my5vcmcvmjawmc9zdmciihhtbg5zonhsaw5rpsjodhrwoi8vd3d3lnczlm9yzy8xotk5l3hsaw5riib2awv3qm94psiwldagmjawldiwmci+pgrlznm+pgnsaxbqyxroiglkpsjyaw5nij48cgf0acbkpsjnmjawldewmeexmdasmtawldasmswxlde5ny44msw3os4ymuwxodgumdmsodeumjlbotasotasmcwxldasmtkwldewmhoilz48l2nsaxbqyxropjxmawx0zxigawq9imjsdxiiihg9ijaiihk9ijaipjxmzudhdxnzawfuqmx1cibpbj0iu291cmnlr3jhcghpyyigc3rkrgv2awf0aw9upsiziiavpjwvzmlsdgvypjxwyxroiglkpsjwiibkpsjnmjuwldewmeexntasmtuwldasmcwxldi0ni43miwxmzeumtlmmtawldewmeewldasmcwwldasmtawldewmhoiigzpbgw9imn5yw4ilz48l2rlznm+pgcgy2xpcc1wyxropsj1cmwoi3jpbmcpij48zybmawx0zxi9invybcgjymx1cikiihryyw5zzm9ybt0icm90yxrlkc02idewmcaxmdapij48dxnlihhsaw5romhyzwy9iinwiibmawxslw9wywnpdhk9ijaiihryyw5zzm9ybt0icm90yxrlkdagmtawidewmckilz48dxnlihhsaw5romhyzwy9iinwiibmawxslw9wywnpdhk9ii4wmyigdhjhbnnmb3jtpsjyb3rhdguomtigmtawidewmckilz48dxnlihhsaw5romhyzwy9iinwiibmawxslw9wywnpdhk9ii4wnyigdhjhbnnmb3jtpsjyb3rhdguomjqgmtawidewmckilz48dxnlihhsaw5romhyzwy9iinwiibmawxslw9wywnpdhk9ii4xiib0cmfuc2zvcm09injvdgf0zsgzniaxmdagmtawksivpjx1c2ugegxpbms6ahjlzj0ii3aiigzpbgwtb3bhy2l0et0ilje0iib0cmfuc2zvcm09injvdgf0zsg0ocaxmdagmtawksivpjx1c2ugegxpbms6ahjlzj0ii3aiigzpbgwtb3bhy2l0et0ilje3iib0cmfuc2zvcm09injvdgf0zsg2mcaxmdagmtawksivpjx1c2ugegxpbms6ahjlzj0ii3aiigzpbgwtb3bhy2l0et0iljiiihryyw5zzm9ybt0icm90yxrlkdcyidewmcaxmdapii8+phvzzsb4bgluazpocmvmpsijccigzmlsbc1vcgfjaxr5psiumjqiihryyw5zzm9ybt0icm90yxrlkdg0idewmcaxmdapii8+phvzzsb4bgluazpocmvmpsijccigzmlsbc1vcgfjaxr5psiumjgiihryyw5zzm9ybt0icm90yxrlkdk2idewmcaxmdapii8+phvzzsb4bgluazpocmvmpsijccigzmlsbc1vcgfjaxr5psiumzeiihryyw5zzm9ybt0icm90yxrlkdewocaxmdagmtawksivpjx1c2ugegxpbms6ahjlzj0ii3aiigzpbgwtb3bhy2l0et0iljm0iib0cmfuc2zvcm09injvdgf0zsgxmjagmtawidewmckilz48dxnlihhsaw5romhyzwy9iinwiibmawxslw9wywnpdhk9ii4zocigdhjhbnnmb3jtpsjyb3rhdguomtmyidewmcaxmdapii8+phvzzsb4bgluazpocmvmpsijccigzmlsbc1vcgfjaxr5psiundeiihryyw5zzm9ybt0icm90yxrlkde0ncaxmdagmtawksivpjx1c2ugegxpbms6ahjlzj0ii3aiigzpbgwtb3bhy2l0et0iljq1iib0cmfuc2zvcm09injvdgf0zsgxntygmtawidewmckilz48dxnlihhsaw5romhyzwy9iinwiibmawxslw9wywnpdhk9ii40ocigdhjhbnnmb3jtpsjyb3rhdguomty4idewmcaxmdapii8+phvzzsb4bgluazpocmvmpsijccigzmlsbc1vcgfjaxr5psiuntiiihryyw5zzm9ybt0icm90yxrlkde4mcaxmdagmtawksivpjx1c2ugegxpbms6ahjlzj0ii3aiigzpbgwtb3bhy2l0et0ilju1iib0cmfuc2zvcm09injvdgf0zsgxotigmtawidewmckilz48dxnlihhsaw5romhyzwy9iinwiibmawxslw9wywnpdhk9ii41osigdhjhbnnmb3jtpsjyb3rhdguomja0idewmcaxmdapii8+phvzzsb4bgluazpocmvmpsijccigzmlsbc1vcgfjaxr5psiunjiiihryyw5zzm9ybt0icm90yxrlkdixniaxmdagmtawksivpjx1c2ugegxpbms6ahjlzj0ii3aiigzpbgwtb3bhy2l0et0iljy2iib0cmfuc2zvcm09injvdgf0zsgymjggmtawidewmckilz48dxnlihhsaw5romhyzwy9iinwiibmawxslw9wywnpdhk9ii42osigdhjhbnnmb3jtpsjyb3rhdguomjqwidewmcaxmdapii8+phvzzsb4bgluazpocmvmpsijccigzmlsbc1vcgfjaxr5psiunyigdhjhbnnmb3jtpsjyb3rhdguomjuyidewmcaxmdapii8+phvzzsb4bgluazpocmvmpsijccigzmlsbc1vcgfjaxr5psiunziiihryyw5zzm9ybt0icm90yxrlkdi2ncaxmdagmtawksivpjx1c2ugegxpbms6ahjlzj0ii3aiigzpbgwtb3bhy2l0et0iljc2iib0cmfuc2zvcm09injvdgf0zsgynzygmtawidewmckilz48dxnlihhsaw5romhyzwy9iinwiibmawxslw9wywnpdhk9ii43osigdhjhbnnmb3jtpsjyb3rhdguomjg4idewmcaxmdapii8+phvzzsb4bgluazpocmvmpsijccigzmlsbc1vcgfjaxr5psiuodmiihryyw5zzm9ybt0icm90yxrlkdmwmcaxmdagmtawksivpjx1c2ugegxpbms6ahjlzj0ii3aiigzpbgwtb3bhy2l0et0iljg2iib0cmfuc2zvcm09injvdgf0zsgzmtigmtawidewmckilz48dxnlihhsaw5romhyzwy9iinwiibmawxslw9wywnpdhk9ii45myigdhjhbnnmb3jtpsjyb3rhdguomzi0idewmcaxmdapii8+phvzzsb4bgluazpocmvmpsijccigzmlsbc1vcgfjaxr5psiuotciihryyw5zzm9ybt0icm90yxrlkdmzniaxmdagmtawksivpjx1c2ugegxpbms6ahjlzj0ii3aiigzpbgwtb3bhy2l0et0imsigdhjhbnnmb3jtpsjyb3rhdguomzq4idewmcaxmdapii8+pc9npjwvzz48l3n2zz4=') no-repeat;  	height: 200px;  	width: 200px;  }
<div class="spinner"></div>

tested , working in ie 10, chrome , firefox.

caveats

changing inner or outer radius of ring more painful might imagine, require editing clip path values. it's outside scope of answer explain how calculate it, suffice took bit of geometry. i'll try put generator on github if time.

how svg version works

that big blob of gibberish base64 encoded svg image. run through a base64 decoder , you'll see original svg image.

here's full image nicely indented , commented can see how works:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewbox="0,0 200,200">      <defs>            <!-- ring shape centred on 100, 100 inner radius 90px, outer               radius 100px , 12 degree gap @ 348. -->          <clippath id="ring">              <path d="m 200, 100                       100, 100, 0, 1, 1, 197.81, 79.21                       l 188.03, 81.29                       90, 90, 0, 1, 0, 190, 100 z"/>          </clippath>            <!-- simple gaussian blur, used visually merge sectors. -->          <filter id="blur" x="0" y="0">              <fegaussianblur in="sourcegraphic" stddeviation="3" />          </filter>            <!-- 12 degree sector extending 150px. -->          <path id="p" d="m 250, 100                          150, 150, 0, 0, 1, 246.72, 131.19                          l 100, 100                          0, 0, 0, 0, 0, 100, 100 z" fill="cyan"/>      </defs>        <!-- clip blurred sectors ring shape. -->      <g clip-path="url(#ring)">            <!-- blur sectors make smooth shape , rotate               them anti-clockwise 6 degrees hide seam               opaque sector blurs transparent one. -->          <g filter="url(#blur)" transform="rotate(-6 100 100)">                <!-- each successive sector increases in opacity , rotated                   further 12 degrees. -->              <use xlink:href="#p" fill-opacity="0"    transform="rotate(  0 100 100)"/>              <use xlink:href="#p" fill-opacity="0.03" transform="rotate( 12 100 100)"/>              <use xlink:href="#p" fill-opacity="0.07" transform="rotate( 24 100 100)"/>              <use xlink:href="#p" fill-opacity="0.1"  transform="rotate( 36 100 100)"/>              <use xlink:href="#p" fill-opacity="0.14" transform="rotate( 48 100 100)"/>              <use xlink:href="#p" fill-opacity="0.17" transform="rotate( 60 100 100)"/>              <use xlink:href="#p" fill-opacity="0.2"  transform="rotate( 72 100 100)"/>              <use xlink:href="#p" fill-opacity="0.24" transform="rotate( 84 100 100)"/>              <use xlink:href="#p" fill-opacity="0.28" transform="rotate( 96 100 100)"/>              <use xlink:href="#p" fill-opacity="0.31" transform="rotate(108 100 100)"/>              <use xlink:href="#p" fill-opacity="0.34" transform="rotate(120 100 100)"/>              <use xlink:href="#p" fill-opacity="0.38" transform="rotate(132 100 100)"/>              <use xlink:href="#p" fill-opacity="0.41" transform="rotate(144 100 100)"/>              <use xlink:href="#p" fill-opacity="0.45" transform="rotate(156 100 100)"/>              <use xlink:href="#p" fill-opacity="0.48" transform="rotate(168 100 100)"/>              <use xlink:href="#p" fill-opacity="0.52" transform="rotate(180 100 100)"/>              <use xlink:href="#p" fill-opacity="0.55" transform="rotate(192 100 100)"/>              <use xlink:href="#p" fill-opacity="0.59" transform="rotate(204 100 100)"/>              <use xlink:href="#p" fill-opacity="0.62" transform="rotate(216 100 100)"/>              <use xlink:href="#p" fill-opacity="0.66" transform="rotate(228 100 100)"/>              <use xlink:href="#p" fill-opacity="0.69" transform="rotate(240 100 100)"/>              <use xlink:href="#p" fill-opacity="0.7"  transform="rotate(252 100 100)"/>              <use xlink:href="#p" fill-opacity="0.72" transform="rotate(264 100 100)"/>              <use xlink:href="#p" fill-opacity="0.76" transform="rotate(276 100 100)"/>              <use xlink:href="#p" fill-opacity="0.79" transform="rotate(288 100 100)"/>              <use xlink:href="#p" fill-opacity="0.83" transform="rotate(300 100 100)"/>              <use xlink:href="#p" fill-opacity="0.86" transform="rotate(312 100 100)"/>              <use xlink:href="#p" fill-opacity="0.93" transform="rotate(324 100 100)"/>              <use xlink:href="#p" fill-opacity="0.97" transform="rotate(336 100 100)"/>              <use xlink:href="#p" fill-opacity="1"    transform="rotate(348 100 100)"/>          </g>      </g>  </svg>

this minified, base64 encoded , used inline css background image. may serve separate file if prefer. technically, should possible embed image without base64 encoding, right works in chrome.


the pure css solution

this solution uses separate linear gradients in each quadrant , relies on visual similarity cover seams. ring shape formed using pseudo-elements.

@keyframes rotate {  	from { transform: rotate(0deg);   }  	to   { transform: rotate(360deg); }  }    .spinner {  	animation: rotate 1s linear infinite;  	background: cyan;  	border-radius: 50%;  	height: 200px;  	width: 200px;  	position: relative;  }    .spinner:before,  .spinner:after {  	content: '';  	position: absolute;  }    .spinner:before {  	border-radius: 50%;  	background:  		linear-gradient(0deg,   hsla(0, 0%, 100%, 1  ) 50%, hsla(0, 0%, 100%, 0.9) 100%)   0%   0%,  		linear-gradient(90deg,  hsla(0, 0%, 100%, 0.9)  0%, hsla(0, 0%, 100%, 0.6) 100%) 100%   0%,  		linear-gradient(180deg, hsla(0, 0%, 100%, 0.6)  0%, hsla(0, 0%, 100%, 0.3) 100%) 100% 100%,  		linear-gradient(360deg, hsla(0, 0%, 100%, 0.3)  0%, hsla(0, 0%, 100%, 0  ) 100%)   0% 100%  	;  	background-repeat: no-repeat;  	background-size: 50% 50%;  	top: -1px;  	bottom: -1px;  	left: -1px;  	right: -1px;  }    .spinner:after {  	background: white;  	border-radius: 50%;  	top: 3%;  	bottom: 3%;  	left: 3%;  	right: 3%;  }
<div class="spinner"></div>

tested , working in ie 10, chrome , firefox.

caveats

unlike svg solution, works against solid background colour. requires modification in several places if want change colour, pain.

how pure css version works

  1. to start with, spinner styled circle uniform background colour. colour of spinning gradient.

    .spinner {     background: cyan;     border-radius: 50%;     /* ... */ } 
  2. set things can overlay pseudo-elements on top of spinner:

    .spinner {     /* ... */     position: relative; }  .spinner:before, .spinner:after {     content: '';     position: absolute; } 
  3. this tricky bit. each quadrant of :before pseudo-element set different linear gradient starting opaque white , progressively becoming more , more transparent. towards centre it's easy see gradients join up, notice how around outside colours close enough appear join smoothly.

    .spinner:before {     border-radius: 50%;     background:         linear-gradient(0deg,   hsla(0, 0%, 100%, 1  ) 50%, hsla(0, 0%, 100%, 0.9) 100%)   0%   0%,         linear-gradient(90deg,  hsla(0, 0%, 100%, 0.9)  0%, hsla(0, 0%, 100%, 0.6) 100%) 100%   0%,         linear-gradient(180deg, hsla(0, 0%, 100%, 0.6)  0%, hsla(0, 0%, 100%, 0.3) 100%) 100% 100%,         linear-gradient(360deg, hsla(0, 0%, 100%, 0.3)  0%, hsla(0, 0%, 100%, 0  ) 100%)   0% 100%     ;     background-repeat: no-repeat;     background-size: 50% 50%;     top: -1px;     bottom: -1px;     left: -1px;     right: -1px; } 

    this positioned goes over edge of spinner because if position right edge faint rim of background colour visible.

  4. finally, hide middle bit using ::after pseudo-element make ring shape:

    .spinner:after {     background: white;     border-radius: 50%;     top: 3%;     bottom: 3%;     left: 3%;     right: 3%; } 

et voilá!


Comments

Popular posts from this blog

java - WrongTypeOfReturnValue exception thrown when unit testing using mockito -

php - Magento - Deleted Base url key -

android - How to disable Button if EditText is empty ? -