Анимированный индикатор загрузки на CSS3 и SVG
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
:root { --spinner-size: 5rem; --dot-size: calc(var(--spinner-size) / 5); --duration: 3s; --delay: calc(var(--duration) / 60); } @-webkit-keyframes rotate { from { -webkit-transform: translateX(0) translateY(0); transform: translateX(0) translateY(0); } 20% { -webkit-transform: translateX(0) translateY(0); transform: translateX(0) translateY(0); } 25% { -webkit-transform: translateX(0) translateY(calc(var(--spinner-size) - var(--dot-size))); transform: translateX(0) translateY(calc(var(--spinner-size) - var(--dot-size))); } 45% { -webkit-transform: translateX(0) translateY(calc(var(--spinner-size) - var(--dot-size))); transform: translateX(0) translateY(calc(var(--spinner-size) - var(--dot-size))); } 50% { -webkit-transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(calc(var(--spinner-size) - var(--dot-size))); transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(calc(var(--spinner-size) - var(--dot-size))); } 70% { -webkit-transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(calc(var(--spinner-size) - var(--dot-size))); transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(calc(var(--spinner-size) - var(--dot-size))); } 75% { -webkit-transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(0); transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(0); } 95% { -webkit-transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(0); transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(0); } } @keyframes rotate { from { -webkit-transform: translateX(0) translateY(0); transform: translateX(0) translateY(0); } 20% { -webkit-transform: translateX(0) translateY(0); transform: translateX(0) translateY(0); } 25% { -webkit-transform: translateX(0) translateY(calc(var(--spinner-size) - var(--dot-size))); transform: translateX(0) translateY(calc(var(--spinner-size) - var(--dot-size))); } 45% { -webkit-transform: translateX(0) translateY(calc(var(--spinner-size) - var(--dot-size))); transform: translateX(0) translateY(calc(var(--spinner-size) - var(--dot-size))); } 50% { -webkit-transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(calc(var(--spinner-size) - var(--dot-size))); transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(calc(var(--spinner-size) - var(--dot-size))); } 70% { -webkit-transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(calc(var(--spinner-size) - var(--dot-size))); transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(calc(var(--spinner-size) - var(--dot-size))); } 75% { -webkit-transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(0); transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(0); } 95% { -webkit-transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(0); transform: translateX(calc(var(--spinner-size) - var(--dot-size))) translateY(0); } } .spinner { position: fixed; top: 50%; left: 50%; height: var(--spinner-size); width: var(--spinner-size); -webkit-transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%); } .spinner > .dot { position: absolute; top: 0; left: 0; height: 100%; width: 100%; -webkit-filter: url('#goo'); filter: url('#goo'); } .spinner > .dot:nth-of-type(1):before { -webkit-animation-delay: var(--delay); animation-delay: var(--delay); } .spinner > .dot:nth-of-type(2) { -webkit-transform: rotate(90deg); transform: rotate(90deg); } .spinner > .dot:nth-of-type(2):after { -webkit-animation-delay: calc(var(--duration) / 12); animation-delay: calc(var(--duration) / 12); } .spinner > .dot:nth-of-type(2):before { -webkit-animation-delay: calc(var(--duration) / 12 + var(--delay)); animation-delay: calc(var(--duration) / 12 + var(--delay)); } .spinner > .dot:nth-of-type(3) { -webkit-transform: rotate(180deg); transform: rotate(180deg); } .spinner > .dot:nth-of-type(3):after { -webkit-animation-delay: calc(var(--duration) / 6); animation-delay: calc(var(--duration) / 6); } .spinner > .dot:nth-of-type(3):before { -webkit-animation-delay: calc(var(--duration) / 6 + var(--delay)); animation-delay: calc(var(--duration) / 6 + var(--delay)); } .spinner > .dot:after { content: ''; position: absolute; top: 0; left: 0; background: #FFF; height: calc(var(--dot-size)); width: calc(var(--dot-size)); border-radius: 50%; -webkit-animation: rotate var(--duration) linear infinite; animation: rotate var(--duration) linear infinite; } .spinner > .dot:before { content: ''; position: absolute; top: 0; left: 0; background: rgba(255, 255, 255, .4); height: var(--dot-size); width: var(--dot-size); border-radius: 50%; -webkit-animation: rotate var(--duration) linear infinite; animation: rotate var(--duration) linear infinite; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div class='spinner'> <div class='dot'></div> <div class='dot'></div> <div class='dot'></div> </div> <svg> <defs> <filter id='goo'> <feGaussianBlur in='SourceGraphic' stdDeviation='8' result='blur' /> <feColorMatrix in='blur' mode='matrix' values=' 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 50 -8' result='goo' /> <feBlend in='SourceGraphic' in2='goo' /> </filter> </defs> </svg> |