Fixed cart icon
Stays anchored in the corner at all times — always reachable, regardless of scroll position.
A single-page e-commerce concept for a boutique handmade cafe — designed and built with semantic HTML, vanilla JavaScript, and a sticky shopping cart experience.
Concept
The cost calculator requirement aligned perfectly with the mental model of a quick-service morning stop: pick a couple of items, see the total update instantly, check out. I wanted to build something that felt genuinely real — not a generic template exercise.
I deliberately chose a small, curated menu rather than a large catalog. The constraint strengthened the design: a focused shop section that matched the cafe's intimate, boutique identity.
The fixed 1280px layout also influenced the shop structure. Two columns — products on the left, cart always visible on the right — mimics holding a physical menu while watching your order tally up like a receipt.
Typography pairs Quicksand (rounded, friendly geometry for UI) with Caveat (handwritten feel in the About section) — reinforcing the artisan brand without sacrificing readability.
Process
I built the site in deliberate phases, resolving each layer of complexity before moving to the next.
Defined the shop concept, product lineup, brand voice, and full information architecture before writing any code. Created a content inventory of all six items with names, descriptions, and pricing.
Established the Sage Green + Warm Orange color system as CSS custom properties, enabling the dark/light mode toggle as a single class swap on body.dark-mode. Locked in type choices and spacing tokens.
Built low-fidelity wireframes before touching code. The most critical decision: two-column shop layout with sticky cart sidebar, confirmed to keep the order total always visible — reducing checkout friction.
Challenged myself to write semantic HTML with almost zero div tags — using <section>, <article>, <hgroup>, <aside>, <figure> throughout. This improved accessibility and made JS selection predictable.
Cart logic (add/remove/re-render), real-time total with 8% tax, hero fade carousel, contact form with conditional regex validation, customer object creation on submit, and localStorage theme persistence.
Rebuilt the layout for mobile — and identified a new problem in the process. See the next section.
UX Decision
The two-column desktop layout works because both panels are always visible. On mobile, that collapses to a single column — and the cart gets pushed below the entire product list. A user could add items and have no feedback about where their order is, or how to check out without scrolling to the bottom.
Stays anchored in the corner at all times — always reachable, regardless of scroll position.
Updates every time an item is added or removed, giving instant visual confirmation of cart state.
Tapping the icon jumps to the Your Order section — no scrolling, direct path to checkout.
This pattern mirrors what users already know from mobile ordering apps. The anchor jump is a deliberate, practical choice: straightforward to implement, and meaningfully better than offering no shortcut at all.
Thinking ahead: A slide-up drawer would eliminate the back-and-forth of jumping to the cart and scrolling back up to keep ordering. That's the logical next iteration — but for this project, the anchor jump solved the core problem cleanly.
Process Note
I used AI tools (GitHub Copilot and Claude by Anthropic) as collaborative thinking and learning partners throughout this project:
Reflection
Cart state management was the steepest climb — pushing product objects, removing by ID, and rebuilding the DOM each time without duplicating nodes. Conditional form validation (phone validates only if the user picks phone; email only if email) also took several iterations to get right.
The most satisfying moment: clicking Add and watching the cart total update live. Going back to make the site responsive — and realizing mid-process that layout wasn't the only thing that needed fixing on mobile — was the most useful learning. Asking "what does a user actually need here" rather than "does this display correctly" is the difference between a coded exercise and a considered design.