IT Man
IT Man

Reputation: 1036

SVG: fixed font size

I have an SVG inlined to html code. Its is scaled to fit width with preserving aspect ratio. Is there a way to set font size fixed to viewport that can be controlled with media queries?

EDIT: The problem is when i set fixed font-size within width range the font is resized anyway relative to svg size.

#svg-container {
  width: 100%;
  padding-bottom: 70%;
  overflow: hidden;
  border: 1px solid red;
}

#svg-container svg text tspan {
  font-size: 14px;
}


@media (min-height: 800px) {
  #svg-container svg text tspan {
    font-size: 50px;
  }
}
<div id="svg-container">
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   version="1.1"
   viewBox="0 0 500 350"
   data-name="Layer 1"
   id="Layer_1"
   inkscape:version="0.91 r13725"
   sodipodi:docname="Desktop_Enhanced.svg"
   width="100%"
   style="position: absolute; left: 0; top: 0;"   
  >
  <sodipodi:namedview
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1"
     objecttolerance="10"
     gridtolerance="10"
     guidetolerance="10"
     inkscape:pageopacity="0"
     inkscape:pageshadow="2"
     inkscape:window-width="1280"
     inkscape:window-height="961"
     id="namedview51"
     showgrid="false"
     inkscape:zoom="1.0054235"
     inkscape:cx="231.42799"
     inkscape:cy="361.93137"
     inkscape:window-x="1272"
     inkscape:window-y="-8"
     inkscape:window-maximized="1"
     inkscape:current-layer="Layer_1"
     fit-margin-bottom="150" />
  <metadata
     id="metadata75">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title>Desktop</dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <defs
     id="defs3">
    <style
       id="style5">.cls-1{fill:#da1f26;}.cls-2{fill:#252e43;}.cls-3{fill:#d1d3d4;}</style>
  </defs>
  <title
     id="title7">Desktop</title>
  <polyline
     id="polyline9"
     points="329.4 62.24 343.54 76.39 329.4 90.53"
     class="cls-1"
     style="fill:#da1f26"
     transform="translate(59.579252,-43.513817)" />
  <polyline
     id="polyline11"
     points="333.56 328.83 347.7 342.97 333.56 357.11"
     class="cls-2"
     style="fill:#252e43"
     transform="translate(59.579252,-43.513817)" />
  <path
     id="path35"
     d="m 394.84925,294.48618 -25,0 c -57.81,0 -77.28,-34.66 -96.1,-68.18 -15.35,-27.34 -29.86,-53.16 -63.9,-53.16 l -31.27,0 0,10 31.3,0 c 28.19,0 40.7,22.27 55.18,48.06 9.68,17.23 19.69,35.06 35.5,49.13 18.26,16.22 40.93,24.15 69.33,24.15 l 25,0 z"
     class="cls-2"
     inkscape:connector-curvature="0"
     style="fill:#252e43" />
  <path
     id="path43"
     d="m 390.97925,27.876183 -21.09,0 c -28.4,0 -51.07,7.9 -69.32,24.15 -15.81,14.08 -25.82,31.9 -35.5,49.129997 -14.48,25.79 -27,48.06 -55.18,48.06 l -31.31,0 0,10 31.3,0 c 34,0 48.54,-25.82 63.9,-53.16 18.8,-33.569997 38.3,-68.179997 96.11,-68.179997 l 21.09,0 z"
     class="cls-1"
     inkscape:connector-curvature="0"
     style="fill:#da1f26" />
  <path
     id="path45"
     d="m 429.38925,17.956183 a 14.92,14.92 0 1 0 14.92,14.92 14.92,14.92 0 0 0 -14.92,-14.92 z m 0,21 a 6.08,6.08 0 1 1 6.08,-6.08 6.08,6.08 0 0 1 -6.08,6.08 z"
     class="cls-1"
     inkscape:connector-curvature="0"
     style="fill:#da1f26" />
  <path
     id="path47"
     d="m 433.38925,284.53618 a 14.92,14.92 0 1 0 14.92,14.95 14.92,14.92 0 0 0 -14.92,-14.95 z m 0,21 a 6.08,6.08 0 1 1 6.09,-6.05 6.08,6.08 0 0 1 -6.09,6.05 z"
     class="cls-2"
     inkscape:connector-curvature="0"
     style="fill:#252e43" />
  <flowRoot
     style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
     id="flowRoot4236"
     xml:space="preserve"
     transform="translate(0,-72.53)"><flowRegion
       id="flowRegion4238"><rect
         y="179.54243"
         x="18.988897"
         height="58.373276"
         width="94.241196"
         id="rect4240" /></flowRegion><flowPara
       id="flowPara4242">ZakładaZ</flowPara></flowRoot>  <text
     x="27.791037"
     y="169.90349"
     font-size="20px"
     id="text49-1"
     style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:15px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#252e43;fill-opacity:1"
     sodipodi:linespacing="125%">
    <tspan
       sodipodi:role="line"
       id="tspan4528"
       x="27.791037"
       y="169.90349">PLEASE CHOOSE</tspan>
  </text>
</svg>


</div>

Upvotes: 11

Views: 24992

Answers (5)

Randelung
Randelung

Reputation: 412

I'd recommend nested SVG tags. You can keep your outermost SVG without viewBox and add all text under this tag, while adding a second SVG to cover the full area but using a viewBox.

You'll need to change positions for the text from absolute to relative values, but it works quite well.

That way your text will change position with the svg size but not scale the text. The inner SVG will, though, since you set a viewBox.

Example: JS for variable container, SVG always fills the div. The scaling is pure SVG.

function changeCircleDiv(element) {
  s = document.getElementById("container").style;
  s.width = element.value + 'px';
  s.height = s.width;
}
body {
  font-size: 2em;
}
<input type="number" onchange="changeCircleDiv(this);" value="100"></input>
<div id="container" style="width: 100px; height: 100px;">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%">
        <svg width="100%" height="100%" viewBox="0 0 20 20">
            <circle cx="10" cy="10" r="8" stroke="black" fill="none"/>
        </svg>
        <text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle">Center</svg>
    </svg>
</div>

Upvotes: 9

Jordan Klaers
Jordan Klaers

Reputation: 149

I actually found a relatively simple workaround.

using D3's scaleSqrt() you can do some math based on the pixel width that the svg is taking up.

For example if the svg viewbox width is 800, then when the svg has a width of 800px, the scale would be 1. When the pixel width of the svg is 400px, relative to the view box, that would be a scale of 1/2

scaleRatio = d3.scaleSqrt()
    .domain([1600, 800, 600, 400, 200, 100])
    .range([0.5, 1, 1.5, 2, 4, 8]);
const svgWidth = d3.select(svg).node().getBoundingClientRect().width;
someD3Element.attr('transform', `scale(${scaleRatio(svgWidth)})`);

Upvotes: 0

zurcacielos
zurcacielos

Reputation: 1702

You can do it in this way "Responsive SVG with sticky text" See here: https://bl.ocks.org/veltman/5cd1ba0b3c623e7b5146

Or... if you want to use media queries for font in SVG, the answer is yes. Run this code snippet.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100%" height="200px">
  <style>
    text {
      font-size: 10px;
    }

    @media (max-width: 600px) {
      text {
        font-size: 20px;
      }
    }

    @media (max-width: 800px) {
      text {
        font-size: 16px;
      }
    }

  </style>
  <circle cx="50" cy="50" r="50" fill="orange"/>
  <text x="50" y="60" text-anchor="middle">Testing</text>
</svg>

Upvotes: 1

IT Man
IT Man

Reputation: 1036

In the end...

I have removed text from svg and added div text block with absolute positioning inside shared html container. That worked prefect. Div's appearance is controlled over css with media queries - it is independent from svg scaling.

Your can see diagram in action at: https://www.xtech.pl/jak-to-dziala-dla-dostawcy (scroll down to second section on the page, then you can resize your screen to see how it works).

Upvotes: 5

Paul LeBeau
Paul LeBeau

Reputation: 101800

The short answer is no.

If the text is in an SVG with a viewBox, and the SVG gets scaled, its contents get scaled also. There is no way to make the text have a "global" size that is unaffected by the SVG scaling.

The only possible solution would be calculate the scaling factor using Javascript and dynamically update the font size every time the SVG size changed.

Upvotes: 10

Related Questions