背景画像翻訳の設計議論用ページ
各セクションは docs/superpowers/specs/2026-05-27-background-image-translation-discussion.md の議論項目に対応している。 DevToolsで実際のDOMを確認しながら議論することを想定。
同じ画像を img タグと background-image で使った場合、それぞれ異なるキーで保存される。
下の左右は同じ画像ファイル (/cat1.webp) を表示しているが、 SDK内部での扱いが異なる。左は img.src = "/cat1.webp" の文字列をそのままキーとして使う。 右は getComputedStyle が返す絶対URL (http://...../cat1.webp) をキーとして使う。
議論ポイント: 顧客が同じ画像を2箇所で使っている場合、翻訳を2回設定する必要がある。

<img src="/cat1.webp">
// SDKでのキー: "/cat1.webp"background-image: url("/cat1.webp");
// getComputedStyle が返す絶対URL:
// "url(\"http://localhost:3000/cat1.webp\")"URL以外にもgradient, image-set, cross-fadeなど多様な layer kind が存在する。
議論ポイント: url() と image-set() のみ翻訳対象とし、 gradient/cross-fade/paint() などは passthrough として元のまま保持する。 parser は top-level のカンマで layer を分割する必要がある (gradient 内のカンマと区別)。
background-image: url("/cat1.webp");background-image:
url("/al-feature.png"), /* layer 1 (top) */
url("/cat2.webp"); /* layer 2 (bottom) */background-image:
linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)), /* passthrough */
url("/cat3.webp"); /* translatable */background-image: -webkit-image-set(
url("/al-feature.png") 1x,
url("/al-feature-2x.png") 2x
);background-image: linear-gradient(135deg, #667eea, #764ba2);
// URLがないため、SDKは何も登録しない非HTTP(S) のURLスキームをどう扱うか。
議論ポイント: 既存の img タグの処理に合わせて、特殊URLも他のURL同様に抽出するか、 スキームでフィルタするか。data: URL は base64 で巨大になりがちで、translation mapに入れる際の懸念がある。
background-image: url("data:image/svg+xml;utf8,<svg ...><circle cx='12' cy='12' r='10' fill='%23ef4444'/></svg>");
// SDKでのキー: data: URL の文字列全体 (長い)background-image: url("/sample.svg#some-fragment");
// SVG sprite の特定要素を参照するパターンblob: URL は URL.createObjectURL() で生成され、 ページ存続期間のみ有効。デモは省略 (Inspect DOM で挙動だけ議論)。
spec が background-image を許可するすべての疑似要素を対象とする。
議論ポイント: サポートする疑似要素の数 × 全要素数 でgetComputedStyle の呼び出し回数が決まる。コスト vs カバレッジ。
下記の各例で ::before, ::after 等は実DOMには現れないが、 DevToolsの「Computed」タブで背景画像が確認できる。
.al-demo-before::before {
content: "";
position: absolute;
width: 32px; height: 32px;
background-image: url("/al-feature.png");
}.al-demo-after::after {
content: "";
background-image: url("/cat1.webp");
}.al-demo-both::before { background-image: url("/cat1.webp"); }
.al-demo-both::after { background-image: url("/cat2.webp"); }.al-demo-all-three { background-image: url("/cat3.webp"); } /* 本体の背景 */
.al-demo-all-three::before { background-image: url("/cat1.webp"); } /* 左の帯 */
.al-demo-all-three::after { background-image: url("/cat2.webp"); } /* 右の帯 */dialog::backdrop {
background-image: url("/cat3.webp");
}Aで始まる文章。最初の文字に背景画像が適用される。
p::first-letter {
background-image: url("/al-feature.png");
background-clip: text;
}input[type="file"]::file-selector-button {
background-image: url("/cat2.webp");
}.al-demo-scrollbar::-webkit-scrollbar-thumb {
background-image: url("/cat1.webp");
}「非表示にする」=要素ごと隠す。レイヤー単位の非表示はサポートしない。
議論ポイント: 下の要素は3レイヤー (gradient + 2 images) で構成されている。 顧客が「badge を非表示にしたい」と思っても、SDKは要素全体を al-hidden で隠す。 レイヤー単位の非表示は modal UI とサーバ契約に大幅な追加が必要なため v1 では対応しない。
background-image:
url("/al-feature.png"), /* layer 1: badge */
linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4)), /* layer 2: overlay */
url("/cat3.webp"); /* layer 3: photo */
// "Hide" を選ぶと → 要素ごと al-hidden で消えるstrict CSP は inline style 書き込みと <style> ブロック注入を両方ブロックする。
議論ポイント: 顧客向けドキュメントに記載 + ランタイム警告なし。 下記のCSP設定の顧客は背景画像翻訳が無音で失敗する。
# 問題のあるCSP例
Content-Security-Policy: style-src 'self';
# → element.style.setProperty(...) も <style id="al-bg-image-rules">{...} も無効
# 必要な変更 (どちらか)
Content-Security-Policy: style-src 'self' 'unsafe-inline';
# または nonce/hash ベースこのページではCSPは設定していないので、ブラウザのDevToolsで挙動を確認できる。 実際のブロック挙動を見るには、サーバ側でCSPヘッダを追加して再現する必要がある。
SDK は resting state のみ翻訳する。state-dependent な背景は元言語のまま。
議論ポイント: hover / focus / アニメーション / メディアクエリ / prefers-color-scheme は SDK の inline style override では追従しない。 元のCSSが state ごとに別の背景を持つ場合、SDK の inline !important は resting state のみカバーする。
.al-demo-hover { background-image: url("/cat1.webp"); }
.al-demo-hover:hover { background-image: url("/cat2.webp"); }
// SDK は resting state (cat1.webp) のみ翻訳する.al-demo-media-query { background-image: url("/cat1.webp"); }
@media (min-width: 700px) {
.al-demo-media-query { background-image: url("/cat2.webp"); }
}
// SDK が抽出した時点で適用されている方のみ翻訳できる
// ウィンドウリサイズ後に再抽出するかは未決@media (prefers-color-scheme: dark) {
.al-demo-color-scheme { background-image: url("/cat3.webp"); }
}
// OS設定をdarkに変更したときに再抽出するかは未決data-al-bg-id 属性、managed <style> ブロック、!important などの衝突可能性。
議論ポイント: SDKは pseudo override 用に data-al-bg-id 属性 + <style id="al-bg-image-rules"> を使う。命名の衝突可能性は低いが、 防御的に長い prefix にするかどうかが論点。
data-al-bg-id="customer-existing-value" 属性を持つ。 SDKが pseudo override で同じ属性名を使うと衝突する。<div data-al-bg-id="customer-existing-value">
// SDK が pseudo override で
// element.setAttribute("data-al-bg-id", "42")
// するとこの値が上書きされる
//
// 防御策候補:
// data-autolingual-bg-id (より長い prefix)
// data-al-bg-id-<projectId> (project スコープ)/* 顧客のCSS */
.al-demo-customer-important {
background-image: url("/cat1.webp") !important;
}
// SDK は host element には inline style + !important で書き込むので勝つ
// しかし pseudo override の場合、selector specificity 次第で負ける可能性