I've been practicing animation in JavaScript and CSS and there's a transition I want to do that goes from dark green to a light green to mimic grass being cut but the animation goes too quick and doesn't properly track the lawn mower's position, so I was wondering what I did wrong. I think it has to do with the progress
variable but I'm not sure.
Also I'm not sure if the whole creating a strip of grass in JavaScript is the best approach to this animation.
Any help would be appreciated.
const grass = document.getElementById('grass');
const lawnMower = document.getElementById('lawnMower');
// Function to create a vertical strip of grass that transitions color
function createGrassStrip(x, width) {
const strip = document.createElement('div');
strip.style.position = 'absolute';
strip.style.top = '0';
strip.style.left = `${x}px`;
strip.style.width = `${width}px`;
strip.style.height = '100%';
grass.appendChild(strip);
return strip;
}
// Function to update the grass strip color based on lawn mower position
function updateGrassStrip(strip, mowerPosition) {
const viewportHeight = window.innerHeight;
const progress = (viewportHeight / mowerPosition) * 10;
// Transition from dark green to light green BELOW the lawn mower
const darkGreen = '#388E3C';
const lightGreen = '#8BC34A';
strip.style.background = `repeating-linear-gradient(0deg, ${darkGreen}, ${darkGreen} ${progress}%, ${lightGreen} ${progress}%, ${lightGreen} 100%)`;
}
// Create a grass strip for the lawn mower's path
const mowerWidth = 100; // Width of the lawn mower
const mowerX = (window.innerWidth - mowerWidth) / 2; // Center the strip
const grassStrip = createGrassStrip(mowerX, mowerWidth);
// Update grass strip color on every animation frame
function animate() {
const mowerPosition = lawnMower.getBoundingClientRect().top;
updateGrassStrip(grassStrip, mowerPosition);
requestAnimationFrame(animate);
}
// Start the animation
animate();
body,
html {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
font-family: Arial, sans-serif;
}
.lawn {
position: relative;
width: 100%;
height: 100vh;
background-color: #4CAF50;
overflow: hidden;
}
.grass {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #388E3C;
);
}
.lawn-mower {
position: absolute;
top: 0;
left: 50%;
width: 100px;
height: 50px;
background-color: #FF5722;
border-radius: 10px;
transform: translateX(-50%);
animation: mow 2.5s linear;
}
@keyframes mow {
0% {
top: 0;
}
50% {
top: 50%;
}
100% {
top: 100%;
}
}
.content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: white;
z-index: 1;
}
<div class="lawn">
<div class="grass" id="grass"></div>
<div class="lawn-mower" id="lawnMower"></div>
</div>
<div class="content">
</div>
A CSS-only solution with a minimal code:
.box {
width: 100px;
aspect-ratio: 2;
border-radius: 10px;
box-shadow: 0 -100vh 0 calc(100vh - 10px) #8bc34a; /* a huge box-shadow (taking the radius into consideration) */
clip-path: inset(-100vh 0 0); /* show only the top part of the box-shadow*/
background: #FF5722;
animation: move 5s linear forwards;
}
@keyframes move {
0% {translate: 0 -100%} /* hide from the top*/
to {translate: 0 100vh} /* move until the bottom of the page */
}
body {
background: #388E3C;
margin: 0;
overflow: hidden;
place-items: center;
}
<div class="box"></div>