342 lines
9.5 KiB
Markdown
342 lines
9.5 KiB
Markdown
|
|
# Visual Design Audit — quiXzoom & Landvex
|
|||
|
|
> Production-grade. No generic observations. Every finding must be implementable.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## STOP CONDITION
|
|||
|
|
|
|||
|
|
Revisionen är inte klar förrän:
|
|||
|
|
|
|||
|
|
- 0 horisontella overflow-fel finns kvar
|
|||
|
|
- 0 inkonsekvenser mellan header/footer-versioner finns kvar
|
|||
|
|
- 0 motstridiga siffror/claims finns kvar
|
|||
|
|
- alla WCAG 2.2 AA-krav passerar
|
|||
|
|
- alla fynd har en implementerbar fix med exakt selector + CSS
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## FÖRBJUDNA UTDATA
|
|||
|
|
|
|||
|
|
Ej tillåtet:
|
|||
|
|
|
|||
|
|
- "looks good"
|
|||
|
|
- "consider improving"
|
|||
|
|
- "might benefit from"
|
|||
|
|
- "increase spacing"
|
|||
|
|
- "improve responsiveness"
|
|||
|
|
- "spacing could be improved"
|
|||
|
|
|
|||
|
|
Varje observation måste sluta i:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
selector: <exact CSS selector>
|
|||
|
|
rotorsak: <root cause>
|
|||
|
|
fix: <exact CSS property + value>
|
|||
|
|
breakpoint: <exact px value if responsive>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Annars är fyndet ogiltigt och ska inte inkluderas.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## FLÖDE
|
|||
|
|
|
|||
|
|
### Fas 1 — Rendera & dokumentera
|
|||
|
|
|
|||
|
|
1. Öppna sidan i browser (desktop 1440px, mobil 390px)
|
|||
|
|
2. Ta screenshot av hela sidan (fullPage)
|
|||
|
|
3. Kör i konsolen:
|
|||
|
|
```js
|
|||
|
|
// Hitta alla overflow-element
|
|||
|
|
(()=>{const r=[];document.querySelectorAll('*').forEach(el=>{if(el.scrollWidth>el.offsetWidth)r.push({el:el.tagName+'.'+[...el.classList].join('.'),w:el.scrollWidth,ow:el.offsetWidth})});return r})()
|
|||
|
|
```
|
|||
|
|
4. Kör Lighthouse (Performance + Accessibility + SEO) via browser
|
|||
|
|
5. Kör axe-core för WCAG 2.2 AA
|
|||
|
|
6. Dokumentera ALLA fel innan du skriver en rad CSS
|
|||
|
|
|
|||
|
|
### Fas 2 — Stack-identifiering (INGEN fråga till användaren)
|
|||
|
|
|
|||
|
|
Identifiera stacken autonomt:
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
// I konsolen:
|
|||
|
|
window.__NEXT_DATA__ // Next.js
|
|||
|
|
window.__nuxt__ // Nuxt
|
|||
|
|
window.React // React
|
|||
|
|
document.querySelector('[data-reactroot]') // React
|
|||
|
|
document.querySelector('[class*="tw-"]') // Tailwind
|
|||
|
|
document.querySelector('[class*="css-"]') // CSS-in-JS (emotion/styled)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Kontrollera också:
|
|||
|
|
- `<link rel="stylesheet">` href-mönster
|
|||
|
|
- class-namnkonventioner (BEM, atomic, utility)
|
|||
|
|
- `<script src>` bundle-namn
|
|||
|
|
|
|||
|
|
→ Rapportera stack som del av audit-header.
|
|||
|
|
→ Fråga användaren **ENDAST** om stacken är ett intern proprietary system som inte går att identifiera med ovan.
|
|||
|
|
|
|||
|
|
### Fas 3 — Systematisk fix
|
|||
|
|
|
|||
|
|
Skriv CSS-fixar i exakt prioritetsordning:
|
|||
|
|
|
|||
|
|
1. Overflow/layout-krascher (blocking)
|
|||
|
|
2. WCAG-fel (blocking)
|
|||
|
|
3. Core Web Vitals (high impact)
|
|||
|
|
4. Trust/Enterprise credibility (high impact)
|
|||
|
|
5. SEO surface (medium impact)
|
|||
|
|
6. Kosmetik (low impact)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## SEKTIONER
|
|||
|
|
|
|||
|
|
### A — Overflow & Layout
|
|||
|
|
|
|||
|
|
Kör overflow-detektorn (se Fas 1, steg 3).
|
|||
|
|
|
|||
|
|
För varje träff:
|
|||
|
|
```
|
|||
|
|
element: <selector>
|
|||
|
|
scrollWidth: Xpx > offsetWidth: Ypx
|
|||
|
|
rotorsak: [tex. img utan max-width, pre utan overflow, grid utan min-width:0]
|
|||
|
|
fix: selector { overflow: hidden; } / max-width: 100%; / min-width: 0;
|
|||
|
|
breakpoint: <px>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### B — Typography
|
|||
|
|
|
|||
|
|
Kontrollera:
|
|||
|
|
- Line-length > 75ch på desktop → `max-width: 65ch`
|
|||
|
|
- Font-size < 16px body → läs computed style
|
|||
|
|
- Font-swap synlig → `font-display: swap` + `<link rel=preload>`
|
|||
|
|
- FOUT/FOIT → dokumentera med filmstrip
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
selector: body
|
|||
|
|
computed font-size: Xpx (expected: ≥16px)
|
|||
|
|
fix: font-size: 1rem (16px)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### C — Spacing & Grid
|
|||
|
|
|
|||
|
|
- Kontrollera att spacing följer ett konsekvent system (4px/8px grid)
|
|||
|
|
- Identifiera element med magic numbers (ex. `padding: 13px 17px`)
|
|||
|
|
- Rapportera med computed values, inte antaganden
|
|||
|
|
|
|||
|
|
### D — Color & Contrast
|
|||
|
|
|
|||
|
|
Mät kontrastförhållande med:
|
|||
|
|
```js
|
|||
|
|
// Computed contrast via APCA eller WCAG AA formula
|
|||
|
|
// Minsta godkänd: 4.5:1 (normal text), 3:1 (large text ≥18pt/14pt bold)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Rapportera varje fel:
|
|||
|
|
```
|
|||
|
|
element: .nav-link
|
|||
|
|
foreground: #888888
|
|||
|
|
background: #0a0a0a
|
|||
|
|
ratio: 2.8:1 (required: 4.5:1)
|
|||
|
|
fix: color: #a8a8a8; /* ratio: 4.6:1 */
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### E — Responsivitet
|
|||
|
|
|
|||
|
|
Testa exakt på: 375px, 390px, 430px, 768px, 1024px, 1280px, 1440px, 1920px
|
|||
|
|
|
|||
|
|
För varje breakpoint — screenshot + overflow-scan.
|
|||
|
|
|
|||
|
|
### F — Interactive States
|
|||
|
|
|
|||
|
|
Kontrollera för alla klickbara element:
|
|||
|
|
- `:hover` state definierad
|
|||
|
|
- `:focus-visible` state med synlig outline (WCAG 2.4.11)
|
|||
|
|
- `:active` state
|
|||
|
|
- Disabled-state om relevant
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
// Testa focus-visible
|
|||
|
|
document.querySelectorAll('a,button,input,select,textarea').forEach(el=>{
|
|||
|
|
const s = getComputedStyle(el,':focus-visible');
|
|||
|
|
if(s.outlineWidth==='0px'&&s.boxShadow==='none') console.warn('no focus style',el)
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### G — Images & Media
|
|||
|
|
|
|||
|
|
- Alla `<img>` har `width` + `height` attribut (CLS prevention)
|
|||
|
|
- `loading="lazy"` på below-fold images
|
|||
|
|
- `alt`-texter är beskrivande (inte tomma, inte "image")
|
|||
|
|
- SVG har `role="img"` + `aria-label` eller är `aria-hidden="true"`
|
|||
|
|
|
|||
|
|
### H — Header & Footer Consistency
|
|||
|
|
|
|||
|
|
Kontrollera att header och footer är identiska på ALLA sidor:
|
|||
|
|
- Logo
|
|||
|
|
- Navigation items
|
|||
|
|
- CTA-knappar
|
|||
|
|
- Copyright-text och år
|
|||
|
|
- Juridiska länkar
|
|||
|
|
|
|||
|
|
Rapportera varje avvikelse:
|
|||
|
|
```
|
|||
|
|
page: /methodology/
|
|||
|
|
element: footer
|
|||
|
|
avvikelse: saknar "Privacy Policy" länk (finns på /index)
|
|||
|
|
fix: lägg till <a href="/privacy/">Privacy Policy</a> i footer nav
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## K.1 — Performance & Core Web Vitals
|
|||
|
|
|
|||
|
|
Mät och rapportera:
|
|||
|
|
|
|||
|
|
- **LCP** (Largest Contentful Paint) — target < 2.5s
|
|||
|
|
- **CLS** (Cumulative Layout Shift) — target < 0.1
|
|||
|
|
- **INP** (Interaction to Next Paint) — target < 200ms
|
|||
|
|
|
|||
|
|
Identifiera alla visuella orsaker till:
|
|||
|
|
- Layout shifts → `width`/`height` saknas på media, font-swap, dynamiskt injicerat innehåll
|
|||
|
|
- Font swaps → FOUT, FOIT, `font-display` inte satt
|
|||
|
|
- Image jumps → `aspect-ratio` saknas, lazy-load utan placeholder
|
|||
|
|
- Counter animations → `will-change: transform`, reducera om `prefers-reduced-motion`
|
|||
|
|
|
|||
|
|
För varje problem:
|
|||
|
|
```
|
|||
|
|
metric: CLS / LCP / INP
|
|||
|
|
impact: +0.XX CLS / +XXXms LCP
|
|||
|
|
selector: <element>
|
|||
|
|
rotorsak: <exakt orsak>
|
|||
|
|
fix: <exakt CSS/HTML-attribut>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## K.2 — Trust & Enterprise Readiness
|
|||
|
|
|
|||
|
|
För quiXzoom och Landvex är trovärdighet lika viktig som design.
|
|||
|
|
|
|||
|
|
Kontrollera närvaro och kvalitet av:
|
|||
|
|
|
|||
|
|
- [ ] Kontaktuppgifter (adress, e-post, telefon om relevant)
|
|||
|
|
- [ ] Organisationsinformation (org.nr, registrerat land, legal entity)
|
|||
|
|
- [ ] Legal footer (© år, entity-namn, jurisdiktion)
|
|||
|
|
- [ ] Privacy policy (länkad från footer + cookie-banner)
|
|||
|
|
- [ ] Terms of service
|
|||
|
|
- [ ] Methodology/how-it-works page
|
|||
|
|
- [ ] Case studies eller proof-of-concept
|
|||
|
|
- [ ] Uptime/status page
|
|||
|
|
- [ ] Trust-badges (GDPR, Stripe, SSL)
|
|||
|
|
- [ ] Named team eller tydlig company-sida
|
|||
|
|
|
|||
|
|
Flagga visuella signaler som får sajten att uppfattas som:
|
|||
|
|
|
|||
|
|
- **Startup prototype**: placeholder-text, "lorem ipsum", "coming soon" utan datum
|
|||
|
|
- **Affiliate site**: överdrivna earning-claims utan kontext, inga juridiska disclaimers
|
|||
|
|
- **Landing page only**: inga sekundära sidor i navigation, ingen intern länkning
|
|||
|
|
|
|||
|
|
För varje enterprise credibility-brist:
|
|||
|
|
```
|
|||
|
|
signal: saknar org.nr i footer
|
|||
|
|
impact: ser ut som anonymous affiliate site
|
|||
|
|
fix: lägg till "Landvex AB · Org.nr 559141-7042 · Tyresö, Sweden" i footer
|
|||
|
|
selector: footer .legal-copy
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Föreslå exakta komponenter som höjer enterprise-känslan:
|
|||
|
|
- Trust bar (logotyper av integrations/partners)
|
|||
|
|
- Security certifications
|
|||
|
|
- Named press mentions
|
|||
|
|
- Verifierbara testimonials (namn + roll + företag)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## K.3 — SEO Surface Audit
|
|||
|
|
|
|||
|
|
Identifiera visuella element som påverkar:
|
|||
|
|
|
|||
|
|
**Crawlability:**
|
|||
|
|
- Text gömd bakom JavaScript-tabs utan SSR → Googlebot ser det inte
|
|||
|
|
- Viktigt innehåll i `display:none` utan progressiv disclosure
|
|||
|
|
- Bilder utan alt-text
|
|||
|
|
|
|||
|
|
**Entity Recognition:**
|
|||
|
|
- H1 är unik per sida (kör: `document.querySelectorAll('h1').length`)
|
|||
|
|
- Brand-namn nämns i H1 eller inom första 100 ord av body-text
|
|||
|
|
- Schema-relaterat innehåll är visuellt synligt (inte bara i `<script type="application/ld+json">`)
|
|||
|
|
|
|||
|
|
**Topical Authority:**
|
|||
|
|
- Interna länkar exponeras visuellt (crawlbara anchor-taggar, inga JavaScript-only navigationer)
|
|||
|
|
- Viktiga entiteter (branschtermer, produktnamn) är synliga i rubriker och brödtext
|
|||
|
|
- FAQ-innehåll är synligt i DOM utan JavaScript
|
|||
|
|
|
|||
|
|
För varje SEO-brist:
|
|||
|
|
```
|
|||
|
|
issue: FAQ-svar gömt bakom JS-toggle
|
|||
|
|
impact: Google ser inte FAQ-innehåll, förlorar FAQ-rich-result
|
|||
|
|
selector: .faq-answer[style="display:none"]
|
|||
|
|
fix: använd <details>/<summary> (native, crawlbar) eller SSR-rendera med CSS toggle
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Rapportera alla designbeslut som försämrar SEO-signaler.**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## OUTPUT FORMAT
|
|||
|
|
|
|||
|
|
### Audit Header
|
|||
|
|
```
|
|||
|
|
URL: https://www.quixzoom.com/
|
|||
|
|
Date: YYYY-MM-DD
|
|||
|
|
Viewport tested: 1440px desktop / 390px mobile
|
|||
|
|
Stack identified: [ramverk, CSS-approach]
|
|||
|
|
Lighthouse scores: Performance XX | Accessibility XX | SEO XX | BP XX
|
|||
|
|
WCAG 2.2 AA violations: N
|
|||
|
|
Overflow elements found: N
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Per Finding
|
|||
|
|
```
|
|||
|
|
ID: A-001
|
|||
|
|
Section: A — Overflow
|
|||
|
|
Severity: BLOCKING / HIGH / MEDIUM / LOW
|
|||
|
|
Page: /
|
|||
|
|
Viewport: 390px mobile
|
|||
|
|
Screenshot: [bifogad]
|
|||
|
|
|
|||
|
|
Observation: [exakt vad som är fel]
|
|||
|
|
selector: nav .nav-links
|
|||
|
|
rotorsak: flex-wrap: nowrap på container med overflow: visible
|
|||
|
|
fix: .nav-links { flex-wrap: wrap; } eller overflow: hidden på parent
|
|||
|
|
breakpoint: < 768px
|
|||
|
|
metric impact: CLS +0.05 (layout reflow vid render)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Summary Table
|
|||
|
|
```
|
|||
|
|
| ID | Sida | Severity | Sektion | Status |
|
|||
|
|
|-------|------|----------|---------|--------|
|
|||
|
|
| A-001 | / | BLOCKING | Overflow| OPEN |
|
|||
|
|
| B-002 | / | HIGH | Typography | OPEN |
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## SAJTER ATT AUDITERAS
|
|||
|
|
|
|||
|
|
1. https://www.quixzoom.com/ (alla undersidor i sitemap)
|
|||
|
|
2. https://www.landvex.com/ (alla undersidor i sitemap)
|
|||
|
|
|
|||
|
|
Börja med startsidor desktop → mobil, sedan sub-sidor med `<200` ms LCP.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## NOTES
|
|||
|
|
|
|||
|
|
- quiXzoom: CloudFront CDN framför origin — testa med `curl -H "Cache-Control: no-cache"` för att se origin-svar vs cached
|
|||
|
|
- Landvex: Direct nginx → test mot origin direkt via `curl -H "Host: www.landvex.com" http://127.0.0.1/`
|
|||
|
|
- Valuta: **aldrig SEK** i copy — rapportera som BLOCKING om hittat
|
|||
|
|
- Credits-siffror: 12–80 per mission är canonical — rapportera avvikelse som HIGH
|