Skip to content

Instantly share code, notes, and snippets.

@vineeth-pappu
Created May 23, 2022 09:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vineeth-pappu/6013754771c3faa3e6612d9a6639bcff to your computer and use it in GitHub Desktop.
Save vineeth-pappu/6013754771c3faa3e6612d9a6639bcff to your computer and use it in GitHub Desktop.
SCI-FI UI #2 - WAVING SQUARE DROPDOWN
-var x = 1
-var sqr = 174
mixin option(label)
-var x = 1
-var sqr = 174
div(class='option' onclick='getOption(this)')
.label= label
.sqrs
while x <= sqr
div(class='sqr sqr-' + x++)
#shot
.card
button#component
input(type='checkbox', name='toggle')
.select
#select.label.placeholder= 'choose a city…'
.arrow
svg(width='14px', height='28px', viewBox='0 0 14 28', version='1.1', xmlns='http://www.w3.org/2000/svg', xmlns:xlink='http://www.w3.org/1999/xlink')
g(id='chevrons')
polygon(id='chevron-1', points='0 18 7 24 14 18 14 22 7 28 0 22')
polygon(id='chevron-2', points='0 12 7 18 14 12 14 16 7 22 0 16')
path(d='M-0,6 L7,0 L14,6 L14,10 L7,16 L0,10 L-0,6 Z M7,4 L2,8 L7,12 L12,8 L7,4 Z', id='losange')
.sqrs
while x <= sqr
div(class='sqr sqr-' + x++)
.options
+option('gotham city')
+option('metropolis')
+option('atlantis')
.description
h1
| waving square dropdown
p
| Click on the white button to unlock the following options
.title
.options
p
| Type of transition
// transition controler
.btns
each val, index in ['row', 'following']
button(id='btn-'+index onclick='setAnim(this)')= val
p
| Aurelien Grimaud, <a href='https://twitter.com/inVoltag' target='_blank'>@inVoltag</a>

SCI-FI UI #2 - WAVING SQUARE DROPDOWN

Particles experiments in order to explore several moves only in CSS. Feel free to add your own!

A Pen by vineeth on CodePen.

License.

// transition controler
function addClass(component, className) {
var y = document.querySelector('#component');
y.removeAttribute('class');
y.classList.add(className);
};
function setAnim(z) {
var btn = document.getElementsByTagName('button')
for (i = 1; i < btn.length; i++) {
btn[i].classList.remove('active');
}
z.classList.toggle('active');
value = z.innerText;
addClass('component', value);
}
// dropdown control
var option = document.querySelectorAll('.option');
var select = document.querySelector('#select');
var check = document.querySelector('input');
var card = document.querySelector('.card');
var body = document.querySelector('body');
function getOption(e) {
var optVal = e.innerText;
// toggle button
if (e.classList.contains('active')) {
check.checked = false;
e.classList.remove('active');
select.innerText = "choose a city…";
select.style.color = 'rgba(17, 17, 17, .5)';
} else {
for (i = 0; i < option.length; i++) {
var x = option[i].classList;
x.remove('active');
x.add('inverted');
};
check.checked = false;
e.classList.add('active');
select.innerText = optVal;
select.style.color = 'rgba(17, 17, 17, .75)';
};
// back to the default start point after ending transition
setTimeout(function() {
for (i = 0; i < option.length; i++) {
var x = option[i].classList;
x.remove('inverted');
}
}, 500)
};
// close options when clicked outside
document.addEventListener('click', function(evt) {
var tgt = evt.target;
if (tgt == card || tgt == body) {
check.checked = false;
}
});
// first transition by default
var btn = document.querySelectorAll('button');
btn[1].classList.add('active');
value = btn[1].innerText;
addClass('component', value);
// colors
$onyx: #111;
$white: #fff;
$ketchup-mayo: #f5d546;
$leather: #4f4c4d;
$light-azur: #C7E3F9;
$tomato: #d64444;
// squares
$sqr: 174;
$row: 29;
$line: 6;
// speed
$speed: 300ms;
$delay: 100ms;
// options
$option: 3;
button#component {
width: 290px;
height: 60px;
border: none;
display: flex;
background: transparent;
margin: auto;
padding: 0;
position: relative;
flex-wrap: wrap;
font-family: 'Barlow', sans-serif;
transform: translateY(-90px);
&:focus {
outline: none
}
.sqrs {
width: 100%;
height: 100%;
position: absolute;
display: flex;
flex-wrap: wrap;
z-index: -1;
.sqr {
width: 10px;
height: 10px;
background-color: $white;
transform-origin: 50% 50%;
transition-property: all;
transition-timing-function: ease-out;
transition-duration: $speed;
}
}
input[type=checkbox] {
position: absolute;
width: 100%;
height: 100%;
margin: 0;
-webkit-appearance: unset;
z-index: 10;
outline: 0;
top: 0;
cursor: pointer;
// expand and collapse only in CSS
&:checked~.select {
background: $ketchup-mayo;
svg {
#losange {
transform: translateY(12px)
}
#chevrons {
transform: rotateX(180deg);
transform-origin: 0 14px;
}
}
}
&:checked~.options {
.option {
transform: translateX(0);
transform: translateY(0);
opacity: 1;
pointer-events: all;
& .sqrs .sqr {
transform: scale(1);
}
}
}
}
.select, .options {
width: 100%;
height: 100%;
display: flex;
position: absolute;
top: 0;
left: 0;
z-index: 9;
.label {
font-weight: 600;
font-size: 18px;
text-align: center;
letter-spacing: 4px;
text-transform: uppercase;
margin: auto;
transition: $speed ease-out all;
&.placeholder {
color: rgba($onyx, .5)
}
}
.arrow {
flex: 0 1 60px;
display: flex;
svg {
margin: auto;
fill: rgba($onyx, .5);
overflow: visible;
& * {
transition: 200ms ease-out all;
}
}
}
}
.options {
top: 60px;
z-index: 8;
height: auto;
.option {
width: 100%;
height: 60px;
display: flex;
align-items: center;
opacity: 0;
pointer-events: none;
cursor: pointer;
transition-duration: $speed;
transition-timing-function: ease;
transition-property: all;
// feedback when an option is selected
&.active {
$k: 3;
@while $k <= $sqr {
& .sqr-#{$k} { background: $ketchup-mayo }
$k: $k + $row;
}
.label {
transform: translateX(10px);
}
}
// dephasing each option
@for $i from 1 through $option {
$k: $i - 1;
&:nth-child(#{$i}) {
transition-delay: $k * $delay;
}
}
.label{
padding: 0 0 0 30px;
color: $white;
text-align: left;
margin: 0;
flex: 1;
}
.sqr {
background: rgba($white, .2);
transform: scale(0);
// yellow padding-left
$i: 1;
$j: 2;
@while $i <= $sqr {
&.sqr-#{$i} { background: $ketchup-mayo }
$i: $i + $row;
@while $j <= $sqr {
&.sqr-#{$j} { background: $ketchup-mayo }
$j: $j + $row;
}
}
}
}
}
}
// row transition with inverted style when an option has been choosen
@for $i from 0 through $row {
@for $j from 1 through $option {
$k: $j - 1;
$r: $sqr + $i;
@while $r > 0 {
#component.row .option:nth-child(#{$j}) .sqr-#{$r} {
transition-delay: ($k * $delay) + (5ms * $i)
}
$r: $r - $row
}
}
}
#component.row .option {
transform: translateX(-50px);
&.inverted {
transform: translateX(50px);
}
}
// following transition with inverted style when an option has been choosen
@for $i from 1 through $sqr {
@for $j from 1 through $option {
$k: $j - 1;
button#component.following .option:nth-child(#{$j}) .sqr-#{$i} {
transition-delay: ($k * $delay) + (1ms * $i)
}
// inverted animation
button#component.following .option:nth-child(#{$j}).inverted .sqr-#{$i} {
$i: $sqr - $i + 1;
$k: $option - $j;
transition-delay: ($k * $delay) + (1ms * $i)
}
button#component.following .option:nth-child(#{$j}).inverted {
$k: $option - $j;
transition-delay: $delay * $k;
}
}
}
#component.following .option {
transform: translateY(-25px);
}
// template style, the least interesting
$duration: 400ms;
$shift: 200ms;
$start: 800ms;
body {
background: lighten($onyx, 5%) url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAG0lEQVQYV2P8//+/FCMj4zMGJMCIzIGxKRQEAJgPBAbJqUVTAAAAAElFTkSuQmCC) repeat;
display: flex;
height: 100vh;
font-family: 'Barlow', sans-serif;
font-size: 14px;
font-weight: 500;
color: $white;
margin: 0;
padding: 0;
}
h1 {
background-color: $ketchup-mayo;
padding: 0 5px 3px 5px;
color: lighten($onyx,.1);
letter-spacing: 1px;
text-transform: uppercase;
font-size: 32px;
letter-spacing: 2px;
margin: 20px 0 10px;
border: 1px $ketchup-mayo solid;
border-radius: 5px;
}
h1, p {
font-weight: 500;
}
p {
opacity: .3;
margin: 0 0 10px 0;
letter-spacing: 1px;
}
a {
color: $ketchup-mayo;
&:hover {
background: $ketchup-mayo;
color: $onyx;
text-decoration: none;
}
}
#shot {
width: 400px;
margin: auto;
position: relative;
.card {
width: 100%;
height: 300px;
display: flex;
background: linear-gradient(0deg, rgba($ketchup-mayo, .1) 0%, rgba($onyx, 0) 100%);
border: 1px $ketchup-mayo solid;
border-radius: 5px;
animation: entrance $duration $start linear backwards 1;
#component {
margin: auto
}
}
.description {
animation: entrance $duration ($start + $shift) linear backwards 1;
}
.title {
height: 100%;
width: 5px;
position: absolute;
top: 0;
left: -50px;
background: $ketchup-mayo;
animation: entrance $duration ($start + $shift * 2) linear backwards 1;
&::before {
@extend p;
content: 'sci-fi ui #2';
text-transform: uppercase;
text-align: right;
position: absolute;
left: -92px;
top: -17px;
transform-origin: 100% 100%;
transform: rotateZ(-90deg);
}
}
.options {
width: 200px;
height: auto;
display: flex;
flex-wrap: wrap;
position: absolute;
top: 0;
right: -220px;
animation: entrance $duration ($start + $shift * 3) linear backwards 1;
button {
height: 40px;
padding: 0 10px;
margin: 0 10px 15px 0;
border: 2px $onyx solid;
outline: 1px $ketchup-mayo solid;
background-color: transparent;
font-size: 14px;
letter-spacing: 1px;
color: $white;
cursor: pointer;
transition: 300ms all ease-out;
&:hover, &:focus, &.active {
background-color: rgba($ketchup-mayo,.5);
}
&.active {
border: 2px $ketchup-mayo solid;
background-color: rgba($ketchup-mayo,1);
color: lighten($onyx,.1)
}
}
}
}
// entrance animation
@-webkit-keyframes entrance {
to, 20%, 40%, 60%, 80% { opacity: 1 }
from, 10%, 30%, 50%, 70%, 90% { opacity: 0 }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment