Test Yourself!

These ten questions run the length of the chapter, and each turns on an SVG behavior that catches experienced developers: percentage lengths, default sizes, <use> inheritance, gradients on straight lines, text paths, what runs inside an image, CSS transform origins, hit testing, bounding boxes and markup inserted with innerHTML. Every snippet ran in headless Chrome 154 1 , driven by Playwright 26,280 , which read the console output and sampled the rendered pixels. Save each listing as a page, write down what it draws and prints and why, and only then check Appendix H, which gives the real result, the reason and the section it comes from. Some questions ask what you see, so look at the page as well as its console.

Checking your answers

The script below is how the answers were produced. It opens a page in your installed Chrome, prints the page's console messages and saves a full-page screenshot beside the file (npm 2,036 install playwright, then node check.mjs questions-1-5.html).

check.mjs: run a question page and capture its console and pixelsJavaScript
// Usage: node check.mjs questions-1-5.html   (prints the console, saves a full-page PNG)
import { chromium } from 'playwright';
import { pathToFileURL } from 'node:url';
const file = process.argv[2];
const browser = await chromium.launch({ channel: 'chrome' });   // your installed Chrome
const page = await browser.newPage({ viewport: { width: 700, height: 900 } });
page.on('console', msg => console.log(msg.text()));
await page.goto(pathToFileURL(file).href);
await page.waitForTimeout(1000);                  // let SMIL and the images settle
await page.screenshot({ path: file.replace(/\.html$/, '.png'), fullPage: true });
await browser.close();

Questions

questions-1-5.html: lengths, sizes, inheritance, gradients and text pathsHTMLLive
<!-- 1. A percentage radius in a viewport that is not square. What radius does r="10%"
        give here, in user units? (Section 1.1.2) -->
<svg width="300" height="150"><circle id="c1" r="10%"/></svg>
<!-- 2. Two SVGs with no width or height in a 600-pixel-wide box, one with a viewBox.
        How large is each? (Sections 1.1.3 and 1.3.6) -->
<div style="width:600px"><svg id="s2"></svg><svg id="s3" viewBox="0 0 100 50"></svg></div>
<!-- 3. The circle sits in a red group; the <use> that copies it is blue. What color is the
        copy? (Section 1.3.2) -->
<svg width="100" height="100"><defs><g fill="red"><circle id="c" cx="50" cy="50" r="40"/></g>
  </defs><use href="#c" fill="blue"/></svg>
<!-- 4. Two lines stroked with the same gradient; the second drops one unit over 260.
        Which can you see? (Section 1.4.2) -->
<svg width="300" height="60"><linearGradient id="g"><stop stop-color="#1f5f8b"/>
  <stop offset="1" stop-color="#e09a10"/></linearGradient>
  <line x1="20" y1="20" x2="280" y2="20" stroke="url(#g)" stroke-width="10"/>
  <line x1="20" y1="40" x2="280" y2="41" stroke="url(#g)" stroke-width="10"/></svg>
<!-- 5. A seal whose text follows a <circle> instead of a <path>. What does it draw, and
        what length does the text report? (Section 1.6.2) -->
<svg width="140" height="140"><circle id="ring" cx="70" cy="70" r="50" fill="none"/>
  <text id="seal"><textPath href="#ring">BookNest seal text</textPath></text></svg>
<script>
  const size = svg => (r => r.width + 'x' + r.height)(svg.getBoundingClientRect());
  console.log('1:', c1.r.baseVal.value.toFixed(2), '2:', size(s2), size(s3));
  console.log('5:', seal.getComputedTextLength().toFixed(1));
</script>
questions-6-10.html: images, transforms, hit testing, bounding boxes and innerHTMLHTMLLive
<!-- 6. Two red squares loaded as images: one recolors itself with SMIL, the other with a
        script. Which turns green? (Section 1.7.2) -->
<div id="imgs"></div>
<!-- 7. A CSS rotation on an SVG rectangle, with no transform-box. Where does the rectangle
        end up? (Section 1.7.3) -->
<svg id="s7" width="300" height="100"><rect id="rot" x="100" y="10" width="40" height="20"
  style="transform:rotate(90deg)"/></svg>
<!-- 8. One circle has fill="none", the other fill="transparent". Which element does a
        click at each circle's center hit? (Section 1.7.4) -->
<svg id="s8" width="200" height="100">
  <circle id="hollow" cx="50" cy="50" r="40" fill="none" stroke="black"/>
  <circle id="clear" cx="150" cy="50" r="40" fill="transparent"/></svg>
<!-- 9. A stroked, scaled circle. What do getBBox() and getBoundingClientRect() report?
        (Section 1.7.4) -->
<svg width="200" height="100"><circle id="c9" cx="50" cy="50" r="10" stroke="black"
  stroke-width="10" transform="scale(2)"/></svg>
<!-- 10. Untrusted markup inserted with innerHTML. Which of the three handlers run?
        (Section 1.8.2) -->
<div id="box"></div>
<script>
  const square = extra => `<img src="data:image/svg+xml,${encodeURIComponent(
    `<svg xmlns="http://www.w3.org/2000/svg"><rect id="r" width="60" height="60" fill="red">
    ${extra}</svg>`)}">`;
  imgs.innerHTML =
    square('<set attributeName="fill" to="green" begin="0.2s" fill="freeze"/></rect>') +
    square(`</rect><script>
      document.getElementById('r').setAttribute('fill', 'green')<\/script>`);
  const box7 = rot.getBoundingClientRect(), svg7 = s7.getBoundingClientRect();
  console.log('7:', box7.x - svg7.x, box7.y - svg7.y, box7.width, box7.height);
  const hit = x => document.elementFromPoint(s8.getBoundingClientRect().x + x,
    s8.getBoundingClientRect().y + 50).id;
  console.log('8:', hit(50), hit(150));
  const b = c9.getBBox(), r = c9.getBoundingClientRect();
  console.log('9:', b.x, b.y, b.width, b.height, '|', r.width, r.height);
  box.innerHTML = `<svg onload="console.log('10: svg onload')">
    <script>console.log('10: svg script')<\/script></svg>
    <img src="missing.png" onerror="console.log('10: img onerror')">`;
</script>