Who actually needs a heavy framework for a landing page?

JulesCrafter Novice 3h ago 453 views 4 likes 2 min read

The project is a tribute to Mumbai's Vada Pav, and the technical constraint was intentionally strict: keep it lightweight and fast. When you strip away the dependencies, you're forced to actually understand the browser's rendering engine rather than relying on a library to handle the heavy lifting.

The Tech Stack (or lack thereof)

I went with a single index.html and a styles.css file. The result is a page that loads instantly because there's no JavaScript bundle to parse or CSS-in-JS overhead. For the visuals, I leaned into a "Mumbai at night" aesthetic—deep navy backgrounds with tungsten glows and saffron accents.

The most interesting part from a dev perspective is how I handled the interactivity without a framework. Instead of using a state management library, I used data-base attributes to handle a recipe scaler. By attaching a simple event listener to the servings input, the quantities recalculate instantly in the DOM.

Implementation Details

If you're looking for a practical tutorial on how to handle scroll-driven animations without a library, here is the logic I used:

1. Dynamic Navigation: I used requestAnimationFrame with eased interpolation to make the nav links fade in proportionally as the user scrolls. This avoids the jank you often get with basic onscroll events.
2. The Interactive Assembler: This is basically a custom tab UI. I implemented the ARIA tablist pattern to ensure it's accessible. Each step swaps an image and updates a description while filling a progress bar.
3. Scroll Reveals: I used the IntersectionObserver API to trigger .reveal animations. It's far more performant than calculating getBoundingClientRect() on every scroll tick.

Here is a snippet of how the recipe scaling logic works:

const scaleInputs = document.querySelectorAll('.serving-input');
const ingredients = document.querySelectorAll('.ingredient-qty');

scaleInputs.forEach(input => {
  input.addEventListener('change', (e) => {
    const multiplier = e.target.value;
    ingredients.forEach(ing => {
      const baseValue = parseFloat(ing.dataset.base);
      ing.textContent = (baseValue * multiplier).toFixed(1);
    });
  });
});

Performance and Accessibility

I'm always skeptical of "modern" sites that take 5 seconds to load just to show some text. This entire page is roughly 32KB of HTML and 27KB of CSS. Even with the images, it's a fraction of the size of a standard Next.js landing page.

On the accessibility front, I didn't treat it as an afterthought. I used:

  • Semantic HTML5 (<main>, <section>, <article>) to ensure screen readers actually understand the page structure.
  • aria-live="polite" for the dynamic content in the assembler so users are notified of changes.
  • prefers-reduced-motion media queries to kill the animations for users who get motion sickness.
Who actually needs a heavy framework for a landing page?

It's a reminder that sometimes the best AI workflow is the one where you step away from the complex tooling and just write clean, standard code.
webdevdevchallengeAI ProgrammingAI Codingfrontendchallenge

All Replies (3)

S
SoloSage Advanced 3h ago
True, but you still have to handle cross-browser CSS bugs manually. Pain in the ass.
0 Reply
D
Drew36 Advanced 3h ago
I did a similar project with plain HTML/CSS and the page load was basically instant.
0 Reply
Z
Zoe12 Novice 3h ago
Did you use any specific tool for image optimization to keep the load times down?
0 Reply

Write a Reply

Markdown supported