インラインSVGのAMP対応における問題、プレゼンテーション属性で指定したスタイルが反映されない問題への対応

公開:2020-01-29 05:30
更新:2020-02-15 04:37
カテゴリ:Webサイトリニューアル,SVG,CSS

はじめに

Webサイトリニューアルの一環として、AMPページにおけるエラーの修正をぼちぼち行っている。いろいろなエラーが出ているのだが、今回はインラインSVGでエラーが出ているコンテンツを修正した顛末、プレゼンテーション属性で指定したスタイルが反映されない問題への対応についても書いておく。

インラインSVGにおけるAMPの対応

AMPはインラインSVGもサポートしているが、制約があって使ってはいけないタグがある。

今回出ているSVGのエラーは以下の通りで、インラインstyleの部分でエラーが発生してしまっている。インラインstyleはAMPではNGだから。

<text sodipodi:linespacing="125%" id="text2989" y="784.32941" x="102.45901" style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Meiryo;-inkscape-font-specification:Meiryo" space="preserve"><tspan y="784.32941" x="102.45901" id="tspan2991" sodipodi:role="line">セッション</tspan></text>

それ以外にもいくつかエラーが出ている。このSVGの中身はInkScapeで作ったデータをそのままコピペしているので、ツールのメタデータなどの本来不要なものが含まれていることが原因のようだ。

Inkscapeでは保存オプションとして「最適化SVG」というものがあって、不要なメタ・データ等を除去することができる。

InkScapeの最適化オプション

svgタグを中身をすべてコピペしてSVGファイルを作り、それをInkScapeで読み込ませて「最適化SVG」で保存しなおしてみると以下のようになる。

 <text x="102.45901" y="784.32941" fill="#000000" font-family="Meiryo" letter-spacing="0px" word-spacing="0px" style="line-height:0%" space="preserve"><tspan x="102.45901" y="784.32941" font-size="10px" style="line-height:1.25">セッション</tspan></text>

そして、もう一度検証してみると、これだけでは解消できないものがあった。それはtextタグにおいてspace=preserveは使用できないエラーであった。この属性はいったい何なのかということで調べてみると以下の通りであった。

この値は、すべての改行文字とタブ文字をスペースに変換するようユーザーエージェントに指示します。次に、すべてのスペース文字(先頭、末尾、および連続する複数のスペース文字を含む)を描画します。 (MDNより)

つまりスペースはそのまま処理されるということである。もう一つdefaultとういうのがあって、その挙動は以下の通り。

  1. すべての改行文字が削除されます。
  2. すべてのタブ文字はスペース文字に変換されます。
  3. 先頭および末尾のスペース文字はすべて削除されます。
  4. 連続するスペース文字はすべて、単一のスペース文字にまとめられます。

この属性自体もうdeprecateのステータスで、今はcssのwhite-spaceを使えとのことである。

この属性を削除してみた結果、エラーは0となった。

検証結果

svgのプレゼンテーション属性で指定したスタイルが反映されない問題

がしかし、実際のページを表示してみるとなぜかフォントが巨大になってはみ出ている。。

実際のページ

本来はこうであってほしいのだが。今回の作業でこうなったのではどうもなさそうだが。

あるべき姿

テキストに加えた設定がすべて飛んでいるように見える。chromeのDevToolで見てみると、

chrome-devtool

svgのスタイルではなくCSSの*で設定したスタイルが優先して設定されている。

* {
    font-family: -apple-system,
                  BlinkMacSystemFont,
                  "Helvetica Neue",
                  "Yu Gothic",
                  YuGothic,
                  "ヒラギノ角ゴ ProN W3",
                  Hiragino Kaku Gothic ProN,
                  Arial,
                  "メイリオ",
                  Meiryo,
                  sans-serif;
    font-size: 18px;
    box-sizing: border-box;
    line-height: 1.85rem;
    letter-spacing: .1rem;
    word-wrap: break-word;
    word-break: loose;
    /*border: 1px dashed gray;*/
}

規格によれば、SVGのプレゼンテーション属性(呈示属性) の詳細度は0であり一番優先度が低いようである。

CSS をサポートする UA においては、呈示属性は 非 CSS による呈示上のヒントの優先順位【訳】 ([CSS2], 6.4.4 節) に従って、対応するスタイル規則に変換された上で,文書のスタイルシートに追加されなければならない。 この追加においては、概念的には,呈示属性は、一連の文書作成者スタイルシートの最初のものになる,新たな文書作成者スタイルシートに挿入される。 すなわち CSS2 カスケード の過程においては、呈示属性は,あたかも対応する CSS スタイル規則に置換された上で,文書作成者のスタイルシートの先頭に詳細度( specificity )がゼロとして置かれたかのように働く。 このことは、一般的に呈示属性は,文書作成者による他の CSS スタイル規則や style 属性よりも優先度が低いことを意味する。

https://triple-underscore.github.io/SVG11/styling.html#UsingPresentationAttributes

つまり上記の動作は仕様通りである。原因がわかったので回避策を考えた。svgのプレゼンテーション属性を生かすには、svg内部に影響するCSS設定をすべて排除すればよいので、CSS定義の*の部分を:not(text,tspan)としてみた。

:not(text,tspan) {
    font-family: -apple-system,
                  BlinkMacSystemFont,
                  "Helvetica Neue",
                  "Yu Gothic",
                  YuGothic,
                  "ヒラギノ角ゴ ProN W3",
                  Hiragino Kaku Gothic ProN,
                  Arial,
                  "メイリオ",
                  Meiryo,
                  sans-serif;
    font-size: 18px;
    box-sizing: border-box;
    line-height: 1.85rem;
    letter-spacing: .1rem;
    word-wrap: break-word;
    word-break: loose;
    /*border: 1px dashed gray;*/
}

そうすると問題は回避できた。

ちなみに<img>で埋め込む場合はこの影響を受けない。

おわりに

今回の問題でCSSのスタイルとsvgで指定しているプレゼンテーション属性との優先度が理解できたのはよかった。

CSSの詳細度については、CSSにはなんとなくそういう優先度みたいなのがあるなあとは思っていたが、詳しくは知らなかった。この詳細度の無理解のせいでまた別の問題が発生するのだがこれは次回の記事で書くことにする。