セレクタ・値・at-rule対応表
セレクタ
マッチングはServo由来のselectorsクレートに委譲しているため、CSS3セレクタは概ねそのまま使える。
| セレクタ | 対応 | 備考 |
|---|---|---|
タイプ(p)・ユニバーサル(*) | ✅ | |
クラス(.foo)・ID(#foo) | ✅ | |
属性([a]/[a=v]/[a^=v]/[a$=v]/[a*=v]/[a~=v]/[a|=v]) | ✅ | 大文字小文字を無視するiフラグも使える |
子孫(空白)・子(>) | ✅ | |
隣接兄弟(+)・一般兄弟(~) | ✅ | |
セレクタリスト(,) | ✅ | |
ネスト(.a { .b { } } / & .b / &.b / > .b) | ✅ | CSS Nesting。&を省いたセレクタは& .b、先頭がコンビネータのものは& > .bとして扱う。&は:is(親)に置き換わるので詳細度は親のうち最も高いものになる。ネストしたルールの後ろに書いた宣言は、そのルールより後ろの順序でカスケードに参加する。ネストした@media等のat-ruleは非対応(ブロックごと無視) |
名前空間(ns|E) | ❌ | @namespace自体が非対応 |
擬似クラス
| 擬似クラス | 対応 | 備考 |
|---|---|---|
:root | ✅ | |
:first-child / :last-child / :only-child | ✅ | |
:nth-child() / :nth-last-child() | ✅ | ストリーミングモードでは:nth-last-child()の結果が変わる(下記参照) |
:first-of-type / :last-of-type / :only-of-type / :nth-of-type() / :nth-last-of-type() | ✅ | ストリーミングモードでは:first-of-type/:nth-of-type()以外の結果が変わる(下記参照) |
:empty | ✅ | |
:not() | ✅ | |
:is() / :where() | ✅ | 引数リストは寛容(未対応のセレクタが混ざっていてもその項だけを捨てる)。詳細度は:is()が引数のうち最も高いもの、:where()は常に0 |
:has() | ✅ | 子孫・>・+・~のいずれも書ける。詳細度は:is()と同じ規則。入れ子(:has()の中の:has())と擬似要素は仕様どおり書けない。ストリーミングモードでは:has(~ ...)が非マッチ(下記参照) |
:hover / :active / :focus / :focus-within / :focus-visible / :target / :enabled / :disabled / :checked / :visited | ⚠️ | パースは通るが常に非マッチ。対話状態を持たない静的なPDF出力では意味を持たないため |
:link / :any-link | ✅ | hrefを持つ<a>にマッチする |
非対応の擬似要素(::first-line等)がセレクタに含まれるとルール全体が捨てられる。
一方:hoverのようにパースが通るものは、ルールとしては生き残った上でマッチしない。
:is() / :where()の引数リストだけは例外で、未対応の項があってもその項が捨てられるだけでルールは生きる。
擬似要素
| 擬似要素 | 対応 | 備考 |
|---|---|---|
::before / ::after | ⚠️ | contentによる生成テキストのみ。ホスト要素の計算スタイルをそのまま流用して描画し、擬似要素専用のボックススタイル(margin/padding/display等)は持たない。ブロック子を持つ要素では生成されない |
::first-letter | ⚠️ | font-family/font-size/font-weight/font-style/color/text-decoration-line/text-transformのみ上書きできる(float・box model系は非対応) |
::first-line | ❌ | パースエラー |
::marker / ::selection / ::placeholder | ❌ | パースエラー |
値・単位・関数
長さ
| 単位 | 対応 |
|---|---|
px / em / rem | ✅ |
mm / cm / in / pt / pc / Q | ✅ |
%(パーセンテージを取るプロパティで) | ✅ |
単位なしの0 | ✅ |
ex / ch / vw / vh / vmin / vmax / lh | ❌ |
絶対単位は1インチ = 96pxとして解釈する(10mmは37.795px)。
印刷向けに寸法を実寸で書けるので、@page { size: 210mm 297mm; margin: 15mm; }のような指定がそのまま通る。
@pageのsizeだけは例外的にページサイズのキーワード(a4/letter等)とlandscape/portraitを受け付ける。
角度(transform専用)
deg / rad / grad / turn、および単位なしの0に対応 ✅。
関数
| 関数 | 対応 | 備考 |
|---|---|---|
calc() | ⚠️ | +/-/*//と括弧・calc()のネスト。項に使えるのは長さ(絶対単位・em/rem)・%・数値のみ。長さ・パーセンテージを取るプロパティ全般で使える |
min() / max() / clamp() | ❌ | |
var() | ⚠️ | カスタムプロパティ(--foo)をパース前のテキスト置換で解決する。フォールバック(var(--x, 10px))・カスタムプロパティ同士の参照に対応。カスケードや継承には従わず、文書全体で「最後に書かれた宣言が勝つ」単純な解決になる点が本来の仕様と異なる |
url() | ✅ | background-image/list-style-image/@font-faceのsrc/@import。相対URLは<base href>または入力元を基準に解決する |
attr() | ⚠️ | contentの中でのみ使える |
counter() / counters() | ✅ | contentの中。第2引数のスタイルはlist-style-typeの値集合 |
linear-gradient()等のグラデーション | ❌ | |
env() / image-set() / element() | ❌ |
色
| 記法 | 対応 |
|---|---|
名前付き色(red等のCSS色キーワード) | ✅ |
#rgb / #rgba / #rrggbb / #rrggbbaa | ✅ |
rgb() / rgba()(カンマ区切り・スペース区切りとも) | ✅ |
hsl() / hsla() / hwb() | ✅ |
lab() / lch() / oklab() / oklch() | ✅ (sRGBへ変換して描画) |
currentcolor / transparent | ✅ |
color()(color(display-p3 ...)等) | ❌ |
color-mix() | ⚠️ (下記) |
相対色構文(rgb(from ...)) | ❌ |
アルファ付きの色は塗り・背景ともPDFのExtGStateで透過描画する。
color-mix()
color-mix(in <色空間> [<色相の回し方> hue]?, <色> <割合>?, <色> <割合>?)に対応する。
割合の正規化(合計が100%を超えるときは比率だけが効き、満たないときは足りないぶんだけ結果が透明になる)と、アルファの事前乗算も仕様どおり行う。
- 色空間:
srgb/srgb-linear/lab/oklab/xyz(xyz-d65) /hsl/hwb/lch/oklch - 色相の回し方:
shorter(既定) /longer/increasing/decreasing - 入れ子にできる(深さ16まで)
以下は非対応で、書くとその宣言だけが無視される。
display-p3/a98-rgb/prophoto-rgb/rec2020。出力先がPDFのDeviceRGBなので、受け付けてもsRGBへ丸められるだけで指定した意味にならない- オペランドの
currentcolor。currentcolorはカスケードの後(その要素のcolorが決まってから)解決するのに対し、混色はパース時に済ませるため、この時点では値が分からない xyz-d50(白色点の変換が要るため)
at-rule
| at-rule | 対応 | 備考 |
|---|---|---|
@media | ⚠️ | メディアタイプのみを評価する。screen(およびnot screen以外の否定)はブロックごと無視し、print/all/タイプ省略は適用する。(min-width: ...)のような特性クエリは評価せず読み飛ばす(=タイプさえ合致すれば中身が適用される) |
@page | ⚠️ | size(キーワード/<length>{1,2}/landscape/portrait)とmargin系に対応。:first/:left/:right擬似クラス単体に対応し、名前付きページ(@page intro)・:blank・複合擬似クラス(:first:left)は非対応 |
@page内のmargin box | ⚠️ | @top-left-corner/@top-left/@top-center/@top-right…の16種すべて。contentのテキスト描画のみで、背景色・枠線等の装飾は非対応。counter(page)/counter(pages)でページ番号を出力できる(counter(pages)はストリーミングモードでは非対応) |
@font-face | ⚠️ | font-family/src/unicode-range/font-weight/font-styleディスクリプタに対応(srcのlocal()・format()/tech()付きurl()も受理)。font-display等その他のディスクリプタは無視。フォントファイルはTTF/OTFのみで、WOFF/WOFF2は非対応 |
@import | ✅ | ネスト(深さ上限16、超過分はその1件だけ無視)・循環参照の検出に対応。@import url(...) screen;のようなメディアクエリ条件は評価せず常に取り込む |
@charset | ❌ | 入力はUTF-8前提 |
@layer | ⚠️ | ブロックの中のルールを書かれた順にトップレベルへ展開する(@layer a { .x {} }は.x {}と同じ)。レイヤーの優先順位は実装せず、通常のカスケード(詳細度・後勝ち)で決まる。@layer a, b;の順序宣言は無視する。Tailwind v4のように出力全体を@layerで包むCSSをそのまま渡せる |
@supports / @keyframes / @namespace / @counter-style / @container / @property | ❌ | ブロックごと無視される |
ストリーミングモード固有の制約
Mode::Batch(一括処理)ではDOM全体が揃っているため下記の制約は無い。
Mode::Streamingでのみ以下が適用される。
<body>直下のトップレベル要素は、次の兄弟が現れた時点で確定として処理します。
そのため「この先に同じ型の要素が続くか」が要るセレクタだけ、<body>直下の要素に限って結果が変わります(その要素の内側は部分木が揃っているので変わりません)。
:last-of-type/:only-of-type/:nth-last-child()/:nth-last-of-type()/:has(~ ...)は、余分にマッチしたり取りこぼしたりします。 これらを使うと警告が出ます:last-child・:empty・:has()の子孫/直後の兄弟は、確定の条件と一致するのでバッチと同じ結果になります+/~・:first-child/:nth-child()/:first-of-type/:nth-of-type()/:only-childもバッチと同じ結果になります。 これらを使っている文書では、処理済みのトップレベル要素を子孫だけ解放し、要素そのものを兄弟として残すためです (残るのはトップレベル要素1個につき1ノードなので、解放できる量はほぼ変わりません)<body>開始後の<style>タグはエラー:EngineError::UnsupportedInStreamingModeを返す。 黙って見た目が崩れるのを避けるため、<style>は<head>に集約するposition: absolute/fixedは無視されるcounter(pages)(総ページ数)は使えない