0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SVG で HTML の文字を CSS で擬似的に縁取りするのと同様の効果を得る方法

Last updated at Posted at 2022-08-18

HTML の文字を CSS で擬似的に縁取り

image.png

このような HTML の文字に対する CSS での縁取りは次のように 8方向に text-shadow を施すと擬似的に再現できる。この手法では縁取り部分を僅かにぼかし柔らかな縁取りにしやすい。また、この手法は Google Fonts / Material Symbols のようにフォント化され文字として扱える記号にも適用できるので、特にフレキシブルな設計で便利な場合もある。

(※この手法のブラウジング時の負荷は決して低くは無いが、近年の一般的なブラウジング環境ならばよほど乱用しない限りは問題なくなって久しい。)

 /* HTML要素の「文字」を対象に擬似的に縁取りする CSS の例 */
 :root {
  /* 輪郭線にしたい色 */
  --shadow-color: #333;
  /* 輪郭線にしたい幅(長さ) */
  --shadow-thickness: 0.5mm;
  /* 輪郭線にしたい幅の2倍の + 向きの長さ = + 向きのオフセット値 */
  --shadow-offset-positive: calc(var(--shadow-thickness) * 2);
  /* 輪郭線にしたい幅の2倍の - 向きの長さ = - 向きのオフセット値 */
  --shadow-offset-negative: calc(var(--shadow-offset-positive) * -1);
  /* 8方向に影を出して擬似的に輪郭線を縁取る text-shadow 用の設定 */
  --shadow:
   /* 影付けの向き①↘: +x, +y = 右下 */
   var(--shadow-offset-positive) var(--shadow-offset-positive) var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き②↙: -x, +y = 左下 */
   var(--shadow-offset-negative) var(--shadow-offset-positive) var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き③➚: +x, -y = 右上 */
   var(--shadow-offset-positive) var(--shadow-offset-negative) var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き④↖: -x, -y = 左上 */
   var(--shadow-offset-negative) var(--shadow-offset-negative) var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き⑤→: +x,  0 = 右   */
   var(--shadow-offset-positive) 0 var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き⑥↓:  0, +y =   下 */
   0 var(--shadow-offset-positive) var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き⑦←: -x,  0 = 左   */
   var(--shadow-offset-negative) 0 var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き⑧↑:  0, -y =   上   */
   0 var(--shadow-offset-negative) var(--shadow-thickness) var(--shadow-color);
 }

SVG で同様の縁取り効果を得る方法

次にこの記事の本題として HTML に SVG ファイルを <img> で読み出して使用する場合に上記の text-shadow と同様の縁取り効果を得たい場合にどうしたらよいのかを記述する。

stroke を使う方法; 🆖🤔❓

SVG について少し知識があれば縁取りは stroke を使えばよいと思い当たる。しかし stroke では期待に近い表現となる場合/部分もあるが、例えば SVG に <text> が含まれる場合に意図しない表現となる場合もある。

image.png

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="100%" y="100%"
 viewBox="-2 -2 48 58" style="enable-background:new 0 0 44 44;" xml:space="preserve">
 <style>
  #a {
   stroke: #333;
   stroke-opacity: 0.9;
   fill: #FFF;
  }
 </style>
 <g id="a">
  <path d="M22,0C9.869,0,0,9.869,0,22s9.869,22,22,22s22-9.869,22-22S34.131,0,22,0z M22,42C10.972,42,2,33.028,2,22S10.972,2,22,2
		s20,8.972,20,20S33.028,42,22,42z" />
  <path d="M33,24c-0.552,0-1,0.448-1,1c0,5.514-4.486,10-10,10s-10-4.486-10-10c0-0.552-0.448-1-1-1s-1,0.448-1,1
		c0,6.617,5.383,12,12,12s12-5.383,12-12C34,24.448,33.552,24,33,24z" />
  <path d="M13,14c1.654,0,3,1.346,3,3c0,0.552,0.448,1,1,1s1-0.448,1-1c0-2.757-2.243-5-5-5s-5,2.243-5,5c0,0.552,0.448,1,1,1
		s1-0.448,1-1C10,15.346,11.346,14,13,14z" />
  <path d="M31,12c-2.757,0-5,2.243-5,5c0,0.552,0.448,1,1,1s1-0.448,1-1c0-1.654,1.346-3,3-3s3,1.346,3,3c0,0.552,0.448,1,1,1
		s1-0.448,1-1C36,14.243,33.757,12,31,12z" />
  <text x="5.5" y="52" font-size="6">with-stroke</text>
 </g>
</svg>

この問題は SVG のドラフト規格の stroke-alignment が現実のブラウジング環境で実用可能な時代が訪れれば解決する可能性もあるが、少なくとも執筆現在の Chrome-104.0.5112.102 ではまだ stroke-alignment は機能しない。

<filter> + <deDropShadow> を使う方法; 🙆‍♀😊👍

SVG でも <filter> + <deDropShadow> で HTML の文字に対する CSS での text-shadow と同様の影付けを行える。

