├── .gitignore ├── Animation1 ├── check.svg ├── index.html ├── transition.js ├── style.css └── style.scss ├── Animation2 ├── index.html ├── transition.js ├── style.css └── style.scss └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.map 2 | -------------------------------------------------------------------------------- /Animation1/check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Animation2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Morpherings Example 2 5 | 6 | 7 | 8 |
9 |
10 | 12 | 14 | 15 | 17 |
18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Animation1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 |
9 |
10 |
11 |
12 | 13 |
16 |
19 | 21 |
22 |
23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Morpherings 2 | CSS3 Animations that causes buttons to morph into forms. A few lines of javascript is used for triggering. This is mostly a personal project I made for fun, but I can imagine it being useful in some situations. For example if you don't want to redirect the user to another page to sign up. Depending on your website layout it could be a bit too verbose to have a extensive form in the middle of the webiste, with these animations the form appears only when you want it to. Which allows you to have a less cluttered page. A smooth animation is quicker than loading a new page. 3 | 4 | ## Accessibility 5 | Having accessible forms is important. Therefore, I have done my best to make the forms accessible. Animation1 has been tested with JAWS, and seems to be working perfectly fine, however I am quite inexperienced with using screen readers so it might not be perfect! You may want to test it out yourself. Animation2 has aria tags(credits to [scottaohara](https://github.com/scottaohara) for helping with this) and should be quite accessible, although not perfect. 6 | ## GIFs 7 | 8 | ### Animation 1 9 | ![](https://i.imgur.com/iHLrJNG.gif) 10 | 11 | ### Animation 2 12 | ![](https://i.imgur.com/WWdKfdX.gif) 13 | -------------------------------------------------------------------------------- /Animation2/transition.js: -------------------------------------------------------------------------------- 1 | var loginEmail = document.getElementById("loginEmail"); 2 | var loginPassword = document.getElementById("loginPassword"); 3 | var loginButton = document.getElementById("loginButton"); 4 | 5 | function showLoginForm() { 6 | loginEmail.className = "input loginInput"; 7 | loginPassword.className = "input loginInput right"; 8 | 9 | loginEmail.value = ""; 10 | loginPassword.value = ""; 11 | 12 | loginButton.className += " loginButton-anim"; 13 | loginButton.blur(); 14 | 15 | // remove aria-hidden to mitigate any issues with screen readers 16 | // that have problems with aria-hidden=false 17 | loginEmail.removeAttribute("aria-hidden"); 18 | loginPassword.removeAttribute("aria-hidden"); 19 | 20 | // remove tabindex=-1 (which is necessary so keyboard focus can't navigate 21 | // to the visually hidden fields prior to the form fields expanding) 22 | loginEmail.removeAttribute('tabindex'); 23 | loginPassword.removeAttribute('tabindex'); 24 | 25 | // set focus to the email field so that keyboard users don't have to navigate 26 | // backwards in the DOM to get to the start of the login fields. 27 | loginEmail.focus(); 28 | 29 | 30 | // Now that the login button has expanded the fields, change the 31 | // button's label to "submit" to indicate it no longer does the same 32 | // action as before. Remove the onclick because it's already expanded, 33 | // and after the animation has occurred, set to type=submit so that 34 | // the button can be used to submit the form. 35 | loginButton.value = "Submit"; 36 | loginButton.removeAttribute('onclick'); 37 | 38 | setTimeout(function () { 39 | loginButton.type = "submit"; 40 | }, 100); 41 | } 42 | -------------------------------------------------------------------------------- /Animation1/transition.js: -------------------------------------------------------------------------------- 1 | var emailbox = document.getElementById("email"); 2 | var passwordbox = document.getElementById("password"); 3 | var button = document.getElementById("submit"); 4 | 5 | function registerClick() { 6 | emailbox.className = "input email"; 7 | emailbox.placeholder = "smith@example.org"; 8 | emailbox.value = ""; 9 | emailbox.readOnly = false; 10 | 11 | // Accessibility 12 | emailbox.setAttribute("role", "textbox"); 13 | emailbox.type = "email"; 14 | emailbox.setAttribute("aria-label", "enter email address"); 15 | passwordbox.setAttribute("aria-hidden", "false"); 16 | button.setAttribute("aria-hidden", "false"); 17 | 18 | passwordbox.className += " password-anim"; 19 | button.className += " button-anim"; 20 | } 21 | 22 | function submitForm() { 23 | passwordbox.className += " password-anim-reverse"; 24 | button.className += " button-anim-reverse"; 25 | emailbox.className += " email-revert"; 26 | emailbox.placeholder = ""; 27 | emailbox.value = ""; 28 | 29 | var loadingCircles = document.getElementById("loadingCircles"); 30 | setTimeout(function() { 31 | loadingCircles.style.display = "block" 32 | }, 620) 33 | 34 | setTimeout(function() { 35 | emailbox.value = "Register"; 36 | 37 | var registerForm = document.getElementById("registerForm"); 38 | registerForm.innerHTML = "

