<div class="container">
<form class="form">
<div class="signup__field">
<label class="label">Halloween Name</label>
<input type="text" name="halloween_name" id="halloween_name" class="name_field summon_bat">
</div>
<fieldset class="signup__fieldset">
<legend>Details</legend>
<div class="signup__field">
<label class="label">What kind of costume are you wearing? </label>
<div class="select-field">
<select name="costume_type" id="costume_type" class="select-field__menu summon_bat">
<option>Pick one</option>
<option value="monster">Monster</option>
<option value="spellcaster">Spellcaster</option>
<option value="vampire">Vampire</option>
<option value="ghost">Ghost</option>
<option value="zombie">Zombie</option>
<option value="pop_culture">Pop Culture Reference</option>
<option value="other">Other</option>
</select>
</div>
</div>
<div class="signup__field">
<div class="label">Do you prefer Tricks or Treats?</div>
<div class="radio__container">
<div class="radio__field">
<input type="radio" value="tricks" name="tricksOrTreats" id="pumpkin_tricks" checked>
<label for="pumpkin_tricks" class="pumpkin summon_bat">
<span class="horror-input-pumpkin-stem"></span>
<span class="horror-input-pumpkin-eye horror-input-pumpkin-eye-left"></span>
<span class="horror-input-pumpkin-eye horror-input-pumpkin-eye-right"></span>
<span class="horror-input-pumpkin-mouth"></span>
</label>
<label for="pumpkin_tricks" class="summon_bat">Tricks</label>
</div>
<div class="radio__field">
<input type="radio" value="treats" name="tricksOrTreats" id="pumpkin_treats">
<label for="pumpkin_treats" class="pumpkin summon_bat">
<span class="horror-input-pumpkin-stem"></span>
<span class="horror-input-pumpkin-eye horror-input-pumpkin-eye-left"></span>
<span class="horror-input-pumpkin-eye horror-input-pumpkin-eye-right"></span>
<span class="horror-input-pumpkin-mouth"></span>
</label>
<label for="pumpkin_treats" class="summon_bat">Treats</label>
</div>
</div>
</fieldset>
<div class="signup__field">
<div class="snack__container">
<input type="checkbox" name="bringing_snacks" id="bringing_snacks">
<label for="bringing_snacks" class="ghost summon_bat">
<span class="ghost-eye ghost-eye-left"></span>
<span class="ghost-eye ghost-eye-right"></span>
<span class="ghost-hand ghost-hand-left"></span>
<span class="ghost-hand ghost-hand-right"></span>
<span class="ghost-candy"></span>
</label>
<label for="bringing_snacks" class="summon_bat">
I volunteer to bring a shareable snack.
</label>
</div>
</div>
<div class="signup__button">
<button class="button summon_bat" type="button">Submit</button>
</div>
</form>
</div>
<div id="stone__container"></div>
<div id="darkness" class="darkness">
<h1>Halloween Party RSVP</h1>
</div>
@use "sass:math";
@use "sass:list";
@import url("https://fonts.googleapis.com/css2?family=Creepster");
@function text-border($size, $color) {
$return-value: ();
@for $i from $size * -1 through $size {
@for $j from $size * -1 through $size {
$value: #{$i $j $color};
$return-value: list.join($return-value, $value, $separator: comma);
}
}
@return $return-value;
}
@mixin bat-generator($color, $width, $height, $wing-span, $wing-height) {
$flap-size: math.ceil($wing-span / 4);
$flap-angle: math.atan2($wing-height, $wing-span / 2);
background-color: $color;
width: $width;
height: $height;
border-radius: 50% / 40%;
&::before, &::after {
content: "";
width: 0;
height: 0;
border: 0;
border-left: solid math.ceil($width / 6) transparent;
border-right: solid math.ceil($width / 6) transparent;
border-bottom: solid math.ceil($height / 2) $color;
position: absolute;
top: 0;
}
&::before {
transform-origin: bottom right;
transform: translateY(math.ceil($height / -2)) rotate(-25deg);
}
&::after {
right: 0;
transform-origin: bottom left;
transform: translateY(math.ceil($height / -2)) rotate(25deg);
}
.horror-input-bat-left-wing,
.horror-input-bat-right-wing {
width: 0;
height: 0;
border: 0;
border-left: solid math.ceil($wing-span / 2) transparent;
border-right: solid math.ceil($wing-span / 2) transparent;
border-bottom: solid $wing-height $color;
position: absolute;
top: calc(50% - #{$wing-height});
&::after {
content: "";
background-image:
radial-gradient(
circle at math.ceil($flap-size / 2) math.ceil($flap-size / 2),
transparent 0 math.ceil($flap-size / 2),
$color math.ceil($flap-size / 2) $flap-size
);
background-size: $flap-size math.ceil($flap-size / 2);
width: $wing-span;
height: math.ceil($flap-size / 2);
position: absolute;
top: $wing-height;
left: math.ceil($wing-span / -2);
transform-origin: top center;
}
}
.horror-input-bat-left-wing {
right: calc(100% - 4px);
transform-origin: bottom right;
transform: rotate(-25deg);
animation: horror-input-bat-left-wing-flap 256ms ease-out infinite;
&::after {
transform: skewX($flap-angle * -1);
}
}
.horror-input-bat-right-wing {
left: calc(100% - 4px);
transform-origin: bottom left;
transform: rotate(25deg);
animation: horror-input-bat-right-wing-flap 256ms ease-out infinite;
&::after {
transform: skewX($flap-angle);
}
}
@keyframes horror-input-bat-left-wing-flap {
0% {
transform: rotate(-25deg);
}
50% {
transform: rotate(25deg);
}
100% {
transform: rotate(-25deg);
}
}
@keyframes horror-input-bat-right-wing-flap {
0% {
transform: rotate(25deg);
}
50% {
transform: rotate(-25deg);
}
100% {
transform: rotate(25deg);
}
}
}
@mixin pumpkin-generator($color, $width, $height) {
$stem-width: math.ceil($height / 8);
$stem-height: math.ceil($height / 3);
$eye-width: math.ceil($width / 4);
$eye-height: math.ceil($height / 7);
$mouth-width: math.ceil($width / 2);
$mouth-height: math.ceil($height / 3);
background-color: $color;
width: $width;
height: $height;
display: inline-flex;
position: relative;
border-radius: 30% / 50%;
&::after {
content: "";
background-image:
radial-gradient(
circle at 25% 25%,
transparent 0% 45%,
rgba(#000000, 0.55) 90%
),
radial-gradient(
circle at 25% 25%,
rgba(#ffffff, 0.3) 0% 5%,
transparent 25% 90%
);
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
border-radius: 30% / 50%;
}
.horror-input-pumpkin-stem {
width: 0;
height: 0;
border: 0;
border-left: solid $stem-width transparent;
border-right: solid $stem-width transparent;
border-top: solid $stem-height #00ab03;
position: absolute;
bottom: 100%;
left: calc(50% - #{$stem-width});
}
.horror-input-pumpkin-eye {
background-color: #000000;
width: $eye-width;
height: $eye-height;
position: absolute;
top: 25%;
border-radius: 50% 50% 0% 0% / 100% 100% 0% 0%;
}
.horror-input-pumpkin-eye-left {
left: 30%;
}
.horror-input-pumpkin-eye-right {
left: 70%;
}
.horror-input-pumpkin-mouth {
background-color: #000000;
width: $mouth-width;
height: $mouth-height;
position: absolute;
bottom: 10%;
right: 15%;
border-radius: 0% 0% 50% 50% / 0% 0% 100% 100%;
&::before, &::after {
content: "";
background-color: $color;
width: math.ceil($mouth-width / 4);
height: math.ceil($mouth-height / 3);
position: absolute;
}
&::before {
top: 0;
left: math.ceil($mouth-width / 8);
}
&::after {
bottom: 0;
right: math.ceil($mouth-width / 8);
}
}
}
@mixin ghost-generator($color, $width, $height) {
$color-dark: darken($color, 25%);
background-image: radial-gradient(
circle at 25% 25%,
$color 0% 25%,
$color-dark 60%
);
width: $width;
height: $height;
display: inline-flex;
position: relative;
vertical-align: middle;
border-radius: 50% 50% 0% 0%;
&::after {
content: "";
background-image: radial-gradient(
circle at math.ceil($width / 8) 0,
$color-dark 0px (math.ceil($width / 8) - 1px),
transparent math.ceil($width / 8)
);
background-size: math.ceil($width / 4) math.ceil($width / 8);
width: $width;
height: math.ceil($width / 8);
position: absolute;
top: 100%;
}
.ghost-eye {
background-color: #000000;
width: math.ceil($height / 8);
height: math.ceil($height / 8);
position: absolute;
top: math.ceil($height / 2);
border-radius: 50%;
}
.ghost-eye-left {
left: math.ceil($height / 8);
}
.ghost-eye-right {
right: math.ceil($height / 8);
}
.ghost-hand {
width: math.ceil($width / 3);
height: math.ceil($width / 4);
position: absolute;
top: 55%;
transition: transform 64ms ease-out;
}
.ghost-hand-left {
background-image: linear-gradient(10deg, $color, $color-dark);
right: 100%;
border-radius: 50% 0% 0% 50%;
transform-origin: top right;
transform: skewY(10deg);
}
.ghost-hand-right {
background-image: linear-gradient(-10deg, $color, $color-dark);
left: 100%;
border-radius: 0% 50% 50% 0%;
transform-origin: top left;
transform: skewY(-10deg);
}
}
html, body {
font-family: "Creepster", cursive;
width: 100%;
height: 100%;
cursor: none;
}
body {
font-size: 16px;
background-image: url("https://images.unsplash.com/photo-1541508186468-098826081946?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzNTM5NTY0NA&ixlib=rb-1.2.1&q=85");
background-size: cover;
background-position: center;
background-attachment: fixed;
display: grid;
place-items: center;
overflow: auto;
}
.container {
padding: 32px;
}
.form {
color: #efefef;
background-color: rgba(#2f2f2f, 0.5);
backdrop-filter: blur(5px);
padding: 32px;
border-radius: 16px;
box-shadow: 8px 8px 16px rgba(#000000, 0.5);
input, select , button {
font-family: inherit;
font-size: inherit;
background-color: #ffffff;
padding: 8px;
border: 0;
outline: 0;
border-radius: 4px;
}
fieldset {
padding: 16px;
padding-bottom: 0;
margin-bottom: 16px;
}
button {
$button-color: #2873d4;
color: #ffffff;
background-color: $button-color;
width: 100%;
box-sizing: border-box;
transition: background-color 64ms ease-out;
&:hover {
background-color: darken($button-color, 10%);
}
&:active {
background-color: darken($button-color, 20%);
}
}
}
.signup__field {
margin-bottom: 16px;
display: flex;
flex-direction: column;
}
.label {
margin-bottom: 8px;
}
.radio__container {
display: flex;
justify-content: flex-start;
}
.radio__field {
margin-right: 8px;
&:last-child {
margin-right: 0px;
}
}
.signup__button {
margin-top: 32px;
}
.signup__fieldset {
margin-top: 32px;
}
#pumpkin_tricks,
#pumpkin_treats {
opacity: 0;
pointer-events: none;
position: absolute;
&:not(:checked) + .pumpkin {
filter: grayscale(100%);
& > .horror-input-pumpkin-eye,
& > .horror-input-pumpkin-mouth {
transform: translateX(100%) scale(0);
}
}
}
.pumpkin {
@include pumpkin-generator(#fc8803, 24px, 16px);
vertical-align: middle;
transition: filter 64ms ease-out;
& > .horror-input-pumpkin-eye,
& > .horror-input-pumpkin-mouth {
transition: transform 64ms ease-out;
}
}
.ghost {
@include ghost-generator(#ffffff, 12px, 16px);
$color-1: #ff1f57;
$color-2: #ffffff;
margin-right: 8px;
.ghost-candy {
$candy-size: 10px;
background-image: radial-gradient(
circle at 50% 25%,
rgba(#ffffff, 0.5) 0% 25%,
rgba(#000000, 0.5) 60%
), linear-gradient(
$color-1 0% 25%,
$color-2 25% 75%,
$color-1 75% 100%
);
background-size: 100% 100%, math.ceil($candy-size / 3) math.ceil($candy-size / 3);
width: $candy-size;
height: $candy-size;
position: absolute;
top: 50%;
left: calc(50% - #{$candy-size / 2});
border-radius: 50%;
opacity: 0;
transform: translate(100%, -100%) rotate(-45deg);
transition: opacity 64ms ease-out, transform 64ms ease-out;
&::before,
&::after {
content: "";
width: 0px;
height: 0px;
display: block;
position: absolute;
top: calc(50% - #{math.ceil($candy-size / 3)});
border-top: solid math.ceil($candy-size / 3) transparent;
border-bottom: solid math.ceil($candy-size / 3) transparent;
}
&::before {
border-left: solid math.ceil($candy-size / 3) $color-1;
right: 100%;
}
&::after {
border-right: solid math.ceil($candy-size / 3) $color-1;
left: 100%;
}
}
}
#bringing_snacks {
opacity: 0;
pointer-events: none;
position: absolute;
&:checked + .ghost {
.ghost-hand-left {
transform: rotateY(180deg) skewY(10deg);
}
.ghost-hand-right {
transform: rotateY(180deg) skewY(-10deg);
}
.ghost-candy {
opacity: 1;
transform: rotate(-45deg);
}
}
}
.horror-input-bat {
--scale: 1;
@include bat-generator(#000000, 24px, 16px, 72px, 8px);
position: absolute;
transform: scale(var(--scale));
pointer-events: none;
}
.stone__image {
--rotate-speed: 0ms;
position: absolute;
transform-origin: center center;
animation: stone-spin var(--rotate-speed) linear infinite;
}
@keyframes stone-spin {
0% {
transform: rotate(0deg) translate(-50%, -50%);
}
99.99999% {
transform: rotate(360deg) translate(-50%, -50%);
}
100% {
transform: rotate(0deg) translate(-50%, -50%);
}
}
#stone__container {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
pointer-events: none;
}
.darkness {
--x: 0px;
--y: 0px;
--level: 0;
--low: 0px;
--high: 0px;
width: 100%;
height: 100%;
background-image: radial-gradient(
circle at var(--x) var(--y),
rgba(0, 0, 0, var(--level)) 0px var(--low),
rgb(0, 0, 0) var(--high)
);
position: fixed;
top: 0;
left: 0;
pointer-events: none;
& > h1 {
font-size: 3rem;
text-align: center;
color: #bf1f1f;
text-shadow: text-border(3px, #000000);
}
}
View Compiled
////////////////////////////////////////////////////////////////////////////////
// THE DARKNESS COVERS THE SCREEN //
////////////////////////////////////////////////////////////////////////////////
enum StoneLocation {
Left,
Right,
}
const bats: HTMLElement = document.querySelectorAll(".summon_bat");
let isActive: boolean = false;
let light: any = {
low: 0,
high: 0,
x: 0,
y: 0,
level: 1,
};
let lightTween: any = gsap.to(light, {});
function random(min: number, max: number, flt: number): number {
flt = flt === undefined ? 0 : flt;
flt = 10 ** flt;
min *= flt;
max *= flt;
return Math.round(Math.random() * (max - min) + min) / flt;
}
function renderLight(): void {
gsap.set("#darkness", {
"--x": `${light.x}px`,
"--y": `${light.y}px`,
"--level": `${light.level}`,
"--low": `${light.low}px`,
"--high": `${light.high}px`,
});
}
function createBat(scale: number): HTMLElement {
const bat: HTMLElement = document.createElement("DIV");
const batLeftWing: HTMLElement = document.createElement("DIV");
const batRightWing: HTMLElement = document.createElement("DIV");
bat.classList.add("horror-input-bat");
batLeftWing.classList.add("horror-input-bat-left-wing");
batRightWing.classList.add("horror-input-bat-right-wing");
bat.appendChild(batLeftWing);
bat.appendChild(batRightWing);
bat.style.setProperty("--scale", scale);
return bat;
}
function createStone(): void {
setTimeout((): void => {
const stoneContainer: HTMLElement = document.getElementById("stone__container");
const stone: HTMLElement = document.createElement("IMG");
stone.src = "https://assets.codepen.io/430361/scart-select-stone.png";
stone.classList.add("stone__image");
stone.style.setProperty("--rotate-speed", `${random(2000, 4000)}ms`);
stoneContainer.appendChild(stone);
const location: StoneLocation = random(0, 1);
let x1: number = 0;
let x2: number = window.innerWidth;
if (location === StoneLocation.Right) {
x1 = window.innerWidth;
x2 = 0;
}
let y1: number = random(0, window.innerHeight);
let y2: number = random(0, window.innerHeight);
gsap.fromTo(stone, {
top: y1,
left: x1,
}, {
top: y2,
left: x2,
duration: random(10, 20),
onComplete(): void {
for (let target of this._targets) {
stoneContainer.removeChild(target);
}
},
});
createStone();
}, random(2000, 4000));
}
document.body.addEventListener("mouseover", (evt: MouseEvent): void => {
isActive = true;
lightTween.kill();
lightTween = gsap.to(light, {
low: 20,
high: 100,
level: 0.5,
ease: "elastic.out(0.5, 0.1)",
duration: 1,
onUpdate() {
renderLight();
},
});
});
document.body.addEventListener("mouseout", (evt: MouseEvent): void => {
isActive = false;
lightTween.kill();
lightTween = gsap.to(light, {
level: 1,
ease: "power4.inOut",
duration: 0.3,
onUpdate() {
renderLight();
},
});
});
document.body.addEventListener("mousemove", (evt: MouseEvent): void => {
if (!isActive) {
return;
}
light.x = evt.pageX - window.scrollX;
light.y = evt.pageY - window.scrollY;
renderLight();
});
for (let bat of bats) {
bat.addEventListener("click", (evt: MouseEvent): void => {
const x: number = evt.pageX - window.scrollX;
const y: number = evt.pageY - window.scrollY;
const count: number = random(2, 4);
const scale: number = random(0.3, 1, 2);
for (let i = 0; i < count; i++) {
const batElm: HTMLElement = createBat(scale);
const gotoX: number = x + random(-100, 100);
const gotoY: number = y + random(-100, 100);
const duration: number = random(3, 6, 2);
document.body.appendChild(batElm);
batElm.style.top = `${y}px`;
batElm.style.left = `${x}px`;
gsap.to(batElm, {
top: `${gotoY}px`,
left: `${gotoX}px`,
"--scale": 0,
duration: duration,
ease: "power4.out",
onComplete(): void {
for (let target of this._targets) {
document.body.removeChild(target);
}
}
});
}
});
}
renderLight();
createStone();
View Compiled
This Pen doesn't use any external CSS resources.