image.png

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="100%" y="100%"
 viewBox="-2 -2 48 58" style="enable-background:new 0 0 44 44;" xml:space="preserve">
 <style>
  #a {
   fill: #FFF;
   filter: url(#shadow)
  }
 </style>
 <filter id='shadow' color-interpolation-filters="sRGB">
  <feDropShadow dx="+0.2" dy="+0.2" stdDeviation="0.1" />
  <feDropShadow dx="-0.2" dy="+0.2" stdDeviation="0.1" />
  <feDropShadow dx="+0.2" dy="-0.2" stdDeviation="0.1" />
  <feDropShadow dx="-0.2" dy="-0.2" stdDeviation="0.1" />
  <feDropShadow dx="+0.2" dy=" 0  " stdDeviation="0.1" />
  <feDropShadow dx=" 0  " dy="+0.2" stdDeviation="0.1" />
  <feDropShadow dx="-0.2" dy=" 0  " stdDeviation="0.1" />
  <feDropShadow dx=" 0  " dy="-0.2" stdDeviation="0.1" />
 </filter>
 <g id="a">
  <path d="M22,0C9.869,0,0,9.869,0,22s9.869,22,22,22s22-9.869,22-22S34.131,0,22,0z M22,42C10.972,42,2,33.028,2,22S10.972,2,22,2
		s20,8.972,20,20S33.028,42,22,42z" />
  <path d="M33,24c-0.552,0-1,0.448-1,1c0,5.514-4.486,10-10,10s-10-4.486-10-10c0-0.552-0.448-1-1-1s-1,0.448-1,1
		c0,6.617,5.383,12,12,12s12-5.383,12-12C34,24.448,33.552,24,33,24z" />
  <path d="M13,14c1.654,0,3,1.346,3,3c0,0.552,0.448,1,1,1s1-0.448,1-1c0-2.757-2.243-5-5-5s-5,2.243-5,5c0,0.552,0.448,1,1,1
		s1-0.448,1-1C10,15.346,11.346,14,13,14z" />
  <path d="M31,12c-2.757,0-5,2.243-5,5c0,0.552,0.448,1,1,1s1-0.448,1-1c0-1.654,1.346-3,3-3s3,1.346,3,3c0,0.552,0.448,1,1,1
		s1-0.448,1-1C36,14.243,33.757,12,31,12z" />
  <text x="3.5" y="52" font-size="6">with-shadow</text>
 </g>
</svg>

この手法では冒頭に示した「HTML の文字に対する CSS の text-shadow による擬似的な縁取り」とおおよそ同様の実装手法と効果が得られる。

おまけ: 拡大縮小性の確認

  1. HTML+CSS
  2. SVG with stroke in HTML
  3. SVG with shadow in HTML

以上の3つの手法を実装し、 2. と 3. については 60mm 幅、 120mm 幅で拡大縮小性についても感知液に確認する HTML を記述した。

(※<img>src 属性で読み出している .svg ファイルはそれぞれ先に紹介した strokedeDropShadow での SVG 実装例をそのままファイルとして保存したもの。)

image.png

<!DOCTYPE html>

<style>
 /* HTML要素の「文字」を対象に擬似的に縁取りする CSS の例 */
 :root {
  /* 輪郭線にしたい色 */
  --shadow-color: #333;
  /* 輪郭線にしたい幅(長さ) */
  --shadow-thickness: 0.5mm;
  /* 輪郭線にしたい幅の2倍の + 向きの長さ = + 向きのオフセット値 */
  --shadow-offset-positive: calc(var(--shadow-thickness) * 2);
  /* 輪郭線にしたい幅の2倍の - 向きの長さ = - 向きのオフセット値 */
  --shadow-offset-negative: calc(var(--shadow-offset-positive) * -1);
  /* 8方向に影を出して擬似的に輪郭線を縁取る text-shadow 用の設定 */
  --shadow:
   /* 影付けの向き①↗: +x, +y = 右上 */
   var(--shadow-offset-positive) var(--shadow-offset-positive) var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き②↖: -x, +y = 左上 */
   var(--shadow-offset-negative) var(--shadow-offset-positive) var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き③↘: +x, -y = 右下 */
   var(--shadow-offset-positive) var(--shadow-offset-negative) var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き④↙: -x, -y = 左下 */
   var(--shadow-offset-negative) var(--shadow-offset-negative) var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き⑤→: +x,  0 = 右   */
   var(--shadow-offset-positive) 0 var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き⑥↑:  0, +y =   上 */
   0 var(--shadow-offset-positive) var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き⑦←: -x,  0 = 左   */
   var(--shadow-offset-negative) 0 var(--shadow-thickness) var(--shadow-color),
   /* 影付けの向き⑧↓:  0, -y =   下   */
   0 var(--shadow-offset-negative) var(--shadow-thickness) var(--shadow-color);
 }

 body * {
  border: hsla(0, 50%, 50%, 0.5) solid 4mm;
 }

 body {
  background-color: #888;
  color: #fff;
  font-size: 20mm;
 }

 #html-text {
  background-color: yellow;
  color: #fff;
  text-shadow: var(--shadow);
 }

 img {
  background-color: yellow;
  width: 60mm;
 }

 .x2{
  width: 120mm;
 }
</style>

<!-- 例A: HTML の文字列要素 + CSS による擬似的な縁取り -->
<p id="html-text">"This 😊 is a happy symbol."</p>

<!-- 例B: HTML に img で読み込む SVG + SVG の内部で stroke で縁取り -->
<img id="with-stroke" src="with-stroke.svg" />

<!-- 例C: HTML に img で読み込む SVG + SVG の内部で shadow で縁取り -->
<img id="with-shadow" src="with-shadow.svg" />

<br/>

<img class="x2" id="with-stroke" src="with-stroke.svg" />
<img class="x2" id="with-stroke" src="with-shadow.svg" />

repos

参考

License

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?