Turn airplane mode on and off! inspired by a Dribbble shot: https://dribbble.com/shots/9748924-Airplane-Mode-Toggle
A Pen by Kiarash Zarinmehr on CodePen.
Turn airplane mode on and off! inspired by a Dribbble shot: https://dribbble.com/shots/9748924-Airplane-Mode-Toggle
A Pen by Kiarash Zarinmehr on CodePen.
| <div class="switch"> | |
| <div class="switch__button"> | |
| <svg | |
| xmlns="http://www.w3.org/2000/svg" | |
| class="airplane" | |
| viewBox="0 0 140.351 139.63" | |
| > | |
| <path fill="var(--color-off)" d="M45.851,139.316s13.2-12.046,11.842-49.753c-41.162-3.584-41.285-3.448-41.285-3.448L10.1,97.9H0L7.725,69.815h0L0,41.729H10.1l6.308,11.785s.123.136,41.285-3.449C59.047,12.359,45.851.314,45.851.314s15.674-.706,17.187,0c.364.169,2.2,3.17,4.789,7.635H82.858a6,6,0,0,1,0,12H74.635c1.651,2.949,3.352,6.007,5.009,9h21.213a6,6,0,1,1,0,12h-14.6C89.473,46.806,91.7,50.9,91.7,50.9s15.527.144,31.431,1.838S140.347,69.48,140.347,69.48v.32c0,.01,0,.02,0,.031l0,.206s-1.31,15.163-17.215,16.856S91.7,88.73,91.7,88.73s-2.228,4.093-5.442,9.95h14.6a6,6,0,1,1,0,12H79.645c-1.658,2.993-3.358,6.051-5.009,9h8.222a6,6,0,1,1,0,12H67.828c-2.587,4.465-4.426,7.465-4.79,7.636a22.453,22.453,0,0,1-5.128.313C52.817,139.63,45.851,139.316,45.851,139.316Z" | |
| /> | |
| </svg> | |
| <svg | |
| xmlns="http://www.w3.org/2000/svg" | |
| class="airplane -on" | |
| viewBox="0 0 140.351 139.63" | |
| > | |
| <path fill="var(--color-on)" d="M45.851,139.316s13.2-12.046,11.842-49.753c-41.162-3.584-41.285-3.448-41.285-3.448L10.1,97.9H0L7.725,69.815h0L0,41.729H10.1l6.308,11.785s.123.136,41.285-3.449C59.047,12.359,45.851.314,45.851.314s15.674-.706,17.187,0c.364.169,2.2,3.17,4.789,7.635H82.858a6,6,0,0,1,0,12H74.635c1.651,2.949,3.352,6.007,5.009,9h21.213a6,6,0,1,1,0,12h-14.6C89.473,46.806,91.7,50.9,91.7,50.9s15.527.144,31.431,1.838S140.347,69.48,140.347,69.48v.32c0,.01,0,.02,0,.031l0,.206s-1.31,15.163-17.215,16.856S91.7,88.73,91.7,88.73s-2.228,4.093-5.442,9.95h14.6a6,6,0,1,1,0,12H79.645c-1.658,2.993-3.358,6.051-5.009,9h8.222a6,6,0,1,1,0,12H67.828c-2.587,4.465-4.426,7.465-4.79,7.636a22.453,22.453,0,0,1-5.128.313C52.817,139.63,45.851,139.316,45.851,139.316Z" | |
| /> | |
| </svg> | |
| </div> | |
| <div class="airport-wrapper"> | |
| <div class="airport"> | |
| <div class="airport__lightLine"> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| </div> | |
| <div class="airport__airstrip"> | |
| <div class="airport__lineContainer"> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| <div class="airport__line"></div> | |
| </div> | |
| </div> | |
| <div class="airport__lightLine"> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| <div class="airport__light"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="sky"> | |
| <div class="cloud-line"> | |
| <div class="cloud-container"> | |
| <div class="cloud"> | |
| <div class="cloud__shape"></div> | |
| <div class="cloud__shape"></div> | |
| </div> | |
| <div class="cloud"> | |
| <div class="cloud__shape"></div> | |
| <div class="cloud__shape"></div> | |
| </div> | |
| <div class="cloud"> | |
| <div class="cloud__shape"></div> | |
| <div class="cloud__shape"></div> | |
| </div> | |
| <div class="cloud"> | |
| <div class="cloud__shape"></div> | |
| <div class="cloud__shape"></div> | |
| </div> | |
| <div class="cloud"> | |
| <div class="cloud__shape"></div> | |
| <div class="cloud__shape"></div> | |
| </div> | |
| </div> | |
| <div class="cloud-container"> | |
| <div class="cloud"> | |
| <div class="cloud__shape"></div> | |
| <div class="cloud__shape"></div> | |
| </div> | |
| <div class="cloud"> | |
| <div class="cloud__shape"></div> | |
| <div class="cloud__shape"></div> | |
| </div> | |
| <div class="cloud"> | |
| <div class="cloud__shape"></div> | |
| <div class="cloud__shape"></div> | |
| </div> | |
| <div class="cloud"> | |
| <div class="cloud__shape"></div> | |
| <div class="cloud__shape"></div> | |
| </div> | |
| <div class="cloud"> | |
| <div class="cloud__shape"></div> | |
| <div class="cloud__shape"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> |
| const switchContainer = document.querySelector('.switch'); | |
| const airplanes = switchContainer.querySelectorAll('.airplane'); | |
| const switchButton = switchContainer.querySelector('.switch__button'); | |
| const cloudLine = document.querySelector('.cloud-line'); | |
| const sky = document.querySelector('.sky'); | |
| const airport = document.querySelector('.airport'); | |
| const remSize = parseFloat(getComputedStyle(document.documentElement).fontSize); | |
| const getStyleVariable = (property, element = document.documentElement) => { | |
| return getComputedStyle(element).getPropertyValue(`--${property}`); | |
| }; | |
| const animateClouds = (() => { | |
| const cloudFinalX = -cloudLine.children[0].clientWidth; | |
| const cloudTimeline = gsap.timeline({ repeat: -1 }); | |
| cloudTimeline.to(cloudLine, 4, { x: cloudFinalX, duration: 2, ease: 'none' }); | |
| })(); | |
| let isAnimating = false; | |
| const switchButtonFinalX = | |
| switchContainer.clientWidth - switchButton.clientWidth; | |
| const airplanesFinalX = | |
| airplanes[0].clientWidth + | |
| switchButton.clientWidth / 2 - | |
| airplanes[0].clientWidth / 2; | |
| const airplanesInitialX = | |
| -1 * (switchButton.clientWidth / 2 - airplanes[0].clientWidth / 2); | |
| const toggleAnimation = isOn => { | |
| const ease = 'power2.inOut'; | |
| const duration = 0.5; | |
| const nextState = isOn ? 'off' : 'on'; | |
| const background = getStyleVariable(`color-background-${nextState}`); | |
| const boxShadow = getStyleVariable(`shadow-${nextState}`); | |
| const switchButtonX = isOn ? 0 : switchButtonFinalX; | |
| const airplanesX = isOn ? airplanesInitialX : airplanesFinalX; | |
| const airportX = isOn ? -110 : -20; | |
| const opacity = isOn ? 0 : 1; | |
| gsap.to(document.body, duration, { background, ease }); | |
| gsap.to(switchContainer, duration, { boxShadow, ease }); | |
| gsap.to(switchButton, duration, { | |
| x: switchButtonX, | |
| ease | |
| }); | |
| gsap.to(airplanes, duration, { | |
| x: airplanesX, | |
| ease | |
| }); | |
| gsap.to(airport, duration, { | |
| x: airportX, | |
| ease | |
| }); | |
| gsap.to(sky, duration, { | |
| opacity, | |
| ease, | |
| onComplete() { | |
| isAnimating = false; | |
| } | |
| }); | |
| }; | |
| const configOn = { | |
| background: getStyleVariable('color-background-on'), | |
| shadow: getStyleVariable('shadow-on'), | |
| opacity: 1, | |
| switchButtonX: switchButtonFinalX, | |
| airplanesX: airplanesFinalX | |
| }; | |
| const toggleSwitch = ({ currentTarget }) => { | |
| if (isAnimating) return; | |
| isAnimating = true; | |
| const isCurrentlyOn = currentTarget.classList.contains('-on'); | |
| currentTarget.classList.toggle('-on'); | |
| toggleAnimation(isCurrentlyOn); | |
| }; | |
| switchContainer.addEventListener('click', toggleSwitch); |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.0.5/gsap.min.js"></script> |
| *, *::after, *::before { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| :root { | |
| --color-background-off: #4e4e4e; | |
| --color-off: #494949; | |
| --shadow-off: 0 1.2rem 1.5rem #4d4d4d; | |
| --color-background-on: #2f86d5; | |
| --color-on: #1AB1FD; | |
| --shadow-on: 0 1.2rem 1.5rem #2c82cc; | |
| font-size: 62.5%; | |
| } | |
| html, body { | |
| height: 100%; | |
| } | |
| body { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| background: var(--color-background-off); | |
| overflow: hidden; | |
| } | |
| .switch { | |
| --switch-width: 31.1rem; | |
| --switch-height: 13.8rem; | |
| width: var(--switch-width); | |
| height: var(--switch-height); | |
| border-radius: 10rem; | |
| box-shadow: var(--shadow-off); | |
| position: relative; | |
| cursor: pointer; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| .switch__button { | |
| width: var(--switch-height); | |
| height: var(--switch-height); | |
| border-radius: 50%; | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| z-index: 1; | |
| overflow: hidden; | |
| background: #fff; | |
| z-index: 3; | |
| } | |
| .airplane { | |
| position: absolute; | |
| top: 50%; | |
| width: calc(var(--switch-height) / 2); | |
| height: calc(var(--switch-height) / 2); | |
| } | |
| .airplane:not(.-on) { | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| } | |
| .airplane.-on { | |
| transform: translateY(-50%); | |
| right: 100%; | |
| } | |
| /* Airport Background */ | |
| .airport-wrapper { | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| width: 100%; | |
| height: 100%; | |
| border-radius: inherit; | |
| background: #848484; | |
| overflow: hidden; | |
| } | |
| .airport-wrapper::before, .airport-wrapper::after { | |
| content: ""; | |
| position: absolute; | |
| width: 100%; | |
| height: 0.5rem; | |
| background: #bebebe; | |
| z-index: 1; | |
| } | |
| .airport-wrapper::before { | |
| top: 18%; | |
| } | |
| .airport-wrapper::after { | |
| bottom: 18%; | |
| } | |
| .airport { | |
| --light-size: 0.6rem; | |
| --line-size: 1.5rem; | |
| width: 100%; | |
| height: 100%; | |
| border-radius: inherit; | |
| display: flex; | |
| flex-direction: column; | |
| background: #848484; | |
| } | |
| .airport__lightLine { | |
| height: 18%; | |
| display: flex; | |
| align-items: center; | |
| padding-left: 3.1rem; | |
| width: 200%; | |
| } | |
| .airport__light { | |
| width: var(--light-size); | |
| height: var(--light-size); | |
| border-radius: 50%; | |
| background: #f7bd00; | |
| } | |
| .airport__light:not(:last-child) { | |
| margin-right: 3rem; | |
| } | |
| .airport__airstripWrapper { | |
| border-top: 0.5rem solid #bebebe; | |
| border-bottom: 0.5rem solid #bebebe; | |
| } | |
| .airport__airstrip { | |
| height: 64%; | |
| display: flex; | |
| } | |
| .airport__lineContainer { | |
| display: flex; | |
| align-items: center; | |
| height: 100%; | |
| margin-left: -0.4rem; | |
| } | |
| .airport__line { | |
| width: var(--line-size); | |
| height: 0.5rem; | |
| background: #fff; | |
| } | |
| .airport__line:not(:last-child) { | |
| margin-right: 2.1rem; | |
| } | |
| /* Sky Background */ | |
| .sky { | |
| width: 100%; | |
| height: 100%; | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| border-radius: inherit; | |
| background: #78c7fe; | |
| opacity: 0; | |
| z-index: 2; | |
| overflow: hidden; | |
| } | |
| .cloud-line { | |
| width: 100%; | |
| height: 100%; | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| } | |
| .cloud-container { | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| .cloud-container:last-child { | |
| left: 100%; | |
| } | |
| .cloud { | |
| width: 3rem; | |
| height: 1rem; | |
| position: absolute; | |
| background: #fff; | |
| } | |
| .cloud::before, .cloud::after, .cloud__shape { | |
| background: inherit; | |
| border-radius: 50%; | |
| position: absolute; | |
| } | |
| .cloud::before { | |
| content: ""; | |
| left: -0.5rem; | |
| bottom: 0; | |
| width: 1.5rem; | |
| height: 1.5rem; | |
| } | |
| .cloud::after { | |
| content: ""; | |
| right: -0.5rem; | |
| bottom: 0; | |
| width: 1.3rem; | |
| height: 1.3rem; | |
| } | |
| .cloud__shape:first-child { | |
| left: 0; | |
| bottom: 0.6rem; | |
| width: 1.7rem; | |
| height: 1.7rem; | |
| } | |
| .cloud__shape:last-child { | |
| right: 0.2rem; | |
| bottom: 0.5rem; | |
| width: 1.4rem; | |
| height: 1.4rem; | |
| } | |
| .cloud:first-child { | |
| left: -0.1rem; | |
| top: 3.2rem; | |
| opacity: 0.6; | |
| } | |
| .cloud:nth-child(2) { | |
| left: 5rem; | |
| transform: scale(1.2); | |
| bottom: 2.4rem; | |
| opacity: 0.65; | |
| } | |
| .cloud:nth-child(3) { | |
| left: 11rem; | |
| transform: scale(1.2) scaleX(-1); | |
| top: 6.4rem; | |
| opacity: 0.5; | |
| } | |
| .cloud:nth-child(4) { | |
| right: 7.6rem; | |
| transform: scale(1.4) scaleX(-1); | |
| top: 2.9rem; | |
| opacity: 0.4; | |
| } | |
| .cloud:nth-child(5) { | |
| right: 3.5rem; | |
| bottom: 2rem; | |
| opacity: 0.5; | |
| } |