Account created. Check your email.

" 39 | registerForm.setAttribute("aria-live", "assertive"); 40 | registerForm.fontAlign = "center"; 41 | 42 | document.getElementById("resultText").className += " showText"; 43 | }, 2620); 44 | } 45 | -------------------------------------------------------------------------------- /Animation2/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #303F9F; 3 | } 4 | 5 | form { 6 | display: flex; 7 | justify-content: flex-end; 8 | } 9 | 10 | #loginForm { 11 | position: relative; 12 | color: white; 13 | font-family: Arial; 14 | } 15 | 16 | .input { 17 | width: 220px; 18 | height: 35px; 19 | margin: 4px 0px; 20 | margin-left: 5px; 21 | padding: 5px 7px; 22 | color: #7C8A99; 23 | background-color: white; 24 | border: 0px solid #9CAAB9; 25 | border-bottom-width: 2px; 26 | border-right-width: 2px; 27 | border-radius: 7px; 28 | outline: 0; 29 | transition: .425s all ease; 30 | display: inline-block; 31 | } 32 | 33 | .button { 34 | width: 105px; 35 | height: 35px; 36 | margin-top: 4px; 37 | margin-left: 8px; 38 | background-color: #388E3C; 39 | color: white; 40 | border: 0px solid #2E7D32; 41 | border-bottom-width: 2px; 42 | border-right-width: 2px; 43 | border-radius: 10px; 44 | cursor: pointer; 45 | position: relative; 46 | z-index: 20; 47 | } 48 | 49 | .button:hover, 50 | .button:focus { 51 | background-color: #2E7D32; 52 | } 53 | 54 | .fake-button { 55 | background-color: #2E7D32; 56 | position: relative; 57 | z-index: 5; 58 | } 59 | 60 | #loginButton { 61 | margin-left: -105px; 62 | } 63 | 64 | .fake-button.right { 65 | width: 52.5px; 66 | border-bottom-left-radius: 0; 67 | border-top-left-radius: 0; 68 | border-left: 0; 69 | margin-left: 0; 70 | text-align: left; 71 | padding: 0; 72 | } 73 | 74 | .fake-button.left { 75 | width: 52.5px; 76 | border-bottom-right-radius: 0; 77 | border-top-right-radius: 0; 78 | border-right: 0; 79 | margin-right: 0; 80 | text-align: right; 81 | padding: 0; 82 | } 83 | 84 | .loginInput { 85 | position: relative; 86 | z-index: 5; 87 | } 88 | 89 | .loginInput:focus { 90 | box-shadow: 0 0 1px 2px #66d9ef; 91 | } 92 | 93 | .loginButton-anim { 94 | animation: login-button-anim 0.5s; 95 | animation-fill-mode: forwards; 96 | animation-delay: 0.425s; 97 | z-index: 0; 98 | opacity: 0; 99 | margin-left: -109px; 100 | } 101 | 102 | @keyframes login-button-anim { 103 | from { 104 | opacity: 0; 105 | margin-left: -105px; 106 | } 107 | 1% { 108 | opacity: 1; 109 | } 110 | to { 111 | opacity: 1; 112 | margin-left: 4px; 113 | } 114 | } 115 | 116 | 117 | 118 | /*# sourceMappingURL=style.css.map */ 119 | -------------------------------------------------------------------------------- /Animation2/style.scss: -------------------------------------------------------------------------------- 1 | $input-width: 220px; 2 | $input-height: 35px; 3 | $input-margin: 4px; 4 | $button-width: 105px; 5 | $button-hover-color: #2E7D32; 6 | $background-color: #303F9F; 7 | 8 | body { 9 | background-color: $background-color; 10 | } 11 | 12 | form { 13 | display: flex; 14 | justify-content: flex-end; 15 | } 16 | 17 | #loginForm { 18 | position: relative; 19 | color: white; 20 | font-family: Arial; 21 | } 22 | 23 | .input { 24 | width: $input-width; 25 | height: $input-height; 26 | margin: $input-margin 0px; 27 | margin-left: 5px; 28 | padding: 5px 7px; 29 | 30 | color: #7C8A99; 31 | background-color: white; 32 | border: 0px solid #9CAAB9; 33 | border-bottom-width: 2px; 34 | border-right-width: 2px; 35 | border-radius: 7px; 36 | 37 | outline: 0; 38 | transition: .425s all ease; 39 | display: inline-block; 40 | } 41 | 42 | 43 | .button { 44 | width: $button-width; 45 | height: $input-height; 46 | margin-top: $input-margin; 47 | margin-left: 8px; 48 | 49 | background-color: #388E3C; 50 | color: white; 51 | 52 | border: 0px solid #2E7D32; 53 | border-bottom-width: 2px; 54 | border-right-width: 2px; 55 | border-radius: 10px; 56 | cursor: pointer; 57 | 58 | position: relative; 59 | z-index: 20; 60 | } 61 | 62 | .button:hover, 63 | .button:focus { 64 | background-color: $button-hover-color; 65 | } 66 | 67 | .fake-button { 68 | background-color: $button-hover-color; 69 | position: relative; 70 | z-index: 5; 71 | } 72 | 73 | #loginButton { 74 | margin-left: $button-width * -1; 75 | } 76 | 77 | .fake-button.right { 78 | width: $button-width / 2; 79 | border-bottom-left-radius: 0; 80 | border-top-left-radius: 0; 81 | border-left: 0; 82 | margin-left: 0; 83 | text-align: left; 84 | padding: 0; 85 | } 86 | 87 | .fake-button.left { 88 | width: $button-width / 2; 89 | border-bottom-right-radius: 0; 90 | border-top-right-radius: 0; 91 | border-right: 0; 92 | margin-right: 0; 93 | text-align: right; 94 | padding: 0; 95 | } 96 | 97 | .loginInput { 98 | position: relative; 99 | z-index: 5; 100 | } 101 | 102 | .loginInput:focus { 103 | box-shadow: 0 0 1px 2px #66d9ef; 104 | } 105 | 106 | .loginButton-anim { 107 | animation: login-button-anim 0.5s; 108 | animation-fill-mode: forwards; 109 | animation-delay: 0.425s; 110 | 111 | z-index: 0; 112 | opacity: 0; 113 | margin-left: ($button-width + $input-margin) * -1; 114 | } 115 | 116 | @keyframes login-button-anim { 117 | from { opacity: 0; margin-left: ($button-width) *-1; } 118 | 1% { opacity: 1; } 119 | to { opacity: 1; margin-left: $input-margin; } 120 | } 121 | -------------------------------------------------------------------------------- /Animation1/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #303F9F; } 3 | 4 | #registerForm { 5 | width: 305px; 6 | height: 300px; 7 | margin: 70px; 8 | position: relative; 9 | color: white; 10 | font-family: Arial; 11 | text-align: center; } 12 | 13 | .input { 14 | width: 305px; 15 | height: 35px; 16 | margin: 4px 0px; 17 | padding: 5px 7px; 18 | color: #7C8A99; 19 | background-color: white; 20 | border: 0px solid #9CAAB9; 21 | border-bottom-width: 2px; 22 | border-right-width: 2px; 23 | border-radius: 7px; 24 | outline: 0; 25 | transition: .325s all ease; } 26 | 27 | .password { 28 | margin-top: -39px; 29 | display: none; } 30 | 31 | input { 32 | box-shadow: none; } 33 | 34 | .button { 35 | margin-top: -15; 36 | display: none; } 37 | 38 | .fake-button { 39 | margin-top: 4px; 40 | text-align: center; 41 | cursor: pointer; 42 | float: left; 43 | display: block; 44 | margin-left: 50%; 45 | transform: translateX(-50%); } 46 | 47 | .email { 48 | margin-left: calc(50% + -1px); 49 | transform: translateX(-50%); 50 | z-index: 100; 51 | position: relative; } 52 | 53 | .password-anim { 54 | animation: move-password-box 0.35s ease-in-out; 55 | animation-fill-mode: forwards; 56 | animation-delay: 0.3s; 57 | display: block; 58 | opacity: 0; 59 | z-index: 25; } 60 | 61 | .button-anim { 62 | animation: move-button 0.25s ease-in-out; 63 | animation-fill-mode: forwards; 64 | animation-delay: 0.7s; 65 | display: block; 66 | opacity: 0; 67 | z-index: 20; } 68 | 69 | .password-anim-reverse { 70 | animation: move-password-box-reverse 0.35s ease-in-out; 71 | animation-fill-mode: forwards; } 72 | 73 | .button-anim-reverse { 74 | animation: move-button-reverse 0.25s ease-in-out; 75 | animation-fill-mode: forwards; } 76 | 77 | .email-revert { 78 | animation: revert-email-box 0.4s ease-in-out; 79 | animation-fill-mode: forwards; 80 | animation-delay: 0.3s; 81 | background-color: #ffffff; 82 | border: 0; } 83 | 84 | .button { 85 | width: 140px; 86 | height: 35px; 87 | background-color: #388E3C; 88 | color: white; 89 | border: 0px solid #2E7D32; 90 | border-bottom-width: 2px; 91 | border-right-width: 2px; 92 | border-radius: 10px; 93 | float: right; 94 | cursor: pointer; } 95 | 96 | .button:hover { 97 | background-color: #2E7D32; } 98 | 99 | @keyframes move-password-box { 100 | from { 101 | transform: translateY(0); 102 | opacity: 1; } 103 | to { 104 | transform: translateY(43px); 105 | opacity: 1; } } 106 | @keyframes move-button { 107 | from { 108 | transform: translateY(0); 109 | opacity: 1; } 110 | to { 111 | transform: translateY(43px); 112 | opacity: 1; } } 113 | @keyframes move-password-box-reverse { 114 | to { 115 | transform: translateY(0); 116 | opacity: 0; } 117 | 99% { 118 | opacity: 1; } 119 | from { 120 | transform: translateY(43px); 121 | opacity: 1; } } 122 | @keyframes move-button-reverse { 123 | to { 124 | transform: translateY(-43px); 125 | opacity: 0; } 126 | 20% { 127 | transform: translateY(-43px); 128 | opacity: 0; } 129 | 99% { 130 | opacity: 1; } 131 | from { 132 | transform: translateY(43px); 133 | opacity: 1; } } 134 | @keyframes revert-email-box { 135 | 0% { 136 | width: 305px; 137 | background-color: #ffffff; } 138 | 100% { 139 | width: 30px; 140 | opacity: 0; 141 | border-radius: 100px; 142 | background-color: #000000; } } 143 | /* Loading Circle */ 144 | .loadingCircle { 145 | position: absolute; 146 | background-color: black; 147 | border-radius: 180px; } 148 | 149 | #loadingCircles { 150 | display: none; 151 | position: absolute; 152 | width: 30px; 153 | height: 30px; 154 | top: 4px; 155 | margin-left: 50%; 156 | transform: translateX(-50%); } 157 | 158 | #loadingCircle1 { 159 | width: 30px; 160 | height: 30px; 161 | background-color: black; 162 | border-radius: 180px; 163 | opacity: 0.5; 164 | animation: loading-circle 1.5s; 165 | animation-iteration-count: infinite; } 166 | 167 | #loadingCircle2 { 168 | width: 20px; 169 | height: 20px; 170 | background-color: black; 171 | border-radius: 180px; 172 | opacity: 0.3; 173 | top: 5px; 174 | left: 5px; 175 | animation-iteration-count: infinite; 176 | animation-delay: 0.75s; } 177 | 178 | @keyframes loading-circle { 179 | 0% { 180 | transform: scale(1); } 181 | 50% { 182 | transform: scale(0.66); } 183 | 100% { 184 | transform: scale(1); } } 185 | @keyframes loading-circle2 { 186 | 0% { 187 | transform: scale(1); } 188 | 50% { 189 | transform: scale(0); } 190 | 100% { 191 | transform: scale(1); } } 192 | .check { 193 | width: 20px; 194 | height: 20px; 195 | margin-top: 10px; } 196 | 197 | .result { 198 | transition: .3s ease opacity; } 199 | 200 | /*# sourceMappingURL=style.css.map */ 201 | -------------------------------------------------------------------------------- /Animation1/style.scss: -------------------------------------------------------------------------------- 1 | $input-width: 305px; 2 | $input-height: 35px; 3 | $input-margin: 4px; 4 | $background-color: #303F9F; 5 | 6 | body { 7 | background-color: $background-color; 8 | } 9 | 10 | #registerForm { 11 | width: $input-width; 12 | height: 300px; 13 | margin: 70px; 14 | position: relative; 15 | color: white; 16 | font-family: Arial; 17 | text-align: center; 18 | } 19 | 20 | .input { 21 | width: $input-width; 22 | height: $input-height; 23 | margin: $input-margin 0px; 24 | padding: 5px 7px; 25 | 26 | color: #7C8A99; 27 | background-color: white; 28 | border: 0px solid #9CAAB9; 29 | border-bottom-width: 2px; 30 | border-right-width: 2px; 31 | border-radius: 7px; 32 | 33 | outline: 0; 34 | transition: .325s all ease; 35 | } 36 | 37 | 38 | .password { 39 | margin-top: ($input-height + $input-margin) * -1; 40 | display: none; 41 | } 42 | 43 | input { 44 | box-shadow: none; 45 | } 46 | 47 | .button { 48 | margin-top: -15; 49 | display: none; 50 | } 51 | 52 | .fake-button { 53 | margin-top: $input-margin; 54 | text-align: center; 55 | cursor: pointer; 56 | float: left; 57 | display: block; 58 | margin-left: 50%; 59 | transform: translateX(-50%); 60 | } 61 | 62 | .email { 63 | margin-left: calc(50% + -1px); 64 | transform: translateX(-50%); 65 | z-index: 100; 66 | position: relative; 67 | } 68 | 69 | .password-anim { 70 | animation: move-password-box 0.35s ease-in-out; 71 | animation-fill-mode: forwards; 72 | animation-delay: 0.3s; 73 | display: block; 74 | opacity: 0; 75 | z-index: 25; 76 | } 77 | 78 | .button-anim { 79 | animation: move-button 0.25s ease-in-out; 80 | animation-fill-mode: forwards; 81 | animation-delay: 0.7s; 82 | display: block; 83 | opacity: 0; 84 | z-index: 20; 85 | } 86 | 87 | .password-anim-reverse { 88 | animation: move-password-box-reverse 0.35s ease-in-out; 89 | animation-fill-mode: forwards; 90 | } 91 | 92 | .button-anim-reverse { 93 | animation: move-button-reverse 0.25s ease-in-out; 94 | animation-fill-mode: forwards; 95 | } 96 | 97 | .email-revert { 98 | animation: revert-email-box 0.4s ease-in-out; 99 | animation-fill-mode: forwards; 100 | animation-delay: 0.3s; 101 | background-color: #ffffff; 102 | border: 0; 103 | } 104 | 105 | .button { 106 | width: 140px; 107 | height: $input-height; 108 | 109 | background-color: #388E3C; 110 | color: white; 111 | 112 | border: 0px solid #2E7D32; 113 | border-bottom-width: 2px; 114 | border-right-width: 2px; 115 | border-radius: 10px; 116 | float: right; 117 | cursor: pointer; 118 | } 119 | 120 | .button:hover { 121 | background-color: #2E7D32; 122 | } 123 | 124 | @keyframes move-password-box { 125 | from { 126 | transform: translateY(0); 127 | opacity: 1; 128 | } 129 | to { 130 | transform: translateY($input-height + $input-margin * 2); 131 | opacity: 1; 132 | } 133 | } 134 | 135 | @keyframes move-button { 136 | from { 137 | transform: translateY(0); 138 | opacity: 1; 139 | } 140 | to { 141 | transform: translateY($input-height + $input-margin * 2); 142 | opacity: 1; 143 | } 144 | } 145 | 146 | @keyframes move-password-box-reverse { 147 | to { 148 | transform: translateY(0); 149 | opacity: 0; 150 | } 151 | 99% { opacity: 1; } 152 | from { 153 | transform: translateY($input-height + $input-margin * 2); 154 | opacity: 1; 155 | } 156 | } 157 | 158 | @keyframes move-button-reverse { 159 | to { 160 | transform: translateY(($input-height + $input-margin + 4px) * -1); 161 | opacity: 0; 162 | } 163 | 20% { 164 | transform: translateY(($input-height + $input-margin + 4px) * -1); 165 | opacity: 0; 166 | } 167 | 99% { opacity: 1; } 168 | from { 169 | transform: translateY($input-height + $input-margin * 2); 170 | opacity: 1; 171 | } 172 | } 173 | 174 | @keyframes revert-email-box { 175 | 0% { width: $input-width; background-color: #ffffff; } 176 | 100% { 177 | width: 30px; 178 | opacity: 0; 179 | border-radius: 100px; 180 | background-color: #000000; 181 | } 182 | } 183 | 184 | 185 | /* Loading Circle */ 186 | 187 | .loadingCircle { 188 | position: absolute; 189 | background-color: black; 190 | border-radius: 180px; 191 | } 192 | 193 | #loadingCircles { 194 | display: none; 195 | position: absolute; 196 | width: 30px; 197 | height: 30px; 198 | 199 | top: $input-margin; 200 | 201 | margin-left: 50%; 202 | transform: translateX(-50%); 203 | } 204 | 205 | #loadingCircle1 { 206 | width: 30px; 207 | height: 30px; 208 | background-color: black; 209 | border-radius: 180px; 210 | opacity: 0.5; 211 | 212 | animation: loading-circle 1.5s; 213 | animation-iteration-count: infinite; 214 | } 215 | 216 | #loadingCircle2 { 217 | width: 20px; 218 | height: 20px; 219 | background-color: black; 220 | border-radius: 180px; 221 | opacity: 0.3; 222 | 223 | top: 5px; 224 | left: 5px; 225 | 226 | animation-iteration-count: infinite; 227 | animation-delay: 0.75s; 228 | } 229 | 230 | 231 | @keyframes loading-circle { 232 | 0% { 233 | transform: scale(1.0); 234 | } 235 | 50% { 236 | transform: scale(0.66); 237 | } 238 | 100% { 239 | transform: scale(1.0); 240 | } 241 | } 242 | 243 | @keyframes loading-circle2 { 244 | 0% { 245 | transform: scale(1.0); 246 | } 247 | 50% { 248 | transform: scale(0.0); 249 | } 250 | 100% { 251 | transform: scale(1.0); 252 | } 253 | } 254 | 255 | .check { 256 | width: 20px; 257 | height: 20px; 258 | margin-top: 10px; 259 | } 260 | 261 | .resultText { 262 | opacity: 0; 263 | transition: .3s ease opacity; 264 | } 265 | .showText { 266 | opacity: 1; 267 | } 268 | --------------------------------------------------------------------------------