SVGでtext要素を上下左右中央寄せする

SVGで上下中央や左右中央、上下左右中央揃えをしてみます。CSSみたいに簡単にできたらいいのですが、そうはいかないようです。

左右中央寄せ


<svg viewBox="0 0 200 100">
  <text x="50%" y="50%" text-anchor="middle">文字</text>
  <rect x="0" y="0" width="200" height="100" fill="none" stroke="#12b886"></rect>
</svg>

text-anchor 属性で左右中央揃えにできます。また、分かりやすいように四角で囲んでいます。

上下中央揃え


<svg viewBox="0 0 200 100">
  <text x="0" y="50%" dominant-baseline="central">文字</text>
  <rect x="0" y="0" width="200" height="100" fill="none" stroke="#12b886"></rect>
</svg>

dominant-baseline 属性を使うと上下中央揃えにすることができます。が、 IEやEdgeでは上下中央揃え になりません。調べてみると対応していませんでした。


// IEまたはEdgeのとき
if (/*@cc_on!@*/false || ('-ms-scroll-limit' in document.documentElement.style && '-ms-ime-align' in document.documentElement.style)) {
  var text = document.querySelector('text');
  var textY = text.getAttribute('y');
  // 文字を囲む矩形を取得
  var rect = text.getBBox();
  // text要素のy属性に%が使われていたらviewBoxの半分にする
  if (~textY.indexOf('%')) textY = document.querySelector('svg').getAttribute('viewBox').split(' ')[3] / 2;

  text.setAttribute('dy', (textY - rect.y) - (rect.height / 2));
}

仕方がないので、JavaScriptで何とかします。移動量を計算して、 dy 属性でずらしています。


text.setAttribute('transform', 'translate(0, ' + ((textY - rect.y) - (rect.height / 2)) + ')');

dy 属性ではなく、 transform 属性を使ってもいいかもしれません。

上下左右中央揃え


<svg viewBox="0 0 200 100">
  <text x="50%" y="50%" text-anchor="middle" dominant-baseline="central">文字</text>
  <rect x="0" y="0" width="200" height="100" fill="none" stroke="#12b886"></rect>
</svg>

// IEまたはEdgeのとき
if (/*@cc_on!@*/false || ('-ms-scroll-limit' in document.documentElement.style && '-ms-ime-align' in document.documentElement.style)) {
  var text = document.querySelector('text');
  var textY = text.getAttribute('y');
  // 文字を囲む矩形を取得
  var rect = text.getBBox();
  // text要素のy属性に%が使われていたらviewBoxの半分にする
  if (~textY.indexOf('%')) textY = document.querySelector('svg').getAttribute('viewBox').split(' ')[3] / 2;

  text.setAttribute('dy', (textY - rect.y) - (rect.height / 2));
}

上下中央と左右中央を組み合わせればOKです。