Search code examples
htmlcsssvg

How to align text inside of a SVG


I am attempting to show text within different sections of an SVG. Due to the curvature of the SVG, I was unable to do this without purchasing various plugins for the software used to generate the SVG (Most of the plugins also didn't provide the desired effect when free trials were used), so I turned to trying to resolve this with HTML and CSS. I found a similar thread which put me on the right path to getting the text within the bounds of the SVG paths but not to the desired locations.

Here is a snippet of the HTML and CSS I currently have:

path:hover {
  fill: #9F1F;
  cursor: pointer;
}

svg>text {
  font-size: 24pt;
  font-weight: 600;
  fill: white;
}
<svg width="540" height="540" viewBox="0 0 1260 1260" style="background: #f4f4f8;" xmlns="http://www.w3.org/2000/svg">
    <path id="lorem-ipsum" d="M19.6535 473.868C47.9918 363.089 105.946 262.111 187.302 181.761C268.658 101.41 370.349 44.7167 481.472 17.7586L494.995 73.5011C393.989 98.0047 301.557 149.536 227.608 222.571C153.659 295.606 100.982 387.39 75.2235 488.083L19.6535 473.868Z" fill="#58585A" stroke="white" stroke-width="10" mask="url(#path-1-inside-1_4_33)"/>
    <text>
        <textPath style="color: #fff;" xlink:href="#lorem-ipsum" startOffset="310" text-anchor="middle" dominant-baseline="central">
            Lorem Ipsum
        </textPath>
    </text>
    <path id="dolor-sit" d="M943.948 453.828C974.447 508.179 990.314 569.517 989.995 631.839C989.677 694.162 973.184 755.334 942.132 809.371C911.079 863.407 866.529 908.456 812.843 940.11C759.156 971.764 698.172 988.938 635.857 989.952C573.542 990.966 512.03 975.785 457.343 945.895C402.655 916.004 356.663 872.428 323.869 819.43C291.075 766.433 272.601 705.829 270.255 643.55C267.909 581.271 281.772 519.449 310.487 464.135L354.36 486.91C329.588 534.629 317.629 587.962 319.653 641.689C321.676 695.417 337.614 747.699 365.905 793.419C394.196 839.14 433.872 876.732 481.051 902.518C528.229 928.304 581.294 941.401 635.053 940.526C688.811 939.652 741.422 924.836 787.736 897.528C834.051 870.221 872.483 831.357 899.272 784.741C926.061 738.124 940.289 685.352 940.563 631.587C940.838 577.822 927.15 524.907 900.839 478.019L943.948 453.828Z" fill="#9F1F63" stroke="white" stroke-width="10" mask="url(#path-6-inside-6_4_33)"/>
    <text>
        <textPath xlink:href="#dolor-sit" startOffset="2175" text-anchor="middle" dominant-baseline="central">
            Dolor Sit
        </textPath>
    </text>
    <path id="amet" d="M476.668 407.763C521.185 377.048 573.901 360.411 627.985 360.008C682.069 359.604 735.028 375.452 779.999 405.5L749.393 451.307C713.598 427.391 671.445 414.776 628.396 415.097C585.348 415.418 543.388 428.661 507.954 453.109L476.668 407.763Z" fill="#9F1F63" stroke="white" stroke-width="10" mask="url(#path-11-inside-11_4_33)"/>
    <text>
        <textPath xlink:href="#amet" startOffset="160" text-anchor="middle" dominant-baseline="central">
            Amet
        </textPath>
    </text>
</svg>

I am expecting the text to be centred within the purple section of the SVG and I have tried using CSS position, margin, padding etc.


Solution

  • The three paths are all outlines of a stroke, therefor it becomes difficult to align the text inside or between the path outline.

    Now that all you paths effectively are strokes, you can turn the path into one line/outline, and give them a stroke instead of a fill. The text elements with the textPath element will now align to the stroke.

    a:hover use:nth-child(1) {
      stroke: Turquoise;
    }
    
    a:hover use:nth-child(2) {
      stroke: #9F1F;
    }
    
    svg text {
      font-size: 24pt;
      font-weight: 600;
      fill: white;
    }
    <svg width="540" height="540" viewBox="0 0 1260 1260" style="background: #f4f4f8;" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <path id="lorem-ipsum" d="M 60 514 C 88 403 146 302 227 222 C 309 141 410 85 521 58"
          fill="none" stroke-linecap="square" />
      </defs>
      <a href="#">
        <use href="#lorem-ipsum" stroke="white" stroke-width="80"  />
        <use href="#lorem-ipsum" stroke="#58585A" stroke-width="60" />
        <text>
          <textPath fill="white" href="#lorem-ipsum"
            startOffset="50%" text-anchor="middle"
            dominant-baseline="central">Lorem Ipsum</textPath>
        </text>
      </a>
    </svg>

    How to convert the paths

    To convert the path from an outline of a stroke to a single line/outline I did the following:

    1. Copied the path (value of the d attribute) into https://yqnn.github.io/svg-path-editor/
    2. Removed that last half of the path commands including the z
    3. Moved the path down and to the right (Translate x/Translate y) so that there was space for a wide stroke + the extra wide stroke for the white "border".
    4. (optional) Now that the viewBox was quite large (1260x1260) I could removed all the decimals (Number of decimals).

    How to make hover work

    It actually worked in Firefox, but to make it work in Chrome you can add a <a> element around the svg elements that need to change on hover.