保留 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" 放在<g>
元素上。您能够做自己想做的事情的唯一方法是在 javascript 中自己计算纵横比并对文本元素应用逆变换。
或者可能在<div>
中尝试使用两个单独的 svg 子项,一个使用 preserveAspectRatio="xMidYMid" 文本,另一个使用非文本。
@RobertLongson 我自己如何在 JS 中保持纵横比?你能在答案中概述一下吗?
【参考方案1】:
我知道这是一个老问题,但我确实找到了一种方法来做纯 SVG 中所要求的事情,没有 JS,而且我已经在 prod 中使用它没有问题!
诀窍是定义一个没有viewBox
的父<svg>
元素,以便它获取容器的尺寸,然后为您想要的不同类型的preserveAspectRatio
值定义子<svg>
元素!
在下面的 sn-p 中,我只是把问题中使用的 SVG 放在了一个 <svg viewBox="0 0 100 100" preserveAspectRatio="none">
中。
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:最终结果甚至可以用作常规图像<img src="./my-weird-responsive-svg.svg" />
的 src,这使得这个技巧非常强大!
【讨论】:
【参考方案2】:问题:如何让标签保持其纵横比,同时改变 svg 的纵横比?
你不能。如果文本是 SVG 的一部分,它会使用 SVG 进行缩放。无法使 SVG 的一部分免于缩放。
可能的解决方案:
(1) 从 SVG 中删除文本并将其放在顶部。例如,在您的 HTML 或其他内容中使用定位的 <div>
。
(2) 使用 JS 计算 SVG 的纵横比,并对<text>
元素进行逆缩放变换。
【讨论】:
我在它前面加了一个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 文本的纵横比的主要内容,如果未能解决你的问题,请参考以下文章