jack
jack

Reputation: 139

How to vertically center <p> text inside an svg <foreignobject>?

I need to center the text inside svg, I can use padding or margin to center it, but I prefer to use vertical-align, which does not work no matter what. Please help if you can. Thanks a lot

p {
  display: inline-block;
  margin: 0;
  text-align: center;
}

svg {
  vertical-align: middle;
  justify-content: center;
}

foreignobject {
  vertical-align: middle;
  justify-content: center;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 260 39" fill="none" class="svg-button-grid__svg" width=" 259.36" ; height="38.26" ;>

  <path d="M13.3999 0.5H245.96C247.574 0.5 248.88 1.80616 248.88 3.42001V34.84C248.88 36.4539 247.574 37.76 245.96 37.76H13.3999C11.7861 37.76 10.48 36.4539 10.48 34.84V26.93H15.72C16.5561 26.93 17.24 26.2461 17.24 25.41C17.24 24.5738 16.5561 23.89 15.72 23.89H10.48V14.46H15.72C16.5561 14.46 17.24 13.7761 17.24 12.94C17.24 12.1038 16.5561 11.42 15.72 11.42H10.48V3.42001C10.48 1.80614 11.7861 0.5 13.3999 0.5Z"
    stroke="#FFEC83"
  />
    <foreignobject width="260" height="39">
      <p class="svg-button-grid__text">WATCH TRAILER</p>
    </foreignobject>
</svg>

Upvotes: 1

Views: 906

Answers (3)

herrstrietzel
herrstrietzel

Reputation: 17283

As pointed out by @Danny '365CSI' Engelman: you might consider to use native svg text elements instead of <foreignobject>

Probably the main reason why you should opt for <foreignobject> – you need multiline text and complex styling.

However, this element will quite often introduce unnecessary issues/drawbacks:

  • quirky browser rendering when combined with animations, complex transformations, filters etc.
  • doesn't work well as a standalone svg. E.g if you need to export/convert your svg for pdf/print/office-application usage.

In your case: your svg <path> frame won't automatically grow or shrink to fit the current amount of text.

So, using native svg <text> elements with relative units might provide are more robust solution:

body {
  font-size: 15vw;
}

.svg-button-grid__svg {
  height: 1em;
  border: 1px solid #ccc;
  overflow: visible;
}

.svg-button-grid__text {
  font-size: 20px;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 239 38" class="svg-button-grid__svg">
  <path d="M3 0.5h232.6c1.6 0 2.9 1.3 2.9 2.9v31.4c0 1.7-1.3 3-2.9 3h-232.6c-1.6 0-2.9-1.3-2.9-3v-7.9h5.2c0.9 0 1.5-0.7 1.5-1.5s-0.6-1.5-1.5-1.5h-5.2v-9.4h5.2c0.9 0 1.5-0.7 1.5-1.6s-0.6-1.5-1.5-1.5h-5.2v-8c0-1.6 1.3-2.9 2.9-2.9z" stroke="#FFEC83" fill="none" />
  <text x="50%" y="50%" text-anchor="middle" dy="2" dominant-baseline="middle" class="svg-button-grid__text">WATCH TRAILER</text>
</svg>

How it works

  • optimize your viewBox to match the actual boundaries via getBBox()
  • optimize your pathData by converting it to relative and shifting the first (M command's) x/y starting coordinates to fit the viewBox boundaries as well.
  • now you can easily center the <text> element by percentage based units like x="50%" y="50%" and text-anchor:middle (kind of the svg equivalent to text-align:center).
  • baseline alignment: apply dominent-basline:middle and optionally a dy value for a fine tuned baseline offset to get the desired result.

Upvotes: 2

Or SVG only with textPath

<svg viewbox="0 0 260 39">
   <path d="m13.4.5h232.6c1.6 0 2.9 1.3 2.9 2.9v31.4c0 1.7-1.3 3-2.9 3h-232.6c-1.6 0-2.9-1.3-2.9-3v-7.9h5.2c.9 0 1.5-.7 1.5-1.5 0-.8-.6-1.5-1.5-1.5h-5.2v-9.4h5.2c.9 0 1.5-.7 1.5-1.6 0-.8-.6-1.5-1.5-1.5h-5.2v-8c0-1.6 1.3-2.9 2.9-2.9z"
         fill="beige" stroke="gold"/>
  <path id="P" pathLength="2" d="M19 22h220" stroke="blue"/>
  <text>
    <textPath href="#P" 
              startoffset="1" text-anchor="middle" 
              dominant-baseline="middle"
              fill="green" font-size="20px">WATCH TRAILER</textPath>
  </text>
</svg>

Upvotes: 1

Anurag Srivastava
Anurag Srivastava

Reputation: 14423

You can simply set flex and height properties on p, removing other css:

p {
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  height: inherit;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 260 39" fill="none" class="svg-button-grid__svg" width=" 259.36" ; height="38.26" ;>

  <path d="M13.3999 0.5H245.96C247.574 0.5 248.88 1.80616 248.88 3.42001V34.84C248.88 36.4539 247.574 37.76 245.96 37.76H13.3999C11.7861 37.76 10.48 36.4539 10.48 34.84V26.93H15.72C16.5561 26.93 17.24 26.2461 17.24 25.41C17.24 24.5738 16.5561 23.89 15.72 23.89H10.48V14.46H15.72C16.5561 14.46 17.24 13.7761 17.24 12.94C17.24 12.1038 16.5561 11.42 15.72 11.42H10.48V3.42001C10.48 1.80614 11.7861 0.5 13.3999 0.5Z"
    stroke="#FFEC83"
  />
    <foreignobject width="260" height="39">
      <p class="svg-button-grid__text">WATCH TRAILER</p>
    </foreignobject>
</svg>

Upvotes: 4

Related Questions