Files
code-crispies/lessons/29-html-figure.json

115 lines
11 KiB
JSON

{
"$schema": "../schemas/code-crispies-module-schema.json",
"id": "html-figure",
"title": "Figure",
"description": "Create self-contained content with captions",
"mode": "html",
"difficulty": "beginner",
"lessons": [
{
"id": "figure-basic",
"title": "Image with Caption",
"description": "The <kbd>&lt;figure&gt;</kbd> element wraps self-contained content like images, diagrams, or code. Add <kbd>&lt;figcaption&gt;</kbd> to provide a caption.<br><br>This semantic structure helps screen readers and search engines understand your content.",
"task": "Create a figure with:<br>1. A <kbd>&lt;figure&gt;</kbd> element<br>2. An <kbd>&lt;img&gt;</kbd> inside (use placeholder URL)<br>3. A <kbd>&lt;figcaption&gt;</kbd> describing the image",
"previewHTML": "",
"previewBaseCSS": "body { font-family: system-ui; padding: 20px; background: #f5f5f5; } figure { margin: 0; background: white; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 15px rgba(0,0,0,0.1); max-width: 400px; } figure img { width: 100%; height: 200px; object-fit: cover; display: block; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); } figcaption { padding: 15px 20px; color: #555; font-size: 0.95rem; border-top: 1px solid #eee; }",
"sandboxCSS": "",
"initialCode": "",
"solution": "<figure>\n <img src=\"https://picsum.photos/400/200\" alt=\"A beautiful landscape\">\n <figcaption>A beautiful mountain landscape at sunset.</figcaption>\n</figure>",
"previewContainer": "preview-area",
"concept": {
"explanation": "The figure element semantically marks self-contained content that's referenced from the main flow but could be moved elsewhere (like a sidebar or appendix) without losing meaning. Figcaption provides an accessible label that screen readers announce when encountering the figure, establishing a programmatic relationship between image and caption that's stronger than visual proximity alone. Unlike an img followed by a p, figure+figcaption creates an accessibility API relationship: AT announces \"figure\" when entering, reads the caption, then describes the image, giving users complete context. Search engines also parse this relationship, using figcaption content to understand image meaning for image search results and context-aware rankings.",
"diagram": "Figure Semantic Relationship\n\nRegular Image + Text:\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n<img src=\"photo.jpg\" alt=\"Mountain\">\n<p>A beautiful mountain.</p>\n\n✗ No semantic link\n✗ SR: \"Mountain image\" then \"A beautiful mountain\"\n✗ Caption could apply to any nearby content\n\nFigure + Figcaption:\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n<figure>\n <img src=\"photo.jpg\" alt=\"Mountain\">\n <figcaption>A beautiful mountain.</figcaption>\n</figure>\n\n✓ Semantic relationship\n✓ SR: \"Figure. Mountain image. A beautiful mountain.\"\n✓ Caption explicitly bound to image\n\nScreen Reader Flow:\n┌─────────────────────────────┐\n│ <figure> │ → \"Entering figure\"\n│ <img alt=\"Mountain\"> │ → \"Mountain, image\"\n│ <figcaption> │\n│ A beautiful mountain │ → \"A beautiful mountain\"\n│ </figcaption> │\n│ </figure> │ → \"Leaving figure\"\n└─────────────────────────────┘\n\nSEO Benefits:\n✓ Image-caption binding\n✓ Better image search results\n✓ Context for visually similar images"
},
"validations": [
{
"type": "element_exists",
"value": "figure",
"message": "Add a <kbd>&lt;figure&gt;</kbd> element"
},
{
"type": "element_exists",
"value": "figure img",
"message": "Add an <kbd>&lt;img&gt;</kbd> inside the figure"
},
{
"type": "element_exists",
"value": "figcaption",
"message": "Add a <kbd>&lt;figcaption&gt;</kbd> for the caption"
}
]
},
{
"id": "figure-code",
"title": "Code Figure",
"description": "Figures aren't just for images! You can use them for code snippets, quotes, or any self-contained content.<br><br>Combine <kbd>&lt;figure&gt;</kbd> with <kbd>&lt;pre&gt;</kbd> and <kbd>&lt;code&gt;</kbd> for code examples.",
"task": "Create a code figure:<br>1. A <kbd>&lt;figure&gt;</kbd> element<br>2. A <kbd>&lt;pre&gt;</kbd> containing <kbd>&lt;code&gt;</kbd> with some code<br>3. A <kbd>&lt;figcaption&gt;</kbd> describing the code",
"previewHTML": "",
"previewBaseCSS": "body { font-family: system-ui; padding: 20px; background: #1e1e1e; } figure { margin: 0; background: #2d2d2d; border-radius: 10px; overflow: hidden; max-width: 500px; } pre { margin: 0; padding: 20px; overflow-x: auto; } code { color: #9cdcfe; font-family: 'Fira Code', 'Consolas', monospace; font-size: 14px; line-height: 1.5; } figcaption { padding: 12px 20px; color: #888; font-size: 0.85rem; background: #252525; border-top: 1px solid #3d3d3d; }",
"sandboxCSS": "",
"initialCode": "",
"solution": "<figure>\n <pre><code>function greet(name) {\n return `Hello, ${name}!`;\n}</code></pre>\n <figcaption>A simple greeting function in JavaScript</figcaption>\n</figure>",
"previewContainer": "preview-area",
"concept": {
"explanation": "Figure isn't limited to images—it's for any self-contained content like code samples, charts, diagrams, poems, or quotes. The semantic meaning is \"referenced content with a caption\", not \"photo with text\". When wrapping code in figure, you establish that this code block is an example being discussed, not inline code to execute. Screen readers announce \"figure\" before the code, signaling to users that this is illustrative content they may want to skip if they're scanning. The figcaption describes what the code does or why it's shown, helping users decide whether to read it in detail—crucial for technical documentation where code blocks can be numerous and lengthy.",
"diagram": "Figure Use Cases\n\nImages:\n<figure>\n <img src=\"chart.png\">\n <figcaption>Sales 2024</figcaption>\n</figure>\n\nCode Samples:\n<figure>\n <pre><code>function add() {}</code></pre>\n <figcaption>Addition function</figcaption>\n</figure>\n\nQuotes:\n<figure>\n <blockquote>To be or not to be</blockquote>\n <figcaption>— Shakespeare</figcaption>\n</figure>\n\nPoems:\n<figure>\n <p>Roses are red</p>\n <p>Violets are blue</p>\n <figcaption>— Anonymous</figcaption>\n</figure>\n\nDiagrams (SVG):\n<figure>\n <svg>...</svg>\n <figcaption>System architecture</figcaption>\n</figure>\n\nCommon Pattern:\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n✓ Content that illustrates a point\n✓ Content referenced by main text\n✓ Content with a description/attribution\n✓ Self-contained units\n\n✗ Not for decorative images\n✗ Not for inline content\n✗ Not for UI elements"
},
"validations": [
{
"type": "element_exists",
"value": "figure",
"message": "Add a <kbd>&lt;figure&gt;</kbd> element"
},
{
"type": "element_exists",
"value": "pre",
"message": "Add a <kbd>&lt;pre&gt;</kbd> element for preformatted text"
},
{
"type": "element_exists",
"value": "code",
"message": "Add a <kbd>&lt;code&gt;</kbd> element for the code"
},
{
"type": "element_exists",
"value": "figcaption",
"message": "Add a <kbd>&lt;figcaption&gt;</kbd> describing the code"
}
]
},
{
"id": "figure-gallery",
"title": "Image Gallery",
"description": "You can put multiple images inside a single <kbd>&lt;figure&gt;</kbd> to create a gallery or comparison.<br><br>The figcaption describes the entire group.",
"task": "Create a gallery figure:<br>1. A <kbd>&lt;figure&gt;</kbd> element<br>2. At least 2 <kbd>&lt;img&gt;</kbd> elements<br>3. A <kbd>&lt;figcaption&gt;</kbd> describing the gallery",
"previewHTML": "",
"previewBaseCSS": "body { font-family: system-ui; padding: 20px; background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%); min-height: 100vh; margin: 0; box-sizing: border-box; } figure { margin: 0; background: white; border-radius: 15px; overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,0.15); max-width: 500px; padding: 15px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; } figure img { width: 100%; height: 120px; object-fit: cover; border-radius: 8px; background: linear-gradient(45deg, #ff6b6b, #feca57); } figcaption { grid-column: 1 / -1; padding: 10px 5px 5px; color: #666; font-size: 0.9rem; text-align: center; }",
"sandboxCSS": "",
"initialCode": "",
"solution": "<figure>\n <img src=\"https://picsum.photos/200/120?1\" alt=\"Photo 1\">\n <img src=\"https://picsum.photos/200/120?2\" alt=\"Photo 2\">\n <img src=\"https://picsum.photos/200/120?3\" alt=\"Photo 3\">\n <img src=\"https://picsum.photos/200/120?4\" alt=\"Photo 4\">\n <figcaption>My vacation photo gallery</figcaption>\n</figure>",
"previewContainer": "preview-area",
"concept": {
"explanation": "A single figure can contain multiple related elements when they collectively form one logical unit, like a photo gallery, before/after comparison, or multi-angle product shots. The figcaption describes the entire collection rather than individual items, establishing that these pieces should be understood together. This pattern is semantically different from multiple separate figures—it communicates \"these images are facets of one concept\" versus \"here are several independent illustrations\". Screen readers announce one figure containing multiple images, then read the collective caption, helping users understand the grouping. Search engines also interpret this structure, understanding that images within a figure are related for relevance ranking.",
"diagram": "Single vs Multiple Figures\n\nMultiple Separate Figures:\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n<figure>\n <img src=\"paris.jpg\">\n <figcaption>Paris</figcaption>\n</figure>\n<figure>\n <img src=\"london.jpg\">\n <figcaption>London</figcaption>\n</figure>\n→ Two independent illustrations\n\nSingle Figure Gallery:\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n<figure>\n <img src=\"paris.jpg\">\n <img src=\"london.jpg\">\n <img src=\"rome.jpg\">\n <figcaption>European cities</figcaption>\n</figure>\n→ One concept with multiple views\n\nUse Cases:\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n✓ Photo gallery (vacation pics)\n✓ Before/after comparison\n✓ Product: front, side, back views\n✓ Step-by-step process images\n✓ Multi-panel comics/diagrams\n\nScreen Reader:\n\"Figure containing 4 images\"\n→ Image 1: \"paris.jpg\"\n→ Image 2: \"london.jpg\"\n→ Image 3: \"rome.jpg\"\n→ Image 4: \"berlin.jpg\"\n\"Caption: European cities\""
},
"validations": [
{
"type": "element_exists",
"value": "figure",
"message": "Add a <kbd>&lt;figure&gt;</kbd> element"
},
{
"type": "element_count",
"value": { "selector": "figure img", "min": 2 },
"message": "Add at least 2 images inside the figure"
},
{
"type": "element_exists",
"value": "figcaption",
"message": "Add a <kbd>&lt;figcaption&gt;</kbd> for the gallery"
}
]
}
]
}