Анимированная кнопка загрузки на CSS3 и Javascript
Стильная кнопочка с анимацией прогресса загрузки на CSS3 и Javascript
Для начала посмотрите ДЕМО
Установка:
1#: В самый низ вашего CSS вставьте:
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 |
.upload-btn { --dur: 0.25s; background: #255ff4; border-radius: 1.25em; color: #fff; cursor: pointer; padding: 0.5em 1em; position: relative; text-align: center; transition: all 0.1s linear; width: 6em; -webkit-tap-highlight-color: #0000; -webkit-appearance: none; appearance: none; } .upload-btn:disabled { cursor: not-allowed; } .upload-btn:not(:disabled):focus, .upload-btn:not(:disabled):hover { background: #0b46da; } .upload-btn:focus { outline: transparent; } .upload-btn-border { display: block; overflow: visible; pointer-events: none; position: absolute; top: 0; left: 0; width: 100%; height: auto; } .upload-btn-border rect { stroke: var(--stroke); } .upload-btn-text { display: inline-block; } .upload-btn-running { text-align: right; } .upload-btn-running .upload-btn-text { animation: flyIn2 var(--dur) ease-in forwards; } .upload-btn-done .upload-btn-border { animation: sinkInA var(--dur) ease-in forwards; } .upload-btn-done .upload-btn-border rect { animation: sinkInB var(--dur) ease-in forwards; } .upload-btn-done .upload-btn-text { animation: pulseIn var(--dur) linear forwards; color: var(--success); } .upload-btn-ready .upload-btn-text { animation: flyIn1 var(--dur) ease-in forwards; } /* Dark theme */ @media (prefers-color-scheme: dark) { :root { --bg: #17181c; --fg: #e3e4e8; } } /* Animations */ @keyframes flyIn1 { from { opacity: 0; transform: translateY(33%); } to { opacity: 1; transform: translateY(0); } } @keyframes flyIn2 { from { opacity: 0; /* (buttonWidth / 2 - rightPadding) + (lastDigit + "%") */ transform: translate(calc(-2em + 2ch),33%); } to { opacity: 1; transform: translate(calc(-2em + 2ch),0); } } @keyframes pulseIn { from { transform: scale(0); } 33% { transform: scale(2.17,2.17); } 67% { transform: scale(1.17,1.17); } to { transform: scale(1.5); } } @keyframes sinkInA { from { transform: scale(1,1); } 25%, to { /* 120/124, 50/54 */ transform: scale(0.968,0.925); } } @keyframes sinkInB { from { stroke-width: 4; } 25%, to { stroke-width: 0; } } |
2#: Между тегами <body> и </body> вставьте:
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 |
<button id="upload" class="upload-btn" type="button"> <svg class="upload-btn-border" xmlns="http://www.w3.org/2000/svg" width="120px" height="50px" viewBox="0 0 120 50" role="presentation"> <rect x="-2" y="-2" width="124" height="54" rx="27" ry="27" fill="none" stroke="#000" stroke-width="4" stroke-dasharray="0 310" opacity="0" /> </svg> <span class="upload-btn-text">Upload</span> </button> <script id="rendered-js" > document.addEventListener("DOMContentLoaded", function () { let upload = document.getElementById("upload"); if (upload) { let progress = 0, strokeLen = 310, startUpload = function (progressRect, elText) { progress = 0; let btnText = this.querySelector(elText); if (btnText) btnText.innerHTML = "0%"; this.disabled = true; this.classList.remove("upload-btn-ready"); this.classList.add("upload-btn-running"); setTimeout(incProgress.bind(this, progressRect, elText), 500); }, incProgress = function (progressRect, elText) { let btnProgress = this.querySelector(progressRect), btnText = this.querySelector(elText); if (progress < 1) { if (btnProgress) { let strokeVal = progress * strokeLen, dashVal = strokeLen - strokeVal; btnProgress.setAttribute("stroke-dasharray", `${strokeVal} ${dashVal}`); btnProgress.setAttribute("opacity", "1"); } if (btnText) { let displayVal = Math.round(progress * 100); btnText.innerHTML = `${displayVal}%`; } progress += 0.005; let interval = 17; setTimeout(incProgress.bind(this, progressRect, elText), interval); } else { this.classList.remove("upload-btn-running"); this.classList.add("upload-btn-done"); if (btnProgress) btnProgress.setAttribute("stroke-dasharray", `${strokeLen} 0`); if (btnText) btnText.innerHTML = "✓"; let timeout = 1500; setTimeout(resetUpload.bind(this, progressRect, elText), timeout); } }, resetUpload = function (progressRect, elText) { this.classList.remove("upload-btn-done"); this.classList.add("upload-btn-ready"); this.disabled = false; let btnProgress = this.querySelector(progressRect), btnText = this.querySelector(elText); if (btnProgress) { btnProgress.setAttribute("stroke-dasharray", `0 ${strokeLen}`); btnProgress.setAttribute("opacity", "0"); } if (btnText) btnText.innerHTML = "Upload"; }; upload.addEventListener("click", startUpload.bind( upload, ".upload-btn-border rect", ".upload-btn-text")); } }); //# sourceURL=pen.js </script> |