--- name: odoo-web-design description: Professional finish for the Odoo frontend of this repo — visual polish, responsive layout and WCAG accessibility across CSS, QWeb/HTML and JS. Use when styling or reviewing website/portal pages (website_sale_aplicoop), adding UI components, or fixing responsive/a11y/design-consistency issues. metadata: type: reference --- # Web design & finish (Odoo 18 frontend) Covers the three layers together: `static/src/css/`, `static/src/js/`, and the QWeb templates in `views/*.xml`. For language-level conventions see `odoo-qweb-html`, `odoo-javascript`, `odoo-xml-views`; this skill is about the **finish**: does it look designed, does it work at 320 px, does it work without a mouse. ## Inherited non-negotiables - No logic in QWeb — prepare everything in the controller. - No business logic in JS — UI and events only. - **No inline `style="..."`** in templates. A style needs a class, and the class needs a token. - Every user-visible string is translatable (see §4). ## 1. Work order Never start by editing a component. Always: 1. **Audit** with the commands in §7. Write down what is inconsistent before touching anything. 2. **Tokens first** (`base/variables.css`). Every value a component needs must already exist as a token. 3. **Component by component**, one file each, media queries co-located at the bottom of that file. 4. **Accessibility pass** per template, top to bottom. 5. **Verify** — lint, contrast, keyboard-only, 320 px, 200 % zoom. Doing 3 before 2 is how a codebase ends up with 61 `!important` and three shades of the same blue. ## 2. Design tokens Odoo 18 ships Bootstrap 5.3 with `$variable-prefix: ''` (`/media/snt/data/odoo/ocb/addons/web/static/src/scss/bootstrap_overridden.scss:51`), so Bootstrap's root custom properties are emitted **unprefixed** into `web.assets_frontend` (via `import_bootstrap.scss` → `@import "root"`). Available in plain CSS, no SCSS needed: ``` --primary --secondary --success --danger --warning --info --light --dark --body-color --body-bg --emphasis-color --secondary-bg --tertiary-bg --border-color --border-radius --border-radius-sm --border-radius-lg --border-radius-xl --border-radius-pill --link-color --link-hover-color --focus-ring-color --focus-ring-width --box-shadow --box-shadow-sm --box-shadow-lg --font-sans-serif --gray-100 … --gray-900 ``` Rules: - **Alias, don't copy.** `--ac-color-primary: var(--primary, #007bff);` keeps the website theme editor in control of the palette. A hardcoded brand hex breaks theming silently. - **Hex literals live only in `base/variables.css`.** A hex anywhere else is a defect. - **Prefix new tokens** (`--ac-…`, aplicoop). Bare names like `--primary-color` sit in Bootstrap's unprefixed namespace and will collide as Odoo adds tokens. - **Never redefine a token inside a media query** to shrink it — use `clamp()` so it scales continuously instead of jumping at one width. - Space and radius come from the scale, never from a typed-in number. If you need a value the scale doesn't have, the scale is wrong — fix the scale. ## 3. Responsive - **Mobile-first, `min-width` only.** Bootstrap 5 breakpoints exclusively: **576 / 768 / 992 / 1200 / 1400**. No 480/720/1600 one-offs — a private breakpoint is a design decision nobody else knows about. - **One range per rule.** Pairing `min-width` and `max-width` to carve a band is almost always a symptom of desktop-first thinking leaking in. - **Media queries belong with their component**, at the bottom of its file. A central `responsive.css` drifts out of sync with the components it overrides and forces `!important`. Don't add to it; empty it as you touch each component. If a rule in `responsive.css` spans multiple components or has no clear owner, move it to the relevant layout partial (e.g. `layout/grid.css`) rather than duplicating it per component; note any such moves in the audit output. - **Prefer intrinsic layout to breakpoints**: `repeat(auto-fill, minmax(min(100%, 16rem), 1fr))`, `clamp()`, `flex-wrap`. Most grids need zero media queries. - `rem` for everything; `px` only for hairlines, borders and shadow offsets. - Touch targets: **24×24 px is the AA floor** (WCAG 2.2 §2.5.8); **44×44 px is §2.5.5, level AAA**, and the size a thumb actually needs — apply it under `@media (pointer: coarse)`. Quantity steppers and icon buttons are the usual offenders. - Must survive **320 px wide** and **200 % zoom** with no horizontal scroll. Details and recipes: `references/responsive.md`. ## 4. Accessibility — WCAG 2.2 AA baseline - **Semantics before ARIA**: `