website-design-system
Skill9 starsChanged 30 days agoMITView on GitHub
The visual build standards for a new site: mobile-first responsive graphics (WebP/AVIF, sized-to-display, srcset, lazy-load, descriptive alt, no layout shift), dark mode (CSS-variable theme tokens + a no-FOUC script + WCAG AA contrast in BOTH themes), and the brand/theme token block that BRAND.md mirrors. Use when building or reviewing layout, images, theming, or BRAND.md (step 6 of the new-website pipeline). Contrast is enforced by a11y.spec.ts (light+dark). Trigger phrases: "dark mode", "theme toggle", "responsive images", "mobile optimization", "image optimization", "WebP", "layout shift", "CLS", "design system", "theme tokens", "brand colors", "BRAND.md".
2 other projects use a version of this.
Adopted by
Most recently taken up by
- karero/croftweaverword for word, first seen Oct 13, 2026
- kais-aljammal/web-dev-skillstheir own version, first seen Aug 3, 2026
Other versions2 projects use a version of this.
Word for word · 1
- karero/croftweaver★ 9100% same
Edited · 0
None found.
Wrote their own version · 1
- kais-aljammal/web-dev-skills★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository41 other files it gives its agents.
- skills/new-website/templates/AGENTS.mdAGENTS.md
- skills/new-website/templates/CLAUDE.mdCLAUDE.md
- ai-seoSkill
- astro-i18n-setupSkill
- business-listings-setupSkill
- copywritingSkill
- customer-researchSkill
- double-knuthSkill
- facts-checkSkill
- imageSkill
- independent-reviewSkill
- internal-link-auditSkill
- keystatic-setupSkill
- new-websiteSkill
- og-imagesSkill
- outgoing-link-auditSkill
- schema-markupSkill
- search-console-insightsSkill
- search-console-setupSkill
- seo-auditSkill
- seo-repositionSkill
- site-architectureSkill
- website-brand-kitSkill
- website-contact-formSkill
- website-content-guideSkill
- website-hero-carouselSkill
- website-launch-checkSkill
- website-motionSkill
- website-new-pageSkill
- website-permissionsSkill
- website-positioning-checkSkill
- website-positioningSkill
- website-qaSkill
- website-reviewSkill
- website-scorecardSkill
- website-seo-geoSkill
- website-storySkill
- website-taglineSkill
- website-team-setupSkill
- website-testimonialsSkill
- wordpress-inspectorSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 26
Tokens, not hard-coded colours: All colour flows through CSS custom properties.
- Distinctive: line 34
Contrast both themes: every text/background pair passes WCAG AA (4.5:1 body, 3:1 large/UI).
- Very specific: line 43
Size to display, not source: Never ship a 2000px image into an 80px slot.
- Very specific: line 61
Prefer flexible widths: Use min-width / flex / grid auto/fr sizing for any element holding translated text, not a fixed width sized to the …
- Very specific: line 107
Write the column names once, in a list, and use it for the header and for every data-label: the label of a stacked cell must equal its …
- Very specific: line 132
Never put a plaintext email or mailto:your@addr in the HTML source — scrapers harvest it for spam within hours.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Website design system
Owns the how it looks and performs visually layer: mobile graphics, dark
mode, and the theme tokens. Outputs/maintains BRAND.md (template: the new-website
skill's templates/brand.md) and the token block in that skill's
templates/astro/src/styles/global.css. Image rules
are below (WebP/AVIF via Astro's astro:assets); the images.spec.ts test
enforces them. For generating image assets, use the image skill.
Dark mode (first-class)
- Tokens, not hard-coded colours. All colour flows through CSS custom
properties; light is the
:rootdefault, dark overrides under:root[data-theme="dark"], plus a@media (prefers-color-scheme: dark)block for no-JS visitors. The starter ships this exact structure. - No-FOUC script in
<head>setsdata-themefromlocalStorage.themeor the system preference before first paint (already wired inBase.astro). The toggle writeslocalStorage.theme(the starter ships none; if you add one, say so in the privacy page's section 3). - Contrast both themes: every text/background pair passes WCAG AA (4.5:1 body, 3:1 large/UI). A colour that passes in light often fails in dark — the a11y test runs the full light+dark matrix, so check both.
Mobile & responsive graphics
- Mobile first: design from 360px up; tap targets ≥ 44px; no horizontal scroll. Verify at 360 / 768 / 1280 (preview_resize).
- Modern formats: WebP (or AVIF) over JPEG/PNG for photos.
- Size to display, not source. Never ship a 2000px image into an 80px slot;
generate width variants and use
srcset/sizes(or<picture>). - No layout shift: set explicit
width/heightattributes so the box is reserved before the image loads (protects CLS / LCP). Astro's<Image>sets them automatically;images.spec.tsrequires the attributes (a CSS-only aspect-ratio will not satisfy the test). - Lazy vs eager:
loading="lazy"below the fold; the LCP/hero image loads eager withfetchpriority="high"(do NOT lazy-load it). - Alt text on every image (
alt=""only if purely decorative). - Fonts: self-host woff2 with
font-display: swap; preload only the 1–2 used above the fold. Avoid layout shift from late font swaps.
Text-length responsiveness (translated copy)
- Translated text runs longer. German (and many other languages) commonly runs 20–35% longer than the equivalent English copy. A button, nav link, or card sized to fit English placeholder text will silently overflow, wrap ugly, or truncate the moment real translated copy replaces it.
- Prefer flexible widths. Use
min-width/ flex / gridauto/frsizing for any element holding translated text, not a fixedwidthsized to the English string. - Overflow ≠ width: flexible sizing doesn't stop a SINGLE long compound noun
(
Datenschutzerklärung) from bursting a narrow column — that needshyphens: auto(correct per-language via thelangattribute Base.astro already sets) plusoverflow-wrap: break-wordas the fallback; the starter'sglobal.cssships both onbody. Table cells turn hyphenation off (see Tables). - Don't rely on
white-space: nowrap+text-overflow: ellipsisalone as the handling for nav links or button labels — truncating a nav link is usually not acceptable UX (the visitor can no longer tell where it goes). Fine for content where truncation is an accepted tradeoff (e.g. a table cell), not for navigation. - Verify with real translated labels, not English placeholders. When a site ships
astro-i18n-setup'sLanguageSwitcher.astroor any bilingual/multilingual nav, check layout at 360/768/1280 (preview_resize) using the actual shipped copy in every language — not just the English placeholder.
Tables
One style for every table; a page carries no layout CSS for a table. It lives in the starter's
src/styles/tables.css (imported after global.css by Base.astro) and tests/tables.spec.ts checks
it. A site made before this section copies tables.css in, adds the import line to its layout, and
removes each page's own table CSS first.
Two kinds, told apart by what the cells hold:
stack(sentences): a table above 40rem; below it each row stacks, the row header as a title and each cell under its column's name. Four columns of prose cannot share 320px.figures(short numbers,class="num"on a number cell): stays a table on a phone and must fit in 320px. If it no longer fits, make itstack; a scroll bar is not the fix.stack figurestogether is the figures look with the stacked layout.
Markup, every table:
<div class="table-wrap stack" role="region" aria-label="What the table shows" tabindex="0">
<table role="table">
<thead role="rowgroup"><tr role="row">
<th scope="col" role="columnheader">{cols[0]}</th><th scope="col" role="columnheader">{cols[1]}</th>
</tr></thead>
<tbody role="rowgroup">{rows.map((r) => (
<tr role="row"><th scope="row" role="rowheader">{r.item}</th><td role="cell" data-label={cols[1]}>{r.text}</td></tr>
))}</tbody>
</table>
</div>- Write the column names once, in a list, and use it for the header and for every
data-label: the label of a stacked cell must equal its column header, and the test compares the two. Afigurestable needs no per-cell roles and nodata-label. - A stacked table is no longer
display: table. The roles are a fallback for a browser that drops the table when the layout changes; that they work there is not checked. In Chromium, measured once on a real table, the accessibility tree kept the table without them. class="tap"on a link that stands alone in a cell makes it a 44px tap target on a phone.nowrapkeeps a short value (1, 3, 6) on one line.long-head(withstack) widens the first column when the row headers are sentences.- Words are not hyphenated in cells. The body's
hyphens: autosqueezes a narrow first column to fragments ("An-thropic"), so the block setshyphens: manualthere. - A page whose tables come from outside and cannot carry the markup goes into
TABLE_EXEMPTin the spec, with the reason.PAGESstays whole: the sitemap andllms.txtchecks need every live route in it.
What tables.spec.ts checks: every table is in a .table-wrap of one kind with its region, label and
tabindex, scope="col" on every header cell and a <th scope="row"> as the first cell of every row, with <td> for the rest; a stacked table has its roles and a label equal to the header on each cell; at 360 and 320px no
page and no table scrolls sideways; at 641px and above a stacked table is a table again with its header row
showing and no word broken (this catches rules such as overflow-wrap: anywhere that let a column squeeze a
word); no cell has hyphens: auto. It also tests the CSS on a fixture it adds to the
home page, with axe in both themes, so a site with no table still proves the block. Headless Chromium does
not hyphenate, so the hyphen guard reads the computed style, not the layout. Safari and VoiceOver are not
checked.
Email obfuscation (hide addresses from crawlers)
Never put a plaintext email or mailto:your@addr in the HTML source — scrapers harvest it
for spam within hours. Render every address through the EmailLink.astro component
(src/components/EmailLink.astro in the new-website skill's templates/astro/, + its
lib/obfuscate.ts helper): the address is reversed + base64-encoded at build time and
reassembled in the browser, so the served HTML contains no readable address. No-JS visitors
see a still-usable "name [at] domain [dot] com" hint.
<EmailLink address="hello@example.com" subject="Project enquiry" text="Email us" />Rule: zero raw mailto: links and zero literal @-addresses in built HTML — website-qa
checks this. Same idea for any phone number you don't want harvested.
Brand tokens
Mirror BRAND.md's palette into the token block and keep them in sync. Define:
brand (fixed), and per-theme heading/ink/muted/accent/link/line/bg/bg-soft/surface. The
accent and the link colour must pass AA on the background in both themes, which is why
each theme has its own. The optional website-brand-kit does the mirroring with a
check: its intake reads BRAND.md's tables, holds every text colour to 4.5:1 on every
background in both themes, and writes the values into all three colour blocks of
global.css (light, dark, and the dark block for visitors without JavaScript). By hand,
change all three blocks together.
Done means
BRAND.md filled and consistent with the token block; images are WebP, sized,
lazy/eager-correct, with alt; the a11y test (light+dark) is green; layout holds
at 360/768/1280 with no shift; every table is stack or figures and tables.spec.ts is green. Perf numbers (FCP/LCP) are verified in website-qa.
Layout also holds at 360/768/1280 with real (not placeholder) copy in every
shipped language, not just the default locale.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

