A useful interface is not born from a coat of paint.
The previous chapter's views already have structure and meaning. Front-end work now begins: create coherent visual identity, adapt layout to screens, make actions obvious, and add only behavior that truly improves the journey.
We will not hide fragile HTML behind effects. CSS will strengthen hierarchy and readability; JavaScript stays progressive; images are chosen for usefulness; caching becomes part of deployment.
Give the task application a responsive interface, add deletion confirmation, optimize images, and ensure every new asset version appears immediately after deployment.
Understand browser assets
An HTML page describes content, while appearance and part of its behavior come from separate assets: CSS, JavaScript, images, fonts, and icons. The browser requests them after receiving the document.
This separation lets one stylesheet serve many pages and lets caching reuse downloaded files. It also requires correct URLs, predictable organization, and a strategy when content changes.
In classic PHPAML, directly accessible files live in public. Private code, configuration, and data must never be exposed by the Web server.
public contains only what the browser must be able to request directly.
Organize CSS, scripts, and images
Start with a simple tree: public/css, public/js, and public/assets. Add subfolders when a real boundary appears, not to populate an empty architecture.
app.css carries shared foundations. Task-specific styles can live in tasks.css when volume justifies it. Name files by responsibility rather than date or author.
Logos, favicons, sitemap, and robots.txt stay directly in public when stable URLs help. Content imagery can be organized under assets/images with descriptive names.
Organization should make assets easy to find and private files hard to expose accidentally.
Build a coherent CSS foundation
Before styling each card, define global foundations: box sizing, colors, typography, reading width, spacing, and focus styles. These decisions create coherence isolated fixes cannot provide.
Use CSS variables for repeated colors, radii, shadows, and spacing. They let the system change without hunting dozens of values and naturally prepare themes.
Avoid overly broad selectors that modify every tag unintentionally. Explicit classes such as task-card or form-error make a rule's effect visible in the template.
Strong design starts with a small system, not an accumulation of fixes.
:root {
--surface: #ffffff;
--text: #17181a;
--accent: #6540d9;
--space-3: 0.75rem;
--space-6: 1.5rem;
}
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; color: var(--text); background: var(--surface); }
.task-grid { display: grid; gap: var(--space-6); }
@media (min-width: 48rem) {
.task-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}Create a responsive layout
Responsive does not mean shrinking everything. Content should rearrange for available space: columns stack, navigation adapts, buttons remain touchable, and text keeps readable measure.
Start with mobile, where constraints force prioritization. Add media queries when content truly benefits from another arrangement rather than targeting an arbitrary device list.
Use min(), max(), clamp(), grid, and flex for fluid dimensions. Check long text, zoom, landscape orientation, and tables; average content hides overflow.
Breakpoints belong to content, not to a phone brand.
Style forms and states
A form should make label, field, help, error, and primary action immediately visible. Spacing and contrast communicate structure before every word is read.
Define hover, focus-visible, disabled, invalid, and loading states. Never remove focus outlines without an obvious alternative, and never communicate errors by color alone.
Keep controls large enough for touch. Disabled buttons should explain why when unclear, and submitting state should prevent duplicate requests.
Every interactive state must remain visible, understandable, and accessible.
Add progressive JavaScript
JavaScript enhances an experience that already works: deletion confirmation, image preview, character counter, or mobile menu. Essential content and forms should retain a functional path without script when reasonable.
Load scripts with defer or as modules so HTML parsing is not blocked. Attach behavior through explicit data attributes rather than classes used only for styling.
Handlers should remain small, clean up effects, and support keyboard and pointer input. Avoid rebuilding a framework on every page; AML View and Engine will cover fully reactive interfaces later.
JavaScript enhances the document; it should not hide the journey's foundations.
document.addEventListener('click', (event) => {
const button = event.target.closest('[data-confirm-delete]');
if (!button) return;
const name = button.dataset.taskName ?? 'this task';
if (!window.confirm(`Delete "${name}"?`)) {
event.preventDefault();
}
});Confirm deletion correctly
Deletion is hard to undo. The button should identify the affected resource and ask for confirmation before submitting DELETE.
Native confirm() is enough for a first safeguard. A custom modal requires more: focus movement, Escape closing, focus restoration, and accessible labels.
Browser confirmation replaces no server security. The controller must still verify CSRF, identity, and authorization because a client can bypass JavaScript entirely.
The interface prevents human mistakes; the server enforces security.
Choose and optimize images
An image needs a purpose: explain, identify, or reinforce hierarchy. Heavy decoration that slows the page without adding meaning should be removed.
Choose an appropriate format: SVG for controlled vector icons, PNG for precise transparency, WebP or AVIF for modern photography. Resize files near their actual display dimensions.
Add width and height to reserve space, loading=lazy for offscreen imagery, and alternative text describing function. Pure decoration uses empty alt so it does not clutter screen readers.
The best image is useful, correctly sized, and accessible.
Understand browser caching
Caching speeds the site by reusing app.css or app.js. But when an URL remains unchanged after editing, visitors may keep an old version and think deployment failed.
Cache busting adds a fingerprint or version to the name: app.a4f82.css. When content changes, the URL changes; old files can remain cached without blocking updates.
In development, hard refresh only for diagnosis. In production, prefer versioned names and coherent headers instead of asking every user to clear cache.
An immutable asset can be cached for a long time when every change creates a new URL.
<link rel="stylesheet" href="/css/app.a4f82.css">
<script src="/js/app.91be2.js" defer></script>Audit performance and behavior
A visually successful page can remain slow or fragile. Inspect requests, transferred sizes, console errors, layout shifts, and scripts that block rendering.
Test keyboard, touch, zoom, and prefers-reduced-motion. Animation should clarify change, remain brief, and be reducible for motion-sensitive users.
Check on a slow network with cold cache, then warm cache. Measure before optimizing so work targets assets that truly cost time.
Front-end quality combines design, accessibility, robustness, and measured performance.
Guided workshop
Finish the task interface.
- Create CSS variables and foundations.
- Style navigation, cards, forms, and states.
- Adapt the page to mobile and tablet.
- Add progressive deletion confirmation.
- Optimize logo, favicon, and content images.
- Add focus-visible and reduced-motion.
- Version CSS and JavaScript for caching.
- Audit network, console, keyboard, and mobile.
Reasoned solution
Remove everything that does not help the journey.
A good solution does not maximize effects. It verifies clear hierarchy, predictable actions, no mobile overflow, and asset weight proportional to usefulness.
In summary
Front end serves content, actions, and people.
You can now organize public assets, build a small CSS system, adapt pages to mobile, add progressive JavaScript, protect deletion, and diagnose caching. These skills remain useful when you move to AML View.
- keep public limited to directly accessible assets
- start with accessible structure and states
- use JavaScript as progressive enhancement
- optimize image formats, dimensions, and loading
- version files to control caching
In chapter 8, we temporarily leave presentation to configure SQLite and migrations for durable application persistence.