イラストレーターとかInkscapeとかそういうベクター画像編集用のアプリケーションを使わず、手軽に縁取り文字が描きたい。
とにかく楽がしたい。
結論
いきなりだけど、さっさと結論。
svgとcssのコラボで楽勝。
ただし、注意点もある。
demo
https://jsfiddle.net/0owv1yjd/
説明
上記の例では2つの方法を使っていますが、見ていただいた通りどちらの方法を取っても結果は同じです。
なんてったって、書いている内容は違えどやっていることは同じなので。
基本的な考え方
svgのtextで使えるstyleにはもともとアウトラインを描画するための「stroke」があります。
このstrokeの色と太さを定義すると文字のアウトラインを描画することができます。
しかし、このアウトラインを太くすると文字の内側をどんどん侵食していき、さらに太くするとstokeの色で塗りつぶされた状態になってしまいます。
黒で描画していた場合真っ黒の文字が現れてギョッとしてしまうことに。
<svg>
<text x="10" y="50" style="stroke-width:10;stroke:#000;fill:#fff;">縁取り</text>
</svg>
縁を描画してから文字の塗りつぶしをしてくれれば良いのですが、塗りつぶしが優先されてしまうようです。
そのため、太い線で縁を描画すると真っ黒になってしまいます。
解決策
原因がわかれば対処のしようはあります。
先に縁を描画して、後から塗りつぶしをするように矯正すればよいはず。
これを実現するための方法として2つ紹介します。
どちらでも実現できるなら2つ目の方が楽でいい気はします。が、いつものようにIEとかEdgeとかは。。。どちらの方法も未確認です!
ちなみにまだCR(勧告候補)な仕様だそうです。
1つ目の方法
2つの文字列要素<text>を重ねて、上に重なる方(つまり後で定義された方)は縁取りをせずに塗りつぶしだけをすれば
擬似的に縁取りをした後に塗りつぶしをしたかのように見せることができます。
<svg>
<text x="10" y="50" style="stroke-width:10;stroke:#000;">縁取り</text>>
<text x="10" y="50" paint-order="stroke" style="fill:#fff;">縁取り</text>
</svg>
2つ目の方法
text要素にpaint-order属性を使って、描画順を明示的に指定すると望んだ結果が得られる。
<svg>
<text x="10" y="50" style="stroke-width:10;stroke:#000;fill:#fff;paint-order:stroke;">縁取り</text>
</svg>
どうやらモバイル版Chrome、2019/03/18時点では非対応だったみたいですが、2019/04/25時点では対応したみたい。
https://developer.mozilla.org/ja/docs/Web/CSS/paint-order
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/paint-order
注意点
ここまでのに紹介した2つの方法ですが、どちらの方法を使った場合も縁取りがある程度の太さになるとフォントの種類や文字によって縁取り線が突き抜けてしまったり、交差してしまったりして残念な感じになります。
これも綺麗に解決!しようとするとさすがにIllustratorとかそういうアプリケーションのお世話になってください。
ただし、少し犠牲を払ってもよければ対策はあります。
突き抜け、交差対策
stroke-linejoin:round;
要は縁取り線の角を丸くすることで飛び出してしまう部分を内側に入れ込んでしまい、見えなくするという方法です。
角丸線で描画することになるので、文字全体がやわらかい雰囲気になってしまうので、パキッとした縁取り文字を使いたいという場合は、縁取りの太さを抑えるか、フォントを変更する。あるいはIllustratorとかでがんばる。
その辺をやってください。
やわらか雰囲気で問題ないのであれば、stroke-linejoinにround指定。これがおすすめ。