セレクタ・値・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>にマッチする |
:host / :host() | ⚠️ | パースは通るが常に非マッチ。シャドウツリーを持たないため。Tailwind v4がテーマ変数を:root, :hostに、preflightをhtml, :hostに書くので、セレクタリストの他の項が捨てられないようにするためのもの。:host-context()はパースエラー |
非対応の擬似要素(::first-line等)がセレクタに含まれるとルール全体が捨てられる。
一方:hoverや::placeholderのようにパースが通るものは、ルールとしては生き残った上でマッチしない。
:is() / :where()の引数リストだけは例外で、未対応の項があってもその項が捨てられるだけでルールは生きる。
擬似要素
| 擬似要素 | 対応 | 備考 |
|---|---|---|
::before / ::after | ⚠️ | 要素の最初と最後の子として、それ自身のボックスを生成する。擬似要素に書いた宣言(font-size・color・display・margin・position・transform等)が適用され、書かれていないプロパティは要素から継承する。ブロック子を持つ要素でも生成され、display: noneなら生成しない。擬似要素自身のcounter-reset/counter-incrementは適用されない。表(display: table)の要素には生成されない |
::first-letter | ⚠️ | font-family/font-size/font-weight/font-style/color/text-decoration-line/text-transformのみ上書きできる(float・box model系は非対応) |
::first-line | ❌ | パースエラー |
::backdrop / ::file-selector-button / ::placeholder / ::selection / ::marker | ⚠️ | パースは通るが常に非マッチ。静的なPDFには最上位レイヤー・ファイル入力・空のフォーム欄・選択範囲がなく、::markerも専用のスタイルを持たない(リストマーカーはlist-style-*で決まる)ため。Tailwind v4のpreflightにある*, ::after, ::before, ::backdrop, ::file-selector-button { ... }のようなセレクタリストの他の項が捨てられないようにするためのもの |
::-webkit-input-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に対応 ✅。
CSS全体キーワード
| キーワード | 対応 | 備考 |
|---|---|---|
inherit / initial / unset | ✅ | ショートハンドを含むすべてのプロパティで使える。inheritは親の計算値をそのまま引き継ぐ(emは親の側で解決済みの値になる)。var()のフォールバック(var(--x, inherit))でも使える。::before/::afterのcontentはどのキーワードでもnormal(生成しない)になり、counter-reset/counter-incrementはそれまでの宣言を打ち消すだけになる。@pageの中と::first-letterでは無視される |
revert / revert-layer | ❌ | 宣言ごと無視される |
関数
| 関数 | 対応 | 備考 |
|---|---|---|
calc() | ⚠️ | +/-/*//と括弧・calc()のネスト。項に使えるのは長さ(絶対単位・em/rem)・%・数値のみ。長さ・パーセンテージを取るプロパティ全般で使える |
min() / max() / clamp() | ❌ | |
var() | ✅ | カスタムプロパティ(--foo)は他のプロパティと同じく要素ごとにカスケード(詳細度・記述順・!important・style属性)する。未登録または@propertyでinherits: trueのものは継承し、inherits: falseのものは要素ごとに登録時のinitial-valueから始まる。var()は計算値の時点でその要素のカスタムプロパティで置換してからパースする。フォールバック(var(--x, 10px)、入れ子可)・カスタムプロパティ同士の参照(循環は無効)・initial/inherit/unsetに対応。解決できない登録済みカスタムプロパティはunsetとして扱う。@page(size・余白・マージンボックス)には要素がないため:root(<html>)の値で解決し、登録時の初期値も参照できる。@page内に書いたカスタムプロパティは参照できない。::before/::afterのcontentは要素の値を使う。!important付きの通常プロパティ(color: var(--c) !important)は未対応 |
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)でページ番号を出力できる(ストリーミングモードにも対応) |
@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をそのまま渡せる |
@property | ⚠️ | syntax・inherits・initial-valueを読む(syntax: "*"ではinitial-valueを省略可)。不正なルールは全体を無視し、同名では文書順で最後の有効な登録が勝つ。適用される@mediaと@layerの中でも使える。syntaxは受理するが現在はすべて"*"として扱うため、型検査と宣言元要素でのem等の計算は行わない |
@supports | ⚠️ | 条件を評価し、真ならブロックの中のルールを@mediaと同じようにトップレベルへ展開する。(property: value)は宣言パーサーが受理すれば真(値にvar()を含む場合は既知のプロパティなら真、!importantは付けてもよい)、selector(...)はセレクターが解釈できれば真。not・and・or・括弧で組み合わせられる(andとorは括弧なしでは混ぜられない)。font-tech()・font-format()など未知の関数は偽。@media・@layerとは入れ子にできる |
@keyframes / @namespace / @counter-style / @container | ❌ | ブロックごと無視される |
ストリーミングモード固有の制約
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)(総ページ数)はPDF完成時に描画することで対応する