A Journey Towards a More Sustainable Front End
|6 min read
After being inspired by the WDC and All Day Hey! conferences, I started a side project called FreeFrom with one clear goal: build exciting, interactive experiences by relying on the native web platform first. The aim was to make use of modern HTML and CSS, using JavaScript only when necessary or when it genuinely added to the experience.
At first, this was a creative challenge. Very quickly, it became something bigger: a practical way to build lighter pages with less processing overhead, less transferred data, and a smaller carbon footprint.
The Conference Moment That Sparked a Challenge
At All Day Hey!, one talk by Bramus Van Damme really stuck with me: scroll-driven View Transitions orchestrated with JavaScript. The example from Chrome Developers is excellent and incredibly clever.
https://chrome.dev/view-transitions-toolkit/scroll-driven-view-transition/
The approach starts a transition, pauses it, and then scrubs animation progress based on scroll position.
Javascript example
const startViewTransition = async () => {
document.startViewTransition(() => {
document.querySelector(".card").classList.toggle("small");
});
await document.activeViewTransition.ready;
pause(document.activeViewTransition);
};
const updateAnimations = () => {
scrub(document.activeViewTransition, scrollProgress);
};
When the scroll direction changes, the animations are reversed and scrubbed back from 1 to 0.
if (isReverse) {
for (const anim of getAnimations(document.activeViewTransition)) {
anim.reverse();
}
}
That demo is a great piece of engineering, but I left with one question:
Could I recreate the same experience without using JavaScript at all?
Chapter 2: Rebuilding the idea with only CSS
Back at my desk in front of my laptop, I challenged myself to use CSS scroll-driven animations via animation-timeline to recreate that same sense of motion and scroll-driven progress.
Instead of:
-
Shipping JavaScript
-
Starting transitions in JavaScript
-
Managing paused animation state
-
Manually scrubbing animation timelines
…I let the browser map animation progress directly to the scroll position.
@supports (animation-timeline: scroll()) {
@keyframes hero-shrink {
from {
clip-path: inset(0 35%);
transform: scaleY(1);
}
to {
clip-path: inset(0 0%);
transform: scaleY(0.45);
}
}
.philosophy-hero {
position: sticky;
top: 0;
transform-origin: top center;
animation: hero-shrink linear both;
animation-timeline: scroll();
animation-range: 0px 300px;
}
}
In FreeFrom, I used animation-timeline: scroll() to connect the progress of a CSS animation directly to the user's scroll position. As the page scrolls, the hero section smoothly shrinks and reveals more content without a single event listener, animation frame loop or manually managed timeline.
The browser handles the relationship between scroll position and animation progress natively, allowing it to optimise rendering and, where appropriate, take advantage of compositor-driven animations. Instead of writing code to constantly observe and update state, I simply described the desired behaviour in CSS.
This is important from a sustainability perspective because CSS is declarative and native to the rendering engine. There is no additional JavaScript to download, parse, or execute for these interactions, reducing work on the main thread and lowering power consumption over time.
Modern browsers can also optimise many CSS animations by running them on the compositor, often taking advantage of GPU acceleration for properties such as transform and opacity. When used appropriately, this results in smoother animations, fewer dropped frames and better performance - particularly on lower-powered devices - while leaving the JavaScript thread free for work that requires it.
The project shifted my mindset from:
"How do I control this with code?"
to:
"How do I describe this in CSS so the browser can do it as efficiently as possible?"
Chapter 3: Challenge Two - The Burger Menu Comparison
The next challenge was intentionally simple: the mobile navigation menu. It's a pattern we encounter on almost every website and application every day.
A Typical JavaScript Burger Menu
This pattern is everywhere and works perfectly well, but it introduces imperative logic and runtime overhead.
HTML
<button class="menu-toggle"
aria-expanded="false"
aria-controls="main-nav">
Menu
</button>
<nav id="main-nav" hidden>
...
</nav>
JavaScript
const btn = document.querySelector('.menu-toggle');
const nav = document.querySelector('#main-nav');
btn.addEventListener('click', () => {
const isOpen = btn.getAttribute('aria-expanded') === 'true';
btn.setAttribute('aria-expanded', String(!isOpen));
nav.hidden = isOpen;
});
My FreeFrom CSS-Only Burger Menu
I instead used a checkbox input paired with a label.
HTML
<input class="menu-btn" type="checkbox" id="menu-btn" name="menu-btn" /> <label class="menu-icon" for="menu-btn"> <span class="navicon" aria-label="Hamburger menu icon"> </span> </label> <nav aria-label="Main navigation"> ... </nav>
CSS then handles the open and closed states using the :checked selector.
No JavaScript in sight. No need for event listeners, class toggling or including a separate npm package. This single component illustrates a much broader principle:
“If the platform already provides a way to represent the state, use that before writing any JavaScript.”
Chapter 4: The Hidden Sustainability Win
When we remove JavaScript from interactions that don't need it, we reduce the carbon impact in several ways at once.
-
Fewer bytes transferred across network infrastructure
-
Less JavaScript parsing and execution on client devices
-
Lower battery usage during interactions
-
Fewer dependencies to maintain over the lifetime of the project
None of this means never use JavaScript.
Instead, it means using JavaScript where it provides value, not simply because it's the default solution.
At scale, these improvements become significant. Saving a small amount of script execution and processing on every page view, multiplied across thousands or millions of visits, can translate into meaningful energy savings.
Chapter 5: Bringing FreeFrom into Production
One of the most rewarding outcomes of FreeFrom has been seeing ideas from a personal experiment make their way into commercial projects.
While working on the recent rebrand of the Dogs Trust website at Aer Studios, I found myself applying the same mindset I'd developed through FreeFrom: before writing any JavaScript, ask what the platform already provides.
One example was the site's Accordion component, which is used extensively throughout the website for FAQs and other expandable content. Rather than building a custom JavaScript solution, I refactored the component to use the native <details> and <summary> elements.
Those elements already provide much of the behaviour users expect, along with built-in accessibility support, keyboard interaction and semantics. By leaning on the platform instead of recreating it, we were able to reduce complexity while producing a component that's easier to maintain, more resilient and more aligned with the principles behind FreeFrom.
It's a relatively small change in isolation, but that's exactly the point. Sustainable front-end development isn't always about major architectural decisions, it can be the accumulation of dozens of small choices to use the web platform more effectively.
One example of this approach can be seen on the Dogs Trust website, where the Accordion component is used on pages such as their guide on how to stop your dog barking.
https://www.dogstrust.org.uk/dog-advice/training/unwanted-behaviours/stop-your-dog-barking
The same philosophy also influenced the redesign of the Aer Studios website.
The site's mobile navigation uses the same CSS-only burger menu approach that originated in FreeFrom, relying on native form controls and CSS state rather than JavaScript to manage whether the navigation is open or closed.
Perhaps my favourite example, though, is the Testimonials component which can be seen on the homepage: http://www.aerstudios.co.uk.
The original design called for a paginated carousel, a component many teams would instinctively build using a JavaScript carousel library. Instead, I asked the same question that FreeFrom had taught me to ask: can the platform already do this?
Rather than introducing JavaScript, I built the component using native radio inputs. Each pagination control is simply a <label> associated with a hidden radio button. CSS then uses the :checked state to determine which testimonial should be visible, while transitions provide the sliding animation between quotes.
The result is a fully interactive carousel without a single event listener, state management hook or third-party dependency.
More importantly, it demonstrates that browser-native state can often replace imperative JavaScript for UI interactions, producing components that are lighter, easier to maintain and still deliver the polished experience users expect.
Chapter 6: What This Project Changed for Me
Building FreeFrom has pushed me to explore modern HTML and CSS more deeply than ever before.
Some examples include:
-
Tabs and accordions using <details> and <summary>
-
Page-to-page motion using CSS View Transitions
-
Scroll-linked animations with animation-timeline
-
Mobile navigation state using nothing more than a checkbox input
The biggest surprise wasn't that I managed to build these interactions without JavaScript. It was how often I discovered the platform already had a solution and I just hadn't looked for it before.
By removing images and JavaScript from my default toolkit, I ended up with a site that is lightweight, fast, accessible and more sustainable by design.
For me, that has become the core lesson of FreeFrom:
The greenest code is often the code you never ship.
FreeFrom started as a personal challenge. It's now become part of how I approach every front-end project: start with the platform, embrace the capabilities the browser already provides, and only reach for JavaScript when needed.
Inspired by WDC, All Day Hey!, and the developers continuing to push the web platform forward. The challenge is no longer whether we can build rich experiences with less JavaScript. It's whether we choose to.
