Attribute

cells

Make elements already on the page the cells of the doodle. The doodle styles them where they are and draws no grid of its own.

Syntax

  • <css-doodle cells="#list li"></css-doodle>
  • <css-doodle cells="h1::letters"></css-doodle>
  • <css-doodle cells="p::words"></css-doodle>

A CSS selector, matched in the document, or in the shadow root that holds the doodle. The elements it selects become the cells, in document order, and :doodle styles their parent. When elements are added or removed, the doodle draws again with the same seed. click:cell, click:update and pause() work on the cells; @content does not.

Examples

Every tag below is clipped to a blob of its own. @R.t gives @shape a noise curve that closes on itself, a different one in each cell. Click a tag for new shapes:

<div id="tags">
  <span>css</span> <span>doodle</span> <span>grid</span>
  <span>shape</span> <span>svg</span> <span>pattern</span>
  <span>scene</span> <span>plot</span> <span>tile</span>
</div>
<css-doodle cells="#tags span" click:update>
  display: inline-block;
  padding: 10px 16px;
  background: @p(#ebbf4d, #e6437d, #2a9d8f);
  clip-path: @shape(r: @R.t(.75, 1));
</css-doodle>
css doodle grid shape svg pattern scene plot tile
display: inline-block; padding: 10px 16px; background: @p(#ebbf4d, #e6437d, #2a9d8f); clip-path: @shape(r: @R.t(.75, 1));

Rows and columns

The page lays the cells out, and the doodle reads where they landed: @y is the row, and @x the place in that row, from 1, so a shorter row still starts at 1. When a resize moves cells to other rows, the doodle draws again. @grid: 3 numbers them in rows of 3 instead.

CSS can't select a row of wrapped elements. Here every row of tags gets its own color:

<p id="rows">
  <span>css</span> <span>doodle</span> <span>grid</span>
  <span>shape</span> <span>svg</span> <span>pattern</span>
  <span>scene</span> <span>plot</span> <span>tile</span>
  <span>palette</span> <span>shaders</span>
</p>
<css-doodle cells="#rows span">
  padding: 0 4px;
  color: #fff;
  background: @pick(@y: #000, #e6437d, #2a9d8f);
</css-doodle>

css doodle grid shape svg pattern scene plot tile palette shaders

padding: 0 4px; color: #fff; background: @pick(@y: #000, #e6437d, #2a9d8f);

Letters and words

::letters or ::words at the end of the selector splits the text of the selected elements, one cell per letter or word. The markup inside is kept, words follow the rules of their language, and screen readers still read the text whole. Here :doodle styles the element being split. Letters are inline, so give them display: inline-block before moving them:

<p id="wave">css-doodle</p>
<css-doodle cells="#wave::letters">
  display: inline-block;
  font: 700 2rem sans-serif;
  animation: up .6s infinite alternate ease-in-out;
  animation-delay: calc(@i * -.1s);
  @keyframes up {
    to { translate: 0 -.3em; }
  }
</css-doodle>

css-doodle

display: inline-block; font: 700 2rem sans-serif; animation: up .6s infinite alternate ease-in-out; animation-delay: calc(@i * -.1s); @keyframes up { to { translate: 0 -.3em; } }

@udx and @udy measure from each cell's center, so every letter knows how far away the pointer is. Move it over the text:

<p id="rise">Move the pointer over these letters</p>
<css-doodle cells="#rise::letters">
  display: inline-block;
  font: 700 1.5rem sans-serif;
  --k: $(max(0, 1 - hypot(@udx, @udy) / 40));
  translate: 0 $px(k * -12);
  color: color-mix(in oklab, #e6437d $%(k * 100), #000);
</css-doodle>

Move the pointer over these letters

display: inline-block; font: 700 1.5rem sans-serif; --k: $(max(0, 1 - hypot(@udx, @udy) / 40)); translate: 0 $px(k * -12); color: color-mix(in oklab, #e6437d $%(k * 100), #000);

See also