🪀

たのしいおもちゃ、CSS Doodle

2024/12/22に公開

はじめに

こんにちは。READFYORでプロダクトエンジニアをしているhxdegawaです。

僕はCSSが好きです。
CSSに関する面白そうな情報を求め、web.devのWeb platform baselineを眺めるのが最近のひまつぶしです。

直近だと新たな数学関数@propertyなどが追加されましたね。
カスタムプロパティで結構面白い遊びができそうな匂いがしています。

CSSで対応できることが増えれば今までは実装の都合で不可能だった「表示用ロジックの大部分をCSS側に寄せる」といったこともできそうなので、他ロジックとの棲み分けなど上手に使えばメンテナビリティも向上しそうですね!

まあとはいえ、もっと派手でガチャガチャしたものをパパッと作りたいなぁという邪な感情も捨てきれないわけです。
(たとえばfilterプロパティが追加された時のような昂りがほしいんですよね)

なので今回はそんな邪な気持ちを楽に具現化できる楽しいおもちゃ、CSS Doodleについて紹介しようと思います!

CSS Doodle is 何

簡潔にまとめると、CSS DoodleはShadow DOM内に実装されたサードパーティーのCSSパーサーです。

仕組み

本記事はCSS Doodleをエンジョイしようという趣旨なので細かくは説明しませんが、処理の流れだけ軽く触れておきましょう。

JavascriptからcustomElements.define()を用いて定義された<css-doodle>という要素に外部からスタイルを渡してやると、JSで実装された本ライブラリの独自パーサーによってスタイルが評価され、描画されます。
Shadow DOM内部で処理が完結していて、外部のCSSスタイルの影響を受けずに独自のスタイリングを適用しているため、css-doodleの内部がカプセル化され、外部のレイアウトやスタイルを壊さずに表示できるのです。

オレオレCSSと何が違う?

Shadow DOMの内部とはいえ、CSSでの記述がJSで評価されるという特徴上、CSSのカスタムプロパティと自前のJSでゴリ押しオレオレスタイルを作り似たようなことをすることもできると感じた方もいらっしゃるかと思います。

その点、本パーサーにはGLSLやSVG周りの記述をよしなにやってくれる実装も含まれているため、その辺りも含めてスタイルを書くだけで描画できるというのは魅力的かと思います。

やってみよう

シンプルに試してみましょう。
必要なものはHTML1枚です。

基本

シンプルな例だと以下の様になります。
(全体のスタイルや<head>などは邪魔なため記述しません。)

<css-doodle>
  :doodle {
      @grid: 3x3;
      @size: 20dvw;
      gap: 5px;
  }
  background-color: #222;
  transform: scale(@rand(.2, .9));
</css-doodle>

なんだか面白そうな匂いがするぞ

DOMエレメントは<css-doodle>しか配置していないのに要素が誕生しましたね。
css-doodleによって生成されるShadow DOM内は基本的にGrid Layoutで描画されます。
軽く読んでいきましょう。見慣れない@プロパティがいくつかありますね。

  • :doodle
    • <css-doodle>要素そのもののスタイルです。
    • gridのルールや、描画範囲などの設定はこのセレクタ内で行います。
  • @grid
    • 名前の通り、gridのルールを決めます。
    • この方法の他に、<css-doodle grid="5">のようにattributeを渡すことで指定もできますが、@gridにあるルールが優先されます。
  • @size
    • 全体のサイズです。
    • 従来のCSSのようにheightやwidthでも指定可能です。

:doodle で指定したgridのルールに従い、子要素は勝手に描画されます。
子要素にスタイルを当てたい場合、ネストせずスタイルを<css-doodle>内に直置きします。
上記の例ですと background-color: #222; ですね。

サッと触ってみると、使い勝手にクセのあるcanvasといったところでしょうか。
現時点だとただgridが勝手に描画されるだけのライブラリに見えますが、このライブラリの真価はその他のselectorfunctionsにあります。

特殊なプロパティに触れる

次はこちらの例です。

<css-doodle>
  @grid: 1 / 100vw 100vh / transparent;
  background-size: 200px 200px;
  background-image: @doodle(
    @grid: 6 / 100%;
    @size: 4px;
    font-size: 4px;
    color: #222;
    box-shadow: @m3x5(
      calc(4em - @nx*1em) @ny(*1em)
        @p(@m3(currentColor), @m2(#0000)),
      calc(2em + @nx*1em) @ny(*1em)
        @lp
    );
  );
</css-doodle>

すごいですよね。初めて動かした時ひっくり返りました。
こちらも読み解いていきましょう!

まず気になるのは @doodle です。名前から何をするのか想像できないプロパティ名に動揺しつつドキュメントを見ると、

Generate url() image with css-doodle code.

CSSで描いた模様をそのままbackground-imageurl()として生成してしまえるFunctionです。
黒魔術すぎる。

Contributorのブログを読むと、どうやらSVGの<foreignObject>を使って要素をベクターイメージとして扱わせる、みたいなことをしているそう。

上記のスニペットを一行一行解説すると長くなってしまうので以下に掻い摘んで説明します。

  1. 6x6マスのgridを設定
  2. それぞれのマスで@m(@multipleの略)というループ機能を使い、模様を作成
  3. 作成した模様を@doodleでラップし、SVG Imageデータとしてbackground-imageに挿入
  4. 挿入した画像を200x200の背景画像としてrepeatして完成

という手順で上記の模様が完成します。
機能を知っていてもどのような模様を作り出せるか発想力が試されそうですよね。

まとめ

CSS Doodleを使いこなして職人芸を披露したい方はぜひ公式ドキュメントにも目を通してみてください。

本記事で触れなかったもプロパティたちの中にもまだまだ
@shaders (GLSLを扱える)や @svg-filter(filter) (フラクタルノイズなどの効果を当てられる)など、もはやCSSの範疇を余裕で超えているようなプロパティも控えているのでそちらもまたいつか触れたいと思います。

Codepenなどをみるととんでもない職人もたくさんいるのでこの辺りの実装に倣うのも面白そうですね!

ではまた👋

Discussion