Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Airplane Mode Toggle Switch ✈️
<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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment