A randomly generated blobby nav created with CSS.
Has smooth anchor scrolling, uses backdrop-filter
, and SVG filter. Also, has a pure CSS "off" click by resizing a label
Enjoy!
- const randomInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min | |
- const SECTIONS = ['HOME', 'ABOUT', 'CONTACT', 'WORK'] | |
nav.menu(style=`--hue: ${Math.random() * 360}`) | |
input(type='checkbox', id='menu-toggle', class='menu__toggle') | |
label(for='menu-toggle', class='menu__toggle-label') | |
label(for='menu-toggle', class='menu__toggle-label menu__toggle-label--closer') | |
svg.menu__icon(preserveAspectRatio='xMinYMin', viewBox='0 0 24 24') | |
path(d='M3,6H21V8H3V6M3,11H21V13H3V11M3,16H21V18H3V16Z') | |
svg.menu__icon(preserveAspectRatio='xMinYMin', viewBox='0 0 24 24') | |
path(d='M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z') | |
ul.menu__content | |
li.menu__item(style=`--x: ${randomInRange(15, 35)}; --y: ${randomInRange(15, 25)};`) | |
a.menu__link(href="#HOME") HOME | |
li.menu__item(style=`--x: ${randomInRange(45, 75)}; --y: ${randomInRange(25, 40)};`) | |
a.menu__link(href="#ABOUT") ABOUT | |
li.menu__item(style=`--x: ${randomInRange(15, 35)}; --y: ${randomInRange(45, 75)};`) | |
a.menu__link(href="#CONTACT") CONTACT | |
li.menu__item(style=`--x: ${randomInRange(65, 75)}; --y: ${randomInRange(50, 75)};`) | |
a.menu__link(href="#WORK") WORK | |
main | |
for SECTION in SECTIONS | |
section(id=SECTION)= SECTION | |
svg(style='position: absolute; left: 100%') | |
defs | |
filter(id=`goo`) | |
feGaussianBlur(in='SourceGraphic', stdDeviation='15', result='BLUR') | |
feColorMatrix(in='BLUR', mode='matrix', values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7', result='GOO') | |
feBlend(in='SourceGraphic', in2=`goo`) |
// 404 |
@import url('https://fonts.googleapis.com/css?family=Alata&display=swap') | |
* | |
box-sizing border-box | |
:root | |
--speed .85 | |
--primary hsl(0, 0, 100%) | |
--size 30 | |
--ease cubic-bezier(0.175, 0.885, 0.32, 1.275) | |
body | |
background #fafafa | |
font-family 'Alata', sans-serif | |
min-height 100vh | |
overflow-x hidden | |
padding 0 | |
main | |
height 100vh | |
overflow-y scroll | |
scroll-behavior smooth | |
scroll-snap-type y mandatory | |
section | |
align-items center | |
display flex | |
font-size 3rem | |
height 100vh | |
justify-content center | |
scroll-snap-align center | |
width 100vw | |
.menu | |
position fixed | |
&__toggle | |
opacity 0 | |
position absolute | |
&:checked | |
& ~ .menu__content .menu__item | |
--active-x var(--x) | |
--active-y var(--y) | |
--scale 1 | |
& ~ .menu__toggle-label:not(.menu__toggle-label--closer) | |
--clip circle(1000% at 0% 0%) | |
height 100vh | |
width 100vw | |
backdrop-filter blur(10px) | |
& ~ .menu__toggle-label .menu__icon | |
&:nth-of-type(1) | |
--scale 0 | |
&:nth-of-type(2) | |
--scale 1 | |
&__toggle-label | |
cursor pointer | |
height calc(var(--size, 20) * 0.5vmin) | |
width calc(var(--size, 20) * 0.5vmin) | |
display block | |
--clip circle(100% at 0% 0%) | |
-webkit-clip-path var(--clip) | |
clip-path var(--clip) | |
position absolute | |
top 0 | |
left 0 | |
transition backdrop-filter calc(var(--speed, 1) * 1s) var(--ease), clip-path 0s, -webkit-clip-path 0s | |
&--closer | |
z-index 3 | |
--scale 0 | |
&__icon | |
--scale 1 | |
height calc(var(--size, 20) * 0.25vmin) | |
width calc(var(--size, 20) * 0.25vmin) | |
position absolute | |
top 50% | |
left 50% | |
transform translate(-70%, -70%) scale(var(--scale, 1)) | |
&:nth-of-type(2) | |
--scale 0 | |
fill var(--primary) | |
transition all calc(var(--speed, 1) * 1s) var(--ease) | |
&__content | |
background 'hsl(%s, 50%, 50%)' % var(--hue, 0) | |
margin 0 | |
display block | |
list-style-type none | |
z-index -1 | |
filter url("#goo") | |
position absolute | |
top 0 | |
height 0 | |
width 0 | |
left 0 | |
z-index 2 | |
&:after | |
background 'hsl(%s, 50%, 50%)' % var(--hue, 0) | |
content '' | |
border-radius 50% | |
transform translate(-50%, -50%) | |
position absolute | |
height calc(var(--size, 20) * 1vmin) | |
width calc(var(--size, 20) * 1vmin) | |
top 0 | |
left 0 | |
&__item | |
background 'hsl(%s, 50%, 50%)' % var(--hue, 0) | |
border-radius 50% | |
cursor pointer | |
display flex | |
list-style-type none | |
font-size 1rem | |
height calc(var(--size, 20) * 1vmin) | |
left calc(var(--active-x, 0) * 1vw) | |
overflow hidden | |
place-items center | |
position absolute | |
text-align center | |
top calc(var(--active-y, 0) * 1vh) | |
transform translate(-50%, -50%) scale(var(--scale, 0.75)) | |
transition all calc(var(--speed, 1) * 1s) calc(var(--delay, 0) * 1s) var(--ease) | |
width calc(var(--size, 20) * 1vmin) | |
@media(min-width 768px) | |
font-size 3rem | |
&:nth-of-type(1) | |
--delay .1 | |
--x 35 | |
--y 35 | |
&:nth-of-type(2) | |
--delay .2 | |
--x 65 | |
--y 35 | |
&:nth-of-type(3) | |
--delay .3 | |
--x 35 | |
--y 65 | |
&:nth-of-type(4) | |
--delay .4 | |
--x 65 | |
--y 65 | |
&__link | |
align-items center | |
color white | |
cursor pointer | |
text-decoration none | |
font-weight bold | |
text-align center | |
display flex | |
justify-content center | |
height 100% | |
width 100% | |
&:hover | |
text-decoration underline |