保留 SVG 文本的纵横比

Posted

技术标签:

【中文标题】保留 SVG 文本的纵横比【英文标题】:Preserve aspect ratio for SVG Text 【发布时间】:2015-05-20 22:57:13 【问题描述】:

这是我将删除的 https://***.com/questions/29105120/preserve-aspect-ratio-for-svg-text-and-react-to-javascript-touch-events 的编辑副本,因为它提出了 2 个相关但技术上不同的问题。

正如我在上一个问题中已经解释的那样,我正在尝试制作一个带有 4 个按钮的导航 div,一个向左,一个向右,另一个向下,另一个向上。另外,中间需要有一个确定按钮。

这里给出的解释非常有效:Using CSS and html5 to create navigation buttons using trapezoids

我像这样创建了 SVG:

<div class="function height3x svg-container" style="height: 112px; width: 200px;">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="mySVG"   viewBox="0 0 100 100" preserveAspectRatio="none" style="background-color: whitesmoke">
    <g class="function" id="keyboard_btn_24">
        <polygon id="ok" points="25,25 75,25 75,75 25,75"></polygon>
        <text id="ok_text" x="39" y="55">OK</text>
    </g>
    <g class="function" id="keyboard_btn_25">
        <polygon id="up" stroke="black" stroke- points="0,0 100,0 65,35 35,35"></polygon>
        <text x="42" y="20"></text>
    </g>
    <g class="function" id="keyboard_btn_26">
        <polygon id="right" stroke="black" stroke- points="100,0 100,100 65,65 65,35"></polygon>
        <text x="81" y="53"></text>
    </g>
    <g class="function" id="keyboard_btn_27">
        <polygon id="down" stroke="black" stroke- points="0,100 35,65 65,65 100,100"></polygon>
        <text x="42" y="91"></text>
    </g>
    <g class="function" id="keyboard_btn_28">
        <polygon id="left" stroke="black" stroke- points="0,0 35,35 35,65 0,100"></polygon>
        <text x="5" y="53"></text>
    </g>
</svg>
</div>

但我有两个问题我似乎无法弄清楚。

首先:虽然我希望 SVG 具有响应性,但我不想在不保持字体给出的纵横比的情况下缩放文本。

我已经尝试过(不成功)preserveAspectRatio,它似乎对文本没有多大作用。

问题:如何让标签保持其纵横比,同时改变 svg 的纵横比?

您可以查看和编辑最小示例:jsFiddle

Paulie_D - 评论了我的老问题:

至于纵横比,您应该删除宽度和高度 100% 价值观。它们并不是真正需要的。 SVG 将缩放到所需的 大小基于 div 大小。 - jsfiddle.net/2qqrL7ng/1 -

这不是一个选项,因为 SVG 元素需要响应无法保持纵横比的大小变化。只是文字需要保持比例,其他一切都应该尽可能响应。

编辑

将 perserveAspectRatio 的 svg 参数从“none”切换到“xMidYMid”可以保持 SVG 的纵横比,但想要的效果是,SVG 本身不会保持它的纵横比,但 -tags 可以。这意味着以下将不是解决方案:

<div class="function height3x svg-container" style="height: 112px; width: 200px;">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="mySVG"   viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" style="background-color: whitesmoke">
        <g class="function" id="keyboard_btn_24">
            <polygon id="ok" points="25,25 75,25 75,75 25,75"></polygon>
            <text id="ok_text" x="39" y="55">OK</text>
        </g>
        <g class="function" id="keyboard_btn_25" preserveAspectRatio="xMidYMid">
            <polygon id="up" stroke="black" stroke- points="0,0 100,0 65,35 35,35"></polygon>
            <text x="42" y="20"></text>
        </g>
        <g class="function" id="keyboard_btn_26">
            <polygon id="right" stroke="black" stroke- points="100,0 100,100 65,65 65,35"></polygon>
            <text x="81" y="53"></text>
        </g>
        <g class="function" id="keyboard_btn_27">
            <polygon id="down" stroke="black" stroke- points="0,100 35,65 65,65 100,100"></polygon>
            <text x="42" y="91"></text>
        </g>
        <g class="function" id="keyboard_btn_28">
            <polygon id="left" stroke="black" stroke- points="0,0 35,35 35,65 0,100"></polygon>
            <text x="5" y="53"></text>
        </g>
    </svg>
</div>

/编辑

提前致谢。

【问题讨论】:

preserveAspectRatio="xMidYMid" 对我有用,“没什么用”到底是什么意思? 我编辑了我的问题以澄清我的意思,抱歉如此不准确。 您不能将 preserveAspectRatio="xMidYMid" 放在 &lt;g&gt; 元素上。您能够做自己想做的事情的唯一方法是在 javascript 中自己计算纵横比并对文本元素应用逆变换。 或者可能在&lt;div&gt; 中尝试使用两个单独的 svg 子项,一个使用 preserveAspectRatio="xMidYMid" 文本,另一个使用非文本。 @RobertLongson 我自己如何在 JS 中保持纵横比?你能在答案中概述一下吗? 【参考方案1】:

我知道这是一个老问题,但我确实找到了一种方法来做纯 SVG 中所要求的事情,没有 JS,而且我已经在 prod 中使用它没有问题!

诀窍是定义一个没有viewBox 的父&lt;svg&gt; 元素,以便它获取容器的尺寸,然后为您想要的不同类型的preserveAspectRatio 值定义子&lt;svg&gt; 元素!

在下面的 sn-p 中,我只是把问题中使用的 SVG 放在了一个 &lt;svg viewBox="0 0 100 100" preserveAspectRatio="none"&gt; 中。

div 
  height: 112px;
  width: 200px;


div > svg 
  height: 100%;
  width: 100%;
  background-color: whitesmoke;


polygon 
  fill: none;
  stroke: black;
  stroke-width: 0.1;
<div>
  
  <!-- SVG wrapper without viewBox to take parent's dimensions -->
  <svg>
  
    <!-- sub SVG that will be resized -->
    <svg viewBox="0 0 100 100" preserveAspectRatio="none">
      <g>
        <polygon points="0,0 100,0 65,35 35,35"></polygon>
        <text x="42" y="20"></text>
      </g>
      <g>
        <polygon points="100,0 100,100 65,65 65,35"></polygon>
        <text x="81" y="53"></text>
      </g>
      <g>
        <polygon points="0,100 35,65 65,65 100,100"></polygon>
        <text x="42" y="91"></text>
      </g>
      <g>
        <polygon points="0,0 35,35 35,65 0,100"></polygon>
        <text x="5" y="53"></text>
      </g>
    </svg>
    
    <!-- regular SVG elements that won't be resized -->
    <text id="ok_text" 
          x="50%" y="50%" 
          text-anchor="middle" 
          alignment-baseline="middle">
      OK
    </text>
    
  </svg>
</div>

PS:最终结果甚至可以用作常规图像&lt;img src="./my-weird-responsive-svg.svg" /&gt; 的 src,这使得这个技巧非常强大!

【讨论】:

【参考方案2】:

问题:如何让标签保持其纵横比,同时改变 svg 的纵横比?

你不能。如果文本是 SVG 的一部分,它会使用 SVG 进行缩放。无法使 SVG 的一部分免于缩放。

可能的解决方案:

(1) 从 SVG 中删除文本并将其放在顶部。例如,在您的 HTML 或其他内容中使用定位的 &lt;div&gt;

(2) 使用 JS 计算 SVG 的纵横比,并对&lt;text&gt; 元素进行逆缩放变换。

【讨论】:

我在它前面加了一个div,用js写了定位逻辑。谢谢你的回答。 @S.vanWickern : 你能发布你的解决方案吗,对你有用吗? 如果您使用 svg 之外的 div 执行此操作,您的情况非常简单,因为您只需要在中心显示“OK”文本。你可以用 CSS 定位它,不需要 JS。 我想我确实找到了一种以干净的纯 SVG 方式执行此操作的方法。随时查看我的答案;)【参考方案3】:

如果您对当前尺寸有 javascript 控制(例如,全屏显示,或者只是通过检查用户正在使用的视口大小),您可以在 SVG 外部的父 div 中添加一个简单的类。

然后,为以下两种情况设置 SVG 文本的字体大小样式:当父 div 具有此类(它告诉您您的 svg 已缩放)时,以及当父 div 没有此类时(即 SVG是非缩放的)。如果是这种情况,这个简单的解决方案就可以了。

.svg_text font-size: 12px; /* normal non-scaled SVG */
.case_for_big_screen_thus_SVG_scaled .svg_text font-size: 6px; /* this parent class only is added when viewport dimensions make your SVG to be scaled */

【讨论】:

以上是关于保留 SVG 文本的纵横比的主要内容,如果未能解决你的问题,请参考以下文章

如何使用“包含”选项调整图像的大小,但保留原始尺寸的纵横比?

使用 CSS 更改 SVG Viewbox 大小

如何在没有纵横比的情况下在 SVG 中保持图像的纵横比

显示图像时在最小化/最大化期间保留纵横比?

调整图像大小并裁剪为新的纵横比

缩放 HTML5 画布宽度保留 w/h 纵横比