meta:title / meta:title-length | title present, ≤ 60 chars |
meta:description / meta:description-length | description present, ≤ 160 chars |
meta:canonical | canonical link |
meta:og:*, meta:og:size | OG tags; image must declare 1200×630 (crop-safe) |
meta:twitter:card | twitter card tag |
meta:json-ld | any application/ld+json script |
meta:robots | not blocked with noindex/nofollow |
meta:sitemap-link | sitemap referenced |
headings:single-h1 | exactly one h1 |
headings:order | h1→h6 sequence, no level skips (h1→h3 is a violation) |
tokens:raw-hex | zero raw hex outside the token block (:root/tokens) |
contrast:wcag-aa | computed WCAG relative luminance, fg/bg pairs ≥ 4.5:1 |
adaptive:scroll-padding | fixed header ⇒ scroll-padding-top present |
adaptive:media-queries | responsive breakpoints exist for tablet widths |
a11y:img-alt | every <img> has an alt attribute (decorative may be empty) — WCAG 1.1.1 / axe image-alt |
a11y:button-name / a11y:link-name | buttons and links have an accessible name (text or aria-label) — WCAG 4.1.2 / axe button-name, link-name |
a11y:form-label | inputs/selects/textareas have a label (<label for>, wrapper, aria-label) — WCAG 4.1.2 / axe label |
a11y:aria-valid | every aria-* attribute name is in the WAI-ARIA 1.2 set — axe aria-valid-attr |
a11y:landmark-unique | at most one <main>; multiple <nav> need distinct labels — WCAG 1.3.1 / axe landmark-unique |
html:doctype | HTML5 doctype on the first line |
html:charset | charset declared as utf-8 |
html:viewport | responsive viewport meta present |
html:lang | <html lang> with a BCP 47 code (a11y + SEO) |
html:dir-rtl | RTL languages (ar/he/fa/ur/yi) require dir="rtl" |
html:unique-id | no duplicate id attributes |
html:semantic | semantic elements used: header, main, footer |
html:favicons | favicon link present |
html:web-app-manifest | manifest.json referenced (PWA) |
html:sri | CDN-hosted scripts carry integrity (SRI); local scripts exempt |
html:defer-async | external scripts load with defer/async/type=module (no render-blocking) |
html:input-types | inputs declare a type (not defaulting to text) |
images:dimensions | img has width/height (CLS prevention) |
images:lazy-loading | 3+ images lazy-load offscreen content |
images:srcset | responsive srcset used for fixed-size images |
images:modern-format | raster jpg/png converted to webp/avif |
js:no-inline | no inline handlers (onclick=…) or inline <script> blocks |
js:no-console | no console.log/debug/warn in HTML |
css:focus-visible | visible :focus-visible indicator for keyboard users |
css:print | @media print stylesheet exists |
css:dark-mode | prefers-color-scheme dark mode supported |
css:font-display | webfonts use font-display: swap (no FOIT) |
perf:resource-hints | preload/preconnect/dns-prefetch hints for critical origins (LCP) |
security:https | no http:// URLs in src/href |
security:noopener | target="_blank" links carry rel="noopener" |
privacy:consent | cookie/consent mention present (GDPR / 152-ФЗ) |
nav:back-to-top | long pages have a way back to top — logo links to top and/or a floating scroll-to-top button (bottom-right, aria-label, appears after scroll) — WCAG 2.4.1 / UX pattern |