#!/usr/bin/env python3
"""
Generate comprehensive HTML/CSS training data for Dev-AI.
Covers: semantic markup, accessibility, responsive design, CSS specificity,
layout patterns, modern CSS features, performance, and best practices.
Target: 100-120 high-quality entries.
"""
import json
import os
import random
from pathlib import Path
BASE = Path(__file__).parent.parent / "data" / "processed"
def g(issue, bad, good):
return {
"messages": [
{"role": "user", "content": f"Review this HTML/CSS code:\n\n```html\n{bad}\n```"},
{"role": "assistant", "content": f"**Issue: {issue}**\n\n**Fix:**\n```html\n{good}\n```"}
],
"source": "html_css_training",
"tags": ["html_css", issue.lower().replace(" ", "_")]
}
entries = []
# =============================================================================
# SEMANTIC HTML (12 entries)
# =============================================================================
entries.append(g(
"Div-based layout (div soup)",
"<div class=\"header\">\n <div class=\"logo\">...</div>\n <div class=\"nav\">\n <div class=\"nav-item\">Home</div>\n </div>\n</div>\n<div class=\"main\">\n <div class=\"article\">\n <div class=\"title\">...</div>\n <div class=\"content\">...</div>\n </div>\n</div>\n<div class=\"footer\">...</div>",
"<header>\n <a href=\"/\" aria-label=\"Home\"><img src=\"logo.svg\" alt=\"Site logo\"></a>\n <nav aria-label=\"Main\">\n <a href=\"/\">Home</a>\n </nav>\n</header>\n<main>\n <article>\n <h1>Title</h1>\n <p>Content...</p>\n </article>\n</main>\n<footer>...</footer>"
))
entries.append(g(
"Missing lang attribute",
"<!DOCTYPE html>\n<html>\n<head><title>Page</title></head>\n<body>...</body>\n</html>",
"<!DOCTYPE html>\n<html lang=\"en\">\n<head><title>Page</title></head>\n<body>...</body>\n</html>\n// lang attribute is required for accessibility and SEO"
))
entries.append(g(
"Using <b>/<i> instead of <strong>/<em>",
"<b>Important warning</b>\n<i>Emphasized text</i>",
"<strong>Important warning</strong>\n<em>Emphasized text</em>\n// strong/em convey meaning, not just style\n// b/i are for visual styling without semantic emphasis"
))
entries.append(g(
"Missing heading hierarchy",
"<h1>Page Title</h1>\n<h3>Section</h3>\n<h2>Subsection</h2>\n// Skips h2, goes h1 -> h3",
"<h1>Page Title</h1>\n<h2>Section</h2>\n<h3>Subsection</h3>\n// Headings must follow sequential order\n// Screen readers use heading structure to navigate"
))
entries.append(g(
"Table without semantic elements",
"<table>\n <tr><td>Name</td><td>Age</td></tr>\n <tr><td>Alice</td><td>30</td></tr>\n</table>",
"<table>\n <thead>\n <tr><th>Name</th><th>Age</th></tr>\n </thead>\n <tbody>\n <tr><td>Alice</td><td>30</td></tr>\n </tbody>\n</table>"
))
entries.append(g(
"Using <br> for spacing",
"<p>Line 1</p>\n<br><br>\n<p>Line 2</p>",
"<p>Line 1</p>\n<p>Line 2</p>\n// Use CSS margin for spacing, not <br> tags\n// <br> is for line breaks within text (addresses, poetry)"
))
entries.append(g(
"Missing alt text on images",
"<img src=\"hero.jpg\">\n<img src=\"icon.png\">",
"<img src=\"hero.jpg\" alt=\"Person planting seeds in garden\">\n<img src=\"icon.png\" alt=\"\"> // Decorative image - empty alt\n// All images need alt. Decorative images use alt=\"\""
))
entries.append(g(
"Using <a> for non-navigation",
"<a href=\"#\" onclick=\"openModal()\">Open Modal</a>\n// Not a navigation link",
"<button type=\"button\" onclick=\"openModal()\">Open Modal</button>\n// Buttons for actions, links for navigation\n// <a> should have a real href for accessibility"
))
entries.append(g(
"Missing form labels",
"<form>\n <input type=\"text\" placeholder=\"Name\">\n <input type=\"email\" placeholder=\"Email\">\n <button>Submit</button>\n</form>",
"<form>\n <label for=\"name\">Name</label>\n <input type=\"text\" id=\"name\" required>\n <label for=\"email\">Email</label>\n <input type=\"email\" id=\"email\" required>\n <button type=\"submit\">Submit</button>\n</form>"
))
entries.append(g(
"Using <div> for text content",
"<div class=\"paragraph\">This is a paragraph of text.</div>\n<div class=\"paragraph\">Another paragraph.</div>",
"<p>This is a paragraph of text.</p>\n<p>Another paragraph.</p>\n// <p> is for paragraphs, <div> is for grouping"
))
entries.append(g(
"Missing main landmark",
"<div id=\"content\">\n <h1>Title</h1>\n <p>Content...</p>\n</div>",
"<main id=\"content\">\n <h1>Title</h1>\n <p>Content...</p>\n</main>\n// <main> marks the primary content\n// Only one <main> per page"
))
entries.append(g(
"Using abbreviations without definition",
"<p>Use the API for integration.</p>\n// API is abbreviated, undefined",
"<p>Use the <abbr title=\"Application Programming Interface\">API</abbr> for integration.</p>\n// <abbr> provides expanded text for accessibility"
))
# =============================================================================
# ACCESSIBILITY (12 entries)
# =============================================================================
entries.append(g(
"Missing focus styles",
"a:focus {\n outline: none;\n}",
"a:focus {\n outline: 2px solid #0066cc;\n outline-offset: 2px;\n}\n// Never remove outline without replacement\n// Focus indicators are essential for keyboard navigation"
))
entries.append(g(
"Inline event handlers",
"<button onclick=\"doSomething()\">Click</button>",
"<button type=\"button\" id=\"action-btn\">Click</button>\n\n<script>\ndocument.getElementById('action-btn').addEventListener('click', doSomething);\n</script>\n// Separate structure from behavior"
))
entries.append(g(
"Color-only information",
"<p><span style=\"color: red;\">Error:</span> Invalid input</p>\n// Red color indicates error, no other indicator",
"<p role=\"alert\">\n <span aria-hidden=\"true\">⚠️</span>\n <strong>Error:</strong> Invalid input\n</p>\n// Don't rely on color alone\n// Add text, icons, or ARIA roles"
))
entries.append(g(
"Missing skip navigation link",
"<nav>\n <a href=\"/1\">One</a>\n <a href=\"/2\">Two</a>\n <a href=\"/3\">Three</a>\n <!-- 50 more links -->\n</nav>",
"<a href=\"#main\" class=\"skip-link\">Skip to main content</a>\n\n<style>\n.skip-link {\n position: absolute;\n left: -9999px;\n}\n.skip-link:focus {\n left: 0;\n}\n</style>\n// Skip link lets keyboard users bypass navigation"
))
entries.append(g(
"aria-label missing on icon button",
"<button class=\"icon-btn\">\n <svg>...</svg>\n</button>\n// Icon button with no text",
"<button class=\"icon-btn\" aria-label=\"Close dialog\">\n <svg aria-hidden=\"true\"><use href=\"#close-icon\"/></svg>\n</button>\n// aria-label describes the action\n// Decorative SVGs use aria-hidden"
))
entries.append(g(
"Table without caption or scope",
"<table>\n <tr><td>Q1</td><td>$100</td></tr>\n <tr><td>Q2</td><td>$150</td></tr>\n</table>",
"<table>\n <caption>Quarterly Revenue</caption>\n <thead>\n <tr><th scope=\"col\">Quarter</th><th scope=\"col\">Revenue</th></tr>\n </thead>\n <tbody>\n <tr><td>Q1</td><td>$100</td></tr>\n <tr><td>Q2</td><td>$150</td></tr>\n </tbody>\n</table>"
))
entries.append(g(
"Missing role on custom component",
"<div class=\"dropdown\">\n <div class=\"dropdown-toggle\" tabindex=\"0\">Menu</div>\n <div class=\"dropdown-menu\">\n <a href=\"/1\">One</a>\n </div>\n</div>",
"<div class=\"dropdown\" role=\"combobox\" aria-expanded=\"false\">\n <div class=\"dropdown-toggle\" tabindex=\"0\" role=\"button\">Menu</div>\n <div class=\"dropdown-menu\" role=\"listbox\">\n <a href=\"/1\" role=\"option\">One</a>\n </div>\n</div>\n// Use ARIA roles to convey semantics to screen readers"
))
entries.append(g(
"Link text not descriptive",
"<a href=\"/details\">Click here</a>\n<a href=\"/docs\">Read more</a>\n// Link text doesn't describe destination",
"<a href=\"/details\">View order details</a>\n<a href=\"/docs\">Read API documentation</a>\n// Link text should be meaningful on its own"
))
entries.append(g(
"Missing live region for dynamic content",
"<div id=\"results\"></div>\n// Content updated dynamically, screen readers won't know",
"<div id=\"results\" aria-live=\"polite\" aria-atomic=\"true\"></div>\n// aria-live announces changes to screen readers\n// polite = wait for pause, assertive = interrupt"
))
entries.append(g(
"Form without error association",
"<form>\n <input type=\"email\" id=\"email\">\n <span class=\"error\">Invalid email</span>\n</form>\n// Error not associated with input",
"<form>\n <label for=\"email\">Email</label>\n <input type=\"email\" id=\"email\" aria-describedby=\"email-error\" aria-invalid=\"true\">\n <span id=\"email-error\" class=\"error\">Invalid email</span>\n</form>"
))
entries.append(g(
"Video without captions",
"<video src=\"demo.mp4\" controls></video>",
"<video src=\"demo.mp4\" controls>\n <track src=\"captions.vtt\" kind=\"subtitles\" srclang=\"en\" label=\"English\">\n</video>\n// Captions are required for accessibility\n// <track> element provides subtitle/caption support"
))
entries.append(g(
"Missing landmarks",
"<div class=\"wrapper\">\n <div class=\"header\">...</div>\n <div class=\"nav\">...</div>\n <div class=\"content\">...</div>\n <div class=\"sidebar\">...</div>\n <div class=\"footer\">...</div>\n</div>",
"<div class=\"wrapper\">\n <header>...</header>\n <nav aria-label=\"Main\">...</nav>\n <main>...</main>\n <aside>...</aside>\n <footer>...</footer>\n</div>\n// Semantic landmarks improve screen reader navigation"
))
# =============================================================================
# CSS SPECIFICITY & SELECTORS (10 entries)
# =============================================================================
entries.append(g(
"Using !important",
".btn {\n color: white;\n background: blue;\n}\n.btn.primary {\n background: red !important;\n}",
".btn {\n color: white;\n background: blue;\n}\n.btn--primary {\n background: red;\n}\n// Fix specificity with better selectors, not !important\n// !important makes CSS unmaintainable"
))
entries.append(g(
"Overly specific selectors",
"div.container > ul.list > li.item > a.link {\n color: blue;\n}\n// Specificity: 0,4,0 - hard to override",
".link {\n color: blue;\n}\n// Use single-class selectors (0,1,0)\n// Keep specificity low and predictable"
))
entries.append(g(
"ID selectors for styling",
"#header {\n background: #333;\n}\n#sidebar {\n width: 300px;\n}\n// IDs have high specificity and can't be reused",
".header {\n background: #333;\n}\n.sidebar {\n width: 300px;\n}\n// Use classes for styling, IDs for JavaScript hooks"
))
entries.append(g(
"Descendant selector abuse",
".nav .menu .item .link .icon {\n color: red;\n}\n// Deep nesting - fragile and high specificity",
".icon--nav {\n color: red;\n}\n// BEM-style: block__element--modifier\n// Or flat selectors with descriptive names"
))
entries.append(g(
"Universal selector in performance-critical path",
".card * {\n box-sizing: border-box;\n}\n// Matches every element inside .card",
"* {\n box-sizing: border-box;\n}\n// Apply universal reset once at the top level\n// Avoid * in component selectors for performance"
))
entries.append(g(
"Adjacent sibling selector fragility",
"h1 + p {\n font-size: 1.2rem;\n}\n// Breaks if any element is inserted between h1 and p",
".lead {\n font-size: 1.2rem;\n}\n// Use a class instead of structural selectors\n// Structural selectors break with DOM changes"
))
entries.append(g(
"Attribute selector performance",
"[class*=\"btn\"] {\n padding: 8px 16px;\n}\n// Matches any element with \"btn\" in class",
".btn {\n padding: 8px 16px;\n}\n// Class selectors are faster than attribute selectors\n// Attribute selectors are for dynamic/generated classes"
))
entries.append(g(
"Missing CSS reset/normalize",
"body {\n font-family: sans-serif;\n}\n// Browser default styles vary",
"/* Normalize.css or custom reset */\n*, *::before, *::after {\n box-sizing: border-box;\n}\nhtml {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n}body {\n margin: 0;\n font-family: system-ui, sans-serif;\n}"
))
entries.append(g(
"Chained class specificity war",
".container .main .content .card .btn {\n background: red;\n}\n// Fighting another rule with more nesting",
".btn--danger {\n background: red;\n}\n// Resolve specificity conflicts with clearer naming\n// Not by adding more selectors"
))
entries.append(g(
"Type selector in component CSS",
"div.card {\n padding: 16px;\n}\n// Tied to element type",
".card {\n padding: 16px;\n}\n// Don't tie styles to element types\n// Components should work on any element"
))
# =============================================================================
# LAYOUT (12 entries)
# =============================================================================
entries.append(g(
"Float-based layout",
".sidebar {\n float: left;\n width: 250px;\n}\n.content {\n margin-left: 270px;\n}\n// Float layout requires clearfix hacks",
".layout {\n display: grid;\n grid-template-columns: 250px 1fr;\n}\n// CSS Grid: clean, no clearfix needed\n// Or Flexbox for simpler layouts"
))
entries.append(g(
"Fixed height containers",
".hero {\n height: 500px;\n}\n// Breaks on small screens and with dynamic content",
".hero {\n min-height: 500px;\n}\n// min-height allows content to expand\n// Fixed height causes overflow issues"
))
entries.append(g(
"Margin collapse not handled",
".parent {\n border: 1px solid #ccc;\n}\n.child {\n margin-top: 20px;\n}\n// Child margin collapses with parent",
".parent {\n border: 1px solid #ccc;\n overflow: hidden;\n /* Or: display: flow-root */\n}\n// Creates new block formatting context"
))
entries.append(g(
"Using display: none for responsive hiding",
"@media (max-width: 768px) {\n .sidebar {\n display: none;\n }\n}\n// Removes from accessibility tree entirely",
"@media (max-width: 768px) {\n .sidebar {\n display: none;\n }\n}\n// OK for responsive, but consider:\n// .sidebar[aria-hidden=\"true\"] for programmatic hiding\n// Or reorder with CSS instead of hiding"
))
entries.append(g(
"Centering with negative margins",
".modal {\n position: fixed;\n top: 50%;\n left: 50%;\n margin-top: -150px;\n margin-left: -200px;\n}\n// Fragile - breaks if size changes",
".modal {\n position: fixed;\n inset: 0;\n display: grid;\n place-items: center;\n}\n// Grid centering: works regardless of size"
))
entries.append(g(
"Holy grail layout with floats",
".header { height: 60px; }\n.sidebar { float: left; width: 200px; }\n.main { margin: 0 200px; }\n.footer { clear: both; height: 40px; }",
".page {\n display: grid;\n grid-template-areas:\n \"header header\"\n \"sidebar main\"\n \"footer footer\";\n grid-template-columns: 200px 1fr;\n min-height: 100vh;\n}\n.header { grid-area: header; }\n.sidebar { grid-area: sidebar; }\n.main { grid-area: main; }\n.footer { grid-area: footer; }"
))
entries.append(g(
"Flexbox with fixed widths",
".nav {\n display: flex;\n}\n.nav-item {\n width: 100px;\n}\n// Doesn't adapt to content",
".nav {\n display: flex;\n gap: 8px;\n}\n.nav-item {\n flex: 1 1 auto;\n min-width: 80px;\n}\n// flex: grow shrink basis\n// gap replaces margin for spacing"
))
entries.append(g(
"Using tables for layout",
"<table style=\"width:100%\">\n <tr><td width=\"200\">Sidebar</td><td>Content</td></tr>\n</table>",
"<div style=\"display: grid; grid-template-columns: 200px 1fr; gap: 16px;\">\n <aside>Sidebar</aside>\n <main>Content</main>\n</div>\n// Tables are for tabular data only"
))
entries.append(g(
"Missing responsive images",
"<img src=\"photo-2000.jpg\" style=\"width: 100%\">\n// Loads 2MB image on mobile",
"<picture>\n <source media=\"(max-width: 600px)\" srcset=\"photo-600.webp\">\n <source media=\"(max-width: 1200px)\" srcset=\"photo-1200.webp\">\n <img src=\"photo-2000.webp\" alt=\"Description\" loading=\"lazy\">\n</picture>"
))
entries.append(g(
"Container not constraining max width",
".content {\n padding: 0 16px;\n}\n// Content stretches to full viewport on wide screens",
".content {\n max-width: 72rem;\n margin: 0 auto;\n padding: 0 16px;\n}\n// max-width + margin: auto centers and constrains"
))
entries.append(g(
"Using px for typography",
"body {\n font-size: 16px;\n line-height: 24px;\n}\nh1 {\n font-size: 32px;\n}\n// Doesn't respect user browser settings",
"body {\n font-size: 1rem;\n line-height: 1.5;\n}\nh1 {\n font-size: 2rem;\n}\n// rem respects user font-size settings\n// unitless line-height inherits properly"
))
entries.append(g(
"Position sticky not working",
".sidebar {\n position: sticky;\n top: 0;\n}\n// Not working - parent has overflow",
".parent {\n overflow: visible; /* not hidden/auto/scroll */\n}\n.sidebar {\n position: sticky;\n top: 0;\n}\n// sticky is constrained by parent overflow"
))
# =============================================================================
# MODERN CSS FEATURES (12 entries)
# =============================================================================
entries.append(g(
"Not using CSS custom properties",
".btn {\n background: #0066cc;\n color: #fff;\n border-radius: 4px;\n}\n.btn--dark {\n background: #333;\n}\n// Duplicated values",
":root {\n --color-primary: #0066cc;\n --color-text-light: #fff;\n --radius-sm: 4px;\n}\n.btn {\n background: var(--color-primary);\n color: var(--color-text-light);\n border-radius: var(--radius-sm);\n}\n.btn--dark {\n --color-primary: #333;\n}"
))
entries.append(g(
"Media query for mobile first",
".container {\n width: 960px;\n}\n@media (max-width: 768px) {\n .container {\n width: 100%;\n }\n}\n// Desktop-first - adds complexity",
".container {\n width: 100%;\n max-width: 960px;\n margin: 0 auto;\n}\n@media (min-width: 768px) {\n .container {\n /* Add desktop enhancements */\n }\n}\n// Mobile-first: base styles = mobile, min-width = larger screens"
))
entries.append(g(
"Not using container queries",
".card {\n display: block;\n}\n@media (min-width: 768px) {\n .card {\n display: flex;\n }\n}\n// Component layout tied to viewport",
".card-container {\n container-type: inline-size;\n}\n.card {\n display: block;\n}\n@container (min-width: 400px) {\n .card {\n display: flex;\n }\n}\n// Container queries: component responds to its container, not viewport"
))
entries.append(g(
"Not using :has() selector",
"// JavaScript needed to style parent based on child\ndocument.querySelectorAll('.form-group').forEach(group => {\n if (group.querySelector('.error')) {\n group.classList.add('has-error');\n }\n});",
".form-group:has(.error) {\n border-color: red;\n}\n// :has() styles parent based on child state\n// No JavaScript needed"
))
entries.append(g(
"Not using CSS layers",
"/* Third-party styles */\n.btn { padding: 8px; }\n/* Base styles */\n.btn { padding: 12px; }\n/* Component styles */\n.btn { padding: 16px; }\n// Specificity wars",
"@layer reset, base, components, utilities;\n\n@layer reset { /* ... */ }\n@layer base { .btn { padding: 12px; } }\n@layer components { .btn { padding: 16px; } }\n// @layer controls cascade order regardless of specificity"
))
entries.append(g(
"Not using subgrid",
".grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n}\n.card {\n display: grid;\n grid-template-columns: 1fr 2fr;\n /* Doesn't align with parent grid */\n}",
".grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n}\n.card {\n display: grid;\n grid-template-columns: subgrid;\n /* Inherits parent grid track sizes */\n}"
))
entries.append(g(
"Not using aspect-ratio",
".image-container {\n position: relative;\n padding-top: 56.25%; /* 16:9 */\n}\n.image-container img {\n position: absolute;\n top: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n// Padding hack for aspect ratio",
".image-container {\n aspect-ratio: 16 / 9;\n}\n.image-container img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n// aspect-ratio: native, clean"
))
entries.append(g(
"Not using clamp() for responsive typography",
"h1 { font-size: 2rem; }\n@media (min-width: 768px) { h1 { font-size: 3rem; } }\n@media (min-width: 1200px) { h1 { font-size: 4rem; } }",
"h1 {\n font-size: clamp(2rem, 5vw + 1rem, 4rem);\n}\n// clamp(min, preferred, max)\n// Fluid typography without media queries"
))
entries.append(g(
"Not using logical properties",
".card {\n margin-left: 16px;\n padding-top: 8px;\n padding-bottom: 8px;\n}\n// Breaks in RTL languages",
".card {\n margin-inline-start: 16px;\n padding-block: 8px;\n}\n// Logical properties adapt to writing direction\n// inline = horizontal, block = vertical"
))
entries.append(g(
"Not using color-mix()",
".btn:hover {\n background: #0055aa;\n}\n// Manual darker shade",
":root {\n --color-primary: #0066cc;\n}\n.btn:hover {\n background: color-mix(in srgb, var(--color-primary) 80%, black);\n}\n// color-mix: programmatic color manipulation"
))
entries.append(g(
"Not using text-wrap: balance",
"h1 {\n /* Multi-line heading wraps awkwardly */\n}",
"h1 {\n text-wrap: balance;\n}\n// Balances line lengths in multi-line text\n// Also: text-wrap: pretty for paragraphs"
))
entries.append(g(
"Not using @scope",
".modal .btn { color: white; }\n.modal .card .btn { color: blue; }\n// Global selectors can conflict",
"@scope (.modal) {\n .btn { color: white; }\n .card :where(.btn) { color: blue; }\n}\n// @scope limits CSS to a subtree\n// Prevents global selector conflicts"
))
# =============================================================================
# RESPONSIVE DESIGN (8 entries)
# =============================================================================
entries.append(g(
"Missing viewport meta tag",
"<!DOCTYPE html>\n<html>\n<head>\n <title>Page</title>\n</head>",
"<!DOCTYPE html>\n<html>\n<head>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>Page</title>\n</head>\n// Required for mobile rendering"
))
entries.append(g(
"Using rem without setting base",
"body {\n font-size: 1rem;\n}\n// 1rem = browser default (usually 16px)\n// Different browsers = different sizes",
"html {\n font-size: 100%; /* Respects user settings */\n}\nbody {\n font-size: 1rem;\n}\n// Or set explicitly: html { font-size: 16px; }"
))
entries.append(g(
"Breakpoint-based instead of content-based",
"@media (min-width: 768px) { /* tablet */ }\n@media (min-width: 1024px) { /* desktop */ }\n@media (min-width: 1440px) { /* large desktop */ }\n// Device-based breakpoints",
"// Break when the design breaks:\n@container (min-width: 300px) {\n .card { display: flex; }\n}\n// Or viewport-based but content-driven:\n@media (min-width: 48em) {\n .layout { display: grid; grid-template-columns: 1fr 1fr; }\n}\n// Use em for viewport breakpoints (scales with font-size)"
))
entries.append(g(
"Fixed width container on mobile",
".container {\n width: 960px;\n margin: 0 auto;\n}\n// Horizontally scrollable on mobile",
".container {\n width: min(960px, 100% - 32px);\n margin: 0 auto;\n}\n// min() constrains to viewport\n// 32px = 16px padding on each side"
))
entries.append(g(
"Not using prefers-reduced-motion",
"@keyframes slide {\n from { transform: translateX(-100%); }\n to { transform: translateX(0); }\n}\n.element {\n animation: slide 0.5s ease;\n}",
"@keyframes slide {\n from { transform: translateX(-100%); }\n to { transform: translateX(0); }\n}\n.element {\n animation: slide 0.5s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .element {\n animation: none;\n }\n}"
))
entries.append(g(
"Not using prefers-color-scheme",
"body {\n background: #fff;\n color: #333;\n}",
":root {\n --bg: #fff;\n --text: #333;\n}\n@media (prefers-color-scheme: dark) {\n :root {\n --bg: #1a1a1a;\n --text: #e0e0e0;\n }\n}\nbody {\n background: var(--bg);\n color: var(--text);\n}"
))
entries.append(g(
"Text sized with viewport units only",
"h1 {\n font-size: 8vw;\n}\n// Too large on desktop, too small on mobile",
"h1 {\n font-size: clamp(1.5rem, 8vw, 4rem);\n}\n// Clamp provides min and max bounds\n// 8vw is the ideal fluid size"
))
entries.append(g(
"Image overflow on small screens",
"<img src=\"photo.jpg\" style=\"width: 800px\">\n// Overflows viewport on mobile",
"<img src=\"photo.jpg\" style=\"max-width: 100%; height: auto;\">\n// max-width: 100% prevents overflow\n// height: auto maintains aspect ratio"
))
# =============================================================================
# CSS PERFORMANCE (8 entries)
# =============================================================================
entries.append(g(
"Loading CSS in body",
"<body>\n <link rel=\"stylesheet\" href=\"styles.css\">\n <div>Content</div>\n</body>",
"<head>\n <link rel=\"stylesheet\" href=\"styles.css\">\n</head>\n<body>\n <div>Content</div>\n</body>\n// CSS in <head> prevents FOUC"
))
entries.append(g(
"Not using font-display swap",
"@font-face {\n font-family: 'Custom';\n src: url('font.woff2') format('woff2');\n}\n// Invisible text while font loads",
"@font-face {\n font-family: 'Custom';\n src: url('font.woff2') format('woff2');\n font-display: swap;\n}\n// swap: show fallback immediately, swap when loaded\n// Also consider: optional, fallback"
))
entries.append(g(
"Large CSS file not split",
"<link rel=\"stylesheet\" href=\"all.css\">\n// 200KB single file with above/below fold styles",
"<link rel=\"stylesheet\" href=\"critical.css\">\n<link rel=\"stylesheet\" href=\"components.css\" media=\"print\" onload=\"this.media='all'\">\n// Critical CSS inlined or loaded first\n// Non-critical deferred"
))
entries.append(g(
"Using @import in CSS",
"@import 'reset.css';\n@import 'base.css';\n@import 'components.css';\n// Each @import is a blocking request",
"<link rel=\"stylesheet\" href=\"reset.css\">\n<link rel=\"stylesheet\" href=\"base.css\">\n<link rel=\"stylesheet\" href=\"components.css\">\n// <link> tags are parallel-loaded\n// @import in CSS is sequential"
))
entries.append(g(
"Not preloading critical resources",
"<head>\n <link rel=\"stylesheet\" href=\"styles.css\">\n</head>",
"<head>\n <link rel=\"preload\" href=\"font.woff2\" as=\"font\" crossorigin>\n <link rel=\"preload\" href=\"hero.webp\" as=\"image\">\n <link rel=\"stylesheet\" href=\"styles.css\">\n</head>\n// Preload critical resources the browser might not discover"
))
entries.append(g(
"Using box-shadow on large area",
".page {\n box-shadow: 0 0 100px rgba(0,0,0,0.3);\n}\n// Large blur on full page is expensive",
".page {\n background: radial-gradient(ellipse at center, transparent 0%, rgba(0,0,0,0.3) 100%);\n}\n// Gradient can be cheaper than large blur shadows\n// Or reduce blur radius: box-shadow: 0 4px 8px"
))
entries.append(g(
"Not using will-change",
".modal {\n transform: translateY(-100%);\n transition: transform 0.3s;\n}\n// Repaints on every frame",
".modal {\n transform: translateY(-100%);\n transition: transform 0.3s;\n will-change: transform;\n}\n// will-change promotes to compositor layer\n// Use sparingly - it consumes memory"
))
entries.append(g(
"Using CSS expressions (legacy)",
"width: expression(document.body.clientWidth > 800 ? '800px' : 'auto');\n// JavaScript in CSS - terrible performance",
"width: min(800px, 100%);\n// Modern CSS function replaces expression()\n// expression() is removed from all modern browsers"
))
# =============================================================================
# CSS ARCHITECTURE (6 entries)
# =============================================================================
entries.append(g(
"No naming convention",
".header {\n}\n.header-title {\n}\n.header-title-small {\n}\n.header-nav {\n}\n// Unclear relationships",
"/* BEM: Block __ Element -- Modifier */\n.header {\n}\n.header__title {\n}\n.header__title--small {\n}\n.header__nav {\n}\n// Clear component hierarchy from names"
))
entries.append(g(
"Utility class abuse",
"<div class=\"d-flex align-center justify-between p-4 m-2 bg-white rounded shadow\">\n Content\n</div>\n// CSS-in-HTML, hard to maintain",
"<div class=\"card\">\n Content\n</div>\n\n.card {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem;\n margin: 0.5rem;\n background: white;\n border-radius: 4px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n}\n// Semantic class names, not utility soup\n// Utility-first (Tailwind) is fine as a system choice"
))
entries.append(g(
"Global state dependency in CSS",
".sidebar .content .card .title {\n color: red;\n}\n// Only works in this specific DOM structure",
".title--highlighted {\n color: red;\n}\n// Component should be self-contained\n// Not dependent on parent structure"
))
entries.append(g(
"Not using CSS modules or scoped CSS",
".button {\n background: blue;\n}\n// Global class - name collision risk",
"// CSS Modules (button.module.css)\n.button {\n background: blue;\n}\n// Compiled to: .button___abc123\n// Scope isolation without global namespace"
))
entries.append(g(
"Not using CSS cascade layers for theming",
"/* Theme overrides scattered everywhere */\n.theme-dark .btn { background: #333; }\n.theme-dark .card { background: #222; }\n.theme-dark .header { background: #111; }\n// Hard to maintain",
":root {\n --theme-bg: #fff;\n --theme-text: #333;\n --theme-accent: #0066cc;\n}\n[data-theme=\"dark\"] {\n --theme-bg: #1a1a1a;\n --theme-text: #e0e0e0;\n --theme-accent: #6699ff;\n}\n.btn {\n background: var(--theme-accent);\n}\n// Theme via CSS custom properties - single source"
))
entries.append(g(
"Missing CSS linting",
"// No CSS linting configured",
"// .stylelintrc.json\n{\n \"extends\": \"stylelint-config-recommended\",\n \"rules\": {\n \"no-descending-specificity\": true,\n \"selector-class-pattern\": \"^[a-z][a-zA-Z0-9_-]*$\",\n \"color-named\": \"never\",\n \"no-invalid-position-at-import-rule\": true\n }\n}"
))
# =============================================================================
# SAVE
# =============================================================================
random.seed(42)
random.shuffle(entries)
os.makedirs(BASE, exist_ok=True)
out = BASE / "dev_finetuning_html_css.json"
with open(out, 'w') as f:
json.dump(entries, f, indent=2)
categories = {}
for e in entries:
for tag in e['tags']:
if tag != 'html_css':
categories[tag] = categories.get(tag, 0) + 1
print(f"Total entries: {len(entries)}")
print(f"Categories:")
for cat, count in sorted(categories.items(), key=lambda x: -x[1]):
print(f" {cat}: {count}")
print(f"Saved: {out}")