Coming back to Alf’s
Some projects only really teach you something the second time you build them. Alf’s Cycles is one of those. Vintage British cycling, top to bottom. I was happy with it when I shipped it, and parts of it still hold up.
This project is about going back to the same brief with everything I’ve picked up since, and using that to build a stronger version of the same shop. The point isn’t to throw the old one out. The first version is still live, side by side with the new one, exactly so the two can be read together.
You can compare them here:
- Original: stalineapen.uk/assets/module/mod_1/alfs-cycles-pr/
- Revisited: stalineapen.uk/alfs/
The thing I kept reminding myself, working on this, is that a redesign isn’t about scoring points against your old self. It’s about noticing what you didn’t know to look for last time, and being honest enough to do the work now that you can see it.
A second read of the original
Sitting with the old site again, a few things settled into place. The structure was static HTML, with the header, navigation, and footer pasted into every page. That’s not a problem until you want to change something, and then it becomes the only problem. The phone number lived in four files. The footer lived in four files. It was a stack of pages dressed up as a site, and it would have buckled the second the shop wanted anything updated.
Accessibility had been considered, but considered isn’t the same as tested. I hadn’t run the original against the WAVE checker, hadn’t measured contrast with a tool, hadn’t gone through the alt text image by image. The site was probably mostly fine. Mostly fine isn’t a standard.
The images on the original were the kind of files you ship when you want to get something live. PNGs at the wrong sizes, photos uploaded straight from a stock library without resizing or converting. The SEO setup was minimal. A title and a description, and not much else. For a brick-and-mortar shop in Keswick, that left a lot of useful signal on the table, especially geolocation.
None of those are failures. They’re the things you only see clearly once you’ve spent more time reading other people’s code, breaking your own, and learning what the platform actually rewards. That second read became the brief I gave myself for the rebuild.
What I worked on, and what I learned
Accessibility, taken properly this time
This was the area I spent the most time on, and the one where I learned the most. The revisited site opens every page with a “Skip to main content” link so keyboard and screen reader users don’t have to walk through the navigation on every load. Every image on the site now carries descriptive alt text written for the content, not the file. So the wheelie illustration on the homepage is described as an illustrated cyclist mid-wheelie, the Alf’s Cycles mascot, rather than something generic like “logo” or “image.”
The accessibility statement is a dedicated page linked from the footer, with contact details for anyone who hits a barrier and wants to flag it. Tap targets across the site were checked against the recommended minimum size on mobile, because a lot of cycling customers might be looking at the site one-handed at a bus stop or in a shop doorway.
What accessibility actually teaches you, more than the specific fixes, is patience. You stop guessing what users need and start asking. You write less clever HTML and more useful HTML. That mindset has changed how I open a new file now.
ARIA labels, working out where they actually help
This was a subtler bit of the same work. ARIA is one of those things where doing more isn’t doing better. Slapping aria-label on every element is noisier than helpful, because screen readers then have to talk over your visible content. The revisit went the other way. ARIA labels are used where the visible text on its own doesn’t tell the full story, like icon-only buttons or the navigation toggle on mobile. Everything else inherits its meaning from semantic HTML, which is what the language was designed to do.
The lesson there is that accessibility tools are at their best when they’re filling specific gaps, not blanketing the page.
Making the site dynamic with PHP includes
The original was static HTML. The revisit moves to PHP, and the header, navigation, and footer now live in their own partial files that are included on every page. Update the phone number once, it changes everywhere. Add a menu item once, it appears across the whole site. Change a footer link, you change one file.
This was the moment the project stopped feeling like a stack of pages and started feeling like an actual website. It’s a small architectural shift, but it changes how you think about everything that comes after it. Components. Separation of concerns. A single source of truth for things that should never be retyped. Learning how to use server side includes properly was easily one of the most valuable bits of this module, and it’s the technique I’ll reach for first on every multi-page brief from now on.
Contrast and colour
The red on cream palette is part of the brand and I wanted to keep it. The challenge was that the original had spots where smaller body copy dropped below WCAG AA contrast against the warmer cream tones. It looked fine to my eye, and that was the problem. I’d been judging it by what I could see, not by what a tool would measure.
I rebuilt the colour tokens in CSS custom properties, then ran every text on background combination through a contrast checker before committing to it. A couple of the lighter greys came up shorter than I expected and got darkened. The palette still reads the same as the brand intended. It just passes the test now.
Image optimisation, the big one
This was the single biggest performance lever, and most of the PageSpeed jump traces back to it. Every photo on the site is now served as WebP, sized to the breakpoint that actually needs it rather than shipped at one giant resolution and scaled down by the browser. The wheelie illustration on the homepage went from a PNG to an SVG, which means it stays sharp at any size and loads at a fraction of the file weight. Width and height attributes are now declared on every image so the browser can reserve space and the layout doesn’t shift during load.
It’s the unglamorous part of web design and it’s also the part that makes the biggest difference. The lesson, properly internalised this time, is that the network is the bottleneck. Every kilobyte you don’t ship is a kilobyte your visitor doesn’t wait for. That goes double for mobile users on patchy signal, which is exactly the audience for a Lake District bike shop.
SEO, with proper signals
The head section on the revisit carries a lot more useful information than the original did. A canonical URL so search engines know which version of the page is the real one. Open Graph tags so the site previews correctly when it’s shared on social or in messages. A theme colour so the browser chrome on mobile picks up the brand red instead of defaulting to grey.
The bigger win, though, is geolocation. The revisited site declares ICBM coordinates, a geo.position pair, a placename of Keswick, Cumbria, and a region code of GB-CMA. This is the metadata that tells a search engine where the shop physically is, which matters enormously for a local business where most of the relevant traffic is going to be people in or near the area searching for “bike shop Keswick” or “bicycle repair Cumbria.” Geolocation was new to me on this project, and it’s the kind of thing I’ll be carrying into every local business brief from now on.
The keyword strategy was rebuilt to match. Rather than abstract terms, the keywords are now phrased the way someone in the Lake District would actually search.
A live open or closed status
The new header carries a small pill that reads Open or Closed based on the current time and day of the week. It’s a tiny piece of JavaScript, but it answers a question the visitor used to have to answer for themselves by finding the hours in the footer and checking their watch. For a brick and mortar shop, this is one of the most useful things a website can do. It’s the difference between “I’ll have to call and check” and “I can pop in now.”
The script reads the day and time, compares it against the trading hours, and updates the pill accordingly. No frameworks, no libraries, just a small bit of vanilla JS in line with the rest of the site’s approach.
The 404 page, which took longer than I’d like to admit
This is the one I struggled with the most, and I want to be honest about that because the struggle is where most of the learning lives. The brief asked for a custom 404 page, which sounds simple. You design a friendly error screen, save it, and you’re done. Except a 404 page isn’t a page in the normal sense. It only exists when the server decides to show it, and the server has to be told.
The first version of my custom 404 was visually finished and completely useless. It sat in the project folder and nobody ever saw it, because the server was still serving the default white text on black error page for missing URLs. I went round in circles for a while trying to work out why. The fix, when it came, was an .htaccess directive telling the server to use my custom file for 404 responses. Once that was in place, the server started serving the right page, and everything I’d designed actually became visible.
There were knock on issues. The first time I got it working, my relative links inside the 404 page were broken, because the 404 can be triggered from any URL on the site, and a relative path from “/some/missing/page” isn’t the same as a relative path from the homepage. I had to rewrite all the links inside the 404 to use absolute paths so they’d resolve correctly no matter where the user had landed.
It’s a small page. It is also the only page on the site that has to work in every possible situation, including the situations you can’t predict. Getting it right taught me more about how the server actually serves files than any of the other parts of this project did.
A mobile first responsive layout
The original was responsive in the sense that it didn’t break at smaller widths. The revisited site is responsive in the sense that each breakpoint was designed, not survived. The CSS is written mobile first, with the small screen layout as the base and the wider layouts added as the viewport gets bigger. Particular attention went into the awkward widths between phone and tablet, where the first version had wasted whitespace and orphaned headings sitting on their own lines. The new layout handles those in between widths properly, which is where most of the real world traffic actually lives.
Smaller details that matter
A few of the smaller pieces of the project don’t need a section of their own but should be mentioned. The Meyer CSS reset is in place as a clean foundation, so the site isn’t fighting browser defaults. The code is consistently indented, with comments where the logic isn’t obvious. File and folder names are descriptive, lowercase, no spaces. HTML and CSS were both validated and the errors fixed before submission. Each of these is small. Together they’re the difference between a project that works and a project that’s been finished.
The numbers, before and after
PageSpeed Insights on mobile for the original site:
[Upload your “Report from May 12, 2026” PageSpeed screenshot here. The one showing the mod_1 site at 79 Performance, 91 Accessibility, 96 Best Practices, 92 SEO.]
- Performance: 79
- Accessibility: 91
- Best Practices: 96
- SEO: 92
PageSpeed Insights on mobile for the revisited site:
[Upload your “Report from May 14, 2026” PageSpeed screenshot here. The one showing stalineapen.uk/alfs at 97 Performance, 96 Accessibility, 100 Best Practices, 92 SEO.]
- Performance: 97 (up 18)
- Accessibility: 96 (up 5)
- Best Practices: 100 (up 4)
- SEO: 92 (held steady)
The performance jump is the one I’m proudest of, and as I mentioned earlier, almost all of it traces back to image optimisation and removing render blocking work. Accessibility climbed because every fix was tested with a tool rather than assumed by eye. Best Practices landing at 100 was the reward for the small disciplines like width and height attributes on every image, secure outbound links, no console errors. SEO held steady at 92, which is fine. The score was already in good shape and the real win there is the geolocation work, which doesn’t show up in a Lighthouse score but matters a great deal in the actual search results.
What this project actually taught me
Revisiting your own work is one of the most useful exercises a designer can do. You read your old code the way an editor reads a first draft, with affection but also with the clarity that distance gives you. The fixes are rarely dramatic. Most of them are small, careful, and only obvious once you know what to look for.
The bigger lesson sits underneath all the specific changes. A website is not a design that happens to be on the internet. It is a system. Maintainable structure through includes. Sensible defaults in the reset and the responsive base. Decisions made on behalf of the person visiting before they ever have to make them. The open or closed pill. The skip link. The tested contrast. The 404 page that actually serves. The geolocation tags that put the shop on the map for search.
When I started Alf’s Cycles, I was building pages. By the end of the revisit, I was building a site. Most of that difference is invisible from the screen. It’s in the includes, the alt text, the contrast values, the WebP files, the meta tags pointing search engines at Keswick, and the .htaccess line that makes the 404 page work. That’s the part I wanted this revisit to be about, and it’s the part I’ll be carrying forward.
Both versions are still live, side by side:
- Original: stalineapen.uk/assets/module/mod_1/alfs-cycles-pr/
- Revisited: stalineapen.uk/alfs/
Declaration of AI tools used
In the spirit of academic transparency, this is a record of where AI tools sat alongside the work on this project. The design decisions, the code, the testing, and the final judgement on what shipped were all my own. The AI tools were used as collaborators and assistants in the way a designer might use Stack Overflow, a tutor, or a writing partner.
- Claude AI (Anthropic). Used for drafting and shaping written content, including this blog post. Helpful for working through how to explain technical decisions in plain English, and for restructuring paragraphs when my first pass felt cluttered.
- Claude Code and Claude Code agents. Used during development for quick code review, debugging help, and walking through specific issues like the .htaccess setup for the 404 page. Useful as a second pair of eyes on code I’d already written rather than a replacement for writing it.
- Google Gemini, including Gemini Flash and Gemini Pro models. Used for cross checking ideas and explanations, particularly around responsive layout patterns and accessibility checks. Sometimes useful for getting a second opinion when one model had given an answer I wasn’t fully convinced by.
- ChatGPT (OpenAI). Used for drafting and refining specific paragraphs in written content, and occasionally for rewording sentences that weren’t landing the way I wanted them to.
All AI assisted output was reviewed, edited, and accepted or rejected by me. Where code was suggested by an AI tool, it was read line by line and tested before being committed. Where text was suggested, it was rewritten in my own voice before being published.
Stalin