Google Chrome 34.0.1797.2 (Official Build 246002) dev-m
OS Windows
Blink 537.36 (@165430)
enable-experimental-web-platform-features フラグ オン
CSS Programming という概念が生まれてから今年で 3 年。 CSS である程度の「計算」ができることは広く知られるようになりました[要出典]が、これまでは致命的な欠点を抱えていました。 それは、計算結果を再び入力として使うことができないという点です。
- たとえば、
counter-increment
を使えばたし算・ひき算ができますが、その結果はcontent: counter(foo)
として表示するだけで、新たな計算の入力としては使えません。 - たとえば、CSS Calculator
では、演算子は一度しか使えず、普通の電卓のように
1 + 2 + 3 + ...
と連続して計算することはできません。 - たとえば、HTML + CSS だけで一次元セルオートマトンを作ることができますが、計算結果をその次のステップで利用するために人間が Tab + Space を押してやる必要があります。
CSS Regions を利用した次のような HTML と CSS を考えます。
<input type="checkbox"><div id="input0" class="in"></div>
<input type="checkbox"><div id="input1" class="in"></div>
<div class="or"></div>
<div class="and"></div>
.in {
flow-into: flow1;
}
input:checked + .in {
height: 100px;
}
.or, .and {
max-height: 100px;
flow-from: flow1;
}
2 つの input
があり、それらをチェックすると、その直後の .in
の高さが変化して flow1
という名前の named flow に流れ込みます。
流れ込んだ .in
は、後続の 2 つの div
に流れ出すことになりますが、
input
がチェックされていなければ.or
も.and
も空。(empty)input
がどちらか 1 つだけチェックされていれば、.or
には要素が流れ出している (fit) ものの、.and
は空。input
が両方ともチェックされていれば、.or
にも.and
にも要素が流れ出す。
というわけで、AND と OR を計算するユニットができたことになります。
div
を四角、named flow を丸で表すと次のような感じでしょうか。
さて本題は、この結果を再び入力として利用することですが、簡単ですね。
.and { flow-into: flow2; }
などとして、同じように flow-from: flow2
な要素も用意してやればいいのです。
AND と OR だけでは不完全なので、NOT も作っておきましょう。
これには ::region()
疑似要素を使います(::region()
なしで作る方法もあるかもしれませんが)。
<div class="not-plus" id="not-plus1"></div>
<div class="not-plus"></div>
<div class="not-plus"></div>
<div class="not-minus"></div>
<div class="not-minus" id="not-minus1"></div>
<div class="not"></div>
/* 前の結果が flow-into: flow2 されている前提 */
.not-plus, .not-minus {
height: 100px;
}
.not-plus {
flow-into: flow2;
}
.not-minus, .not {
flow-from: flow2;
}
#not-minus1::region(#not-plus1) {
margin-top: -200px;
}
- 前の結果が流れ込んでこなければ、3 つの
.not-plus
が.not-minus
と.not
に流れ出す。 - 流れ込んでくると、
- まずその要素が 1 つ目の
.not-minus
に流れ出す。 - 次の
#not-plus1
が#not-minus1
に流れ出し、::region()
のルールが適用される。200px 分の隙間ができる。 - その隙間に残り 2 つの
.not-plus
が流れこむため、.not
は空のままになる。
- まずその要素が 1 つ目の
::region()
のところを赤線で表すと次のように図にかけます。
残念ながら、::region()
疑似要素を使えるブラウザはまだありません。
Chrome (とたぶん Safari も)では古い @-webkit-region
ルールが使えるのですが、margin-top
はサポートされていません。
そのため、以下のデモでは JavaScript Polyfill を利用しています。::region()
疑似要素については「CSS Regions と ::region() 疑似要素」も参照してください。
以上で、AND, OR, NOT 等の基本的なユニットが完成し、また各ユニットの出力を入力に使うこともできるようになりました。 これで、(将来的にはきっと CSS だけで)論理演算ができます。めでたし、めでたし……
flow の名前の処理が手書きでは煩雑なため、テンプレートエンジンなどを使って自動生成したいところです。 例えば、私は CoffeeCup で、regioncalc/regioncalc.coffee のようなテンプレートを用意していますが、まったく役に立たなくて便利かと思います。
- Demo: 加算器
- ソース (CoffeeCup)
- 半加算器の部分の図。flow 間を単につなげるだけの要素を薄い四角で表しています(コネクタと呼んでいます)。
- 出力を自分や、より上流に再入力して循環参照させることはできません。 できたとするといつまでもスタイルの計算が終わらなくなるため、CSS Regions の仕様で防ぐようになっています。
- polyfill が重い +
setTimeout
等を乱用していて遅いため、スタイルが適用されるまでにタイムラグがあります。- そもそもこんなことをしているのも、無茶をすることで polyfill の不具合発見や性能向上に役立てたいという意図があります。