Web platform design and accessibility guidelines. Use when building web interfaces, auditing accessibility, implementing responsive layouts, or reviewing web UI code. Triggers on tasks involving HTML, CSS, web components, WCAG compliance, responsive design, or web performance.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Instruções da origem · Visualização somente leitura
name
web-design-guidelines
description
Web platform design and accessibility guidelines. Use when building web interfaces, auditing accessibility, implementing responsive layouts, or reviewing web UI code. Triggers on tasks involving HTML, CSS, web components, WCAG compliance, responsive design, or web performance.
Anti-pattern: Using <div> or <span> for interactive elements. Never write <div onclick> when <button> exists.
1.2 ARIA Labels on Interactive Elements
Every interactive element must have an accessible name. Prefer visible text; use aria-label or aria-labelledby only when visible text is insufficient (SC 4.1.2).
<!-- Icon-only button: needs aria-label -->
<button aria-label="Close dialog">
<svg aria-hidden="true">...</svg>
</button>
<!-- Linked by labelledby -->
<h2 id="section-title">Notifications</h2>
<ul aria-labelledby="section-title">...</ul>
<!-- Redundant: visible text is enough -->
<button>Save Changes</button> <!-- No aria-label needed -->
1.3 Keyboard Navigation
All interactive elements must be reachable and operable via keyboard (SC 2.1.1).
Use native interactive elements (<button>, <a href>, <input>, <select>) which are keyboard-accessible by default.
Custom widgets need tabindex="0" to enter tab order and keydown handlers for activation.
Never use tabindex values greater than 0.
Trap focus inside modals; return focus on close.
// Focus trap for modal
dialog.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
const focusable = dialog.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const first = focusable[0];
const last = focusable[focusable.length - 1];
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
});
1.4 Visible Focus Indicators
Never remove focus outlines without providing a visible replacement (SC 2.4.7, enhanced 2.4.11/2.4.12 in WCAG 2.2).
Identify and describe errors in text (SC 3.3.1). Link error messages to inputs with aria-describedby or aria-errormessage.
<label for="email">Email</label>
<input id="email" type="email" aria-describedby="email-error" aria-invalid="true">
<p id="email-error" role="alert">Enter a valid email address, e.g. name@example.com</p>
1.10 ARIA Live Regions
Announce dynamic content changes to screen readers (SC 4.1.3).
<!-- Polite: announced when user is idle -->
<div aria-live="polite" aria-atomic="true">
3 results found
</div>
<!-- Assertive: interrupts current speech -->
<div role="alert">
Your session will expire in 2 minutes.
</div>
<!-- Status messages -->
<div role="status">
File uploaded successfully.
</div>
Use aria-live="polite" by default. Reserve role="alert" / aria-live="assertive" for time-sensitive warnings.
1.11 ARIA Role Quick Reference
Role
Purpose
Native Equivalent
button
Clickable action
<button>
link
Navigation
<a href>
tab / tablist / tabpanel
Tab interface
None
dialog
Modal
<dialog>
alert
Assertive live region
None
status
Polite live region
<output>
navigation
Nav landmark
<nav>
main
Main landmark
<main>
complementary
Aside landmark
<aside>
search
Search landmark
<search> (HTML5)
img
Image
<img>
list / listitem
List
<ul>/<li>
heading
Heading (with aria-level)
<h1>-<h6>
menu / menuitem
Menu widget
None
tree / treeitem
Tree view
None
grid / row / gridcell
Data grid
<table>
progressbar
Progress
<progress>
slider
Range input
<input type="range">
switch
Toggle
<input type="checkbox">
Rule: Prefer native HTML over ARIA. Use ARIA only when no native element exists for the pattern.
2. Responsive Design [CRITICAL]
2.1 Mobile-First Approach
Write base styles for the smallest viewport. Layer complexity with min-width media queries.
/* Or use CSS filter for simple cases */
@media (prefers-color-scheme: dark) {
.decorative-img {
filter: brightness(0.9) contrast(1.1);
}
}
8. Navigation and State [MEDIUM]
8.1 URL Reflects State
Every meaningful view should have a unique URL. Users should be able to bookmark, share, and reload any state.
// Update URL without full page reload
function updateFilters(filters) {
const params = new URLSearchParams(filters);
history.pushState(null, '', `?${params}`);
renderResults(filters);
}
// Restore state from URL on load
const params = new URLSearchParams(location.search);
const initialFilters = Object.fromEntries(params);
// Disable browser auto-restoration for manual control
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
// Save scroll position before navigation
function saveScrollPosition() {
sessionStorage.setItem(`scroll-${location.pathname}`, window.scrollY);
}
// Restore on back/forward
window.addEventListener('popstate', () => {
const saved = sessionStorage.getItem(`scroll-${location.pathname}`);
if (saved) {
requestAnimationFrame(() => window.scrollTo(0, parseInt(saved)));
}
});
9. Touch and Interaction [MEDIUM]
9.1 Touch-Action for Scroll Control
Use touch-action to control gesture behavior on interactive elements.
/* Allow only vertical scrolling (disable horizontal pan and pinch-zoom) */
.vertical-scroll {
touch-action: pan-y;
}
/* Carousel: horizontal scroll only */
.carousel {
touch-action: pan-x;
}
/* Canvas/map: disable all browser gestures */
.canvas {
touch-action: none;
}
9.2 Tap Highlight
Control the tap highlight on mobile WebKit browsers.
button, a {
-webkit-tap-highlight-color: transparent;
}
9.3 Hover and Focus Parity
Every hover interaction must also work with keyboard focus.
Set lang on the <html> element. Use dir="auto" for user-generated content.
<html lang="en" dir="ltr">
<!-- User-generated content: let browser detect direction -->
<p dir="auto">User-submitted text here</p>
<!-- Explicit override for known RTL content -->
<blockquote lang="ar" dir="rtl">...</blockquote>
10.2 Intl APIs for Formatting
Use the Intl API for locale-aware formatting. Never hard-code date or number formats.
// Dates
new Intl.DateTimeFormat('en-US', { dateStyle: 'long' }).format(date);
// "January 15, 2026"
// Numbers
new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(1234.56);
// "1.234,56 EUR"
// Relative time
new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(-1, 'day');
// "yesterday"
// Lists
new Intl.ListFormat('en', { style: 'long', type: 'conjunction' }).format(['a', 'b', 'c']);
// "a, b, and c"
// Plurals
const pr = new Intl.PluralRules('en');
const suffixes = { one: 'st', two: 'nd', few: 'rd', other: 'th' };
function ordinal(n) { return `${n}${suffixes[pr.select(n)]}`; }
10.3 Avoid Text in Images
Text in images cannot be translated, resized, or read by screen readers. Use HTML/CSS text with background images when a styled text overlay is needed.
10.4 CSS Logical Properties
Use logical properties instead of physical ones to support both LTR and RTL layouts.
/* Physical (breaks in RTL) */
/* margin-left: 1rem; padding-right: 2rem; border-left: 1px solid; */
/* Logical (works in LTR and RTL) */
.sidebar {
margin-inline-start: 1rem;
padding-inline-end: 2rem;
border-inline-start: 1px solid var(--color-border);
}
.stack > * + * {
margin-block-start: 1rem;
}
/* Logical shorthands */
.box {
margin-inline: auto; /* left + right */
padding-block: 2rem; /* top + bottom */
inset-inline-start: 0; /* left in LTR, right in RTL */
border-start-start-radius: 8px; /* top-left in LTR, top-right in RTL */
}
Physical
Logical
left / right
inline-start / inline-end
top / bottom
block-start / block-end
margin-left
margin-inline-start
padding-right
padding-inline-end
border-top-left-radius
border-start-start-radius
width
inline-size
height
block-size
text-align: left
text-align: start
10.5 RTL Layout Support
Test layouts in RTL mode. Flexbox and Grid handle RTL automatically with logical properties.
/* This layout works in both LTR and RTL without changes */
.layout {
display: flex;
gap: 1rem;
}
/* Icons that indicate direction need flipping */
[dir="rtl"] .arrow-icon {
transform: scaleX(-1);
}
Evaluation Checklist
Use this checklist when building or reviewing web interfaces.
Accessibility
All images have appropriate alt text
Color contrast meets 4.5:1 (text) and 3:1 (UI components)
All interactive elements are keyboard accessible
Focus indicators are visible (3:1 contrast, 2px minimum perimeter)
Skip navigation link is present
Form inputs have associated labels
Error messages are linked to their inputs
Dynamic content updates use ARIA live regions
No content flashes more than 3 times per second
Page has proper heading hierarchy (h1-h6, no skips)
Landmarks are used correctly (main, nav, header, footer)
Responsive
No horizontal scrolling at 320px width
Touch targets are at least 44x44px
Viewport meta tag is present (no user-scalable=no)
Layout works on mobile, tablet, and desktop
Text is readable without zooming on mobile
Forms
All inputs have visible labels
Autocomplete attributes are set for common fields
Correct input types trigger correct mobile keyboards