我发现的一切都是相反的,例如“如何缩放文本以适合 SVG”。但我想达到相反的效果:
我的 html 中的 SVG:
<svg class="text" xmlns='http://www.w3.org/2000/svg' stroke='black' fill='none'>
<text>
<tspan>Some Text</tspan>
</text>
</svg>
Run Code Online (Sandbox Code Playgroud)
CSS:
svg.text {
font-size: 2.5rem; // changes on different screen sizes
height: 0.8em;
width: auto; // This doesn't work... the width becomes something weird, always the same, no matter the contents of the text
}
svg.text text {
transform: translateY(0.8em); // needed this to make the text visible at all
}
Run Code Online (Sandbox Code Playgroud)
我希望<svg>增长以匹配元素的宽度text,就像普通 DOM 元素设置为display: inline-block;or position: absolute;or一样float: left;
有任何想法吗?
感谢@enxaneta 的评论,我想出了这个:
JavaScript:
/**
* Fit SVGs to their first text child's viewBox
*/
fitSvgTextElements() {
const elements = document.querySelectorAll('svg.text');
for( const el of elements ) {
const box = el.querySelector('text').getBBox();
el.setAttribute('viewBox', `${box.x} ${box.y} ${box.width} ${box.height}`);
}
}
Run Code Online (Sandbox Code Playgroud)
这有效。但是有没有办法用纯 CSS/SVG 属性来解决这个问题呢?
由于 SVG 格式的基本设计决策,如果不编写脚本就无法实现您想要实现的尺寸更改。该规范对相关概念的描述如下:
所有 SVG 内容都在SVG 视口内绘制。每个 SVG 视口都定义一个绘图区域,其特征在于尺寸(宽度、高度)和原点...
SVG 视口的宽度、高度和原点是通过生成 SVG 视口的 SVG 文档片段与该片段的父片段(无论是真实的还是隐式的)之间的协商过程确定的...
这意味着视口的尺寸取决于其外部上下文,但与其内部内容无关。
您尝试按其内容调整视口元素的大小会颠倒该逻辑顺序,并且只能在渲染最初完成后才能实现。此时,只有脚本可以更改渲染的 DOM。
如何进行脚本化解决方案,您已经在问题中演示了,尽管我会写得有点不同。虽然 CSS 规则width: auto; height: 1em 应该足够了,但一些较旧的浏览器在这方面存在问题。我更喜欢明确地计算元素width的样式<svg>。(width属性的特异性低于 CSS 样式表规则。)
fitSvgTextElements() {
const elements = document.querySelectorAll('svg.text');
for( const el of elements ) {
const box = el.querySelector('text').getBBox();
el.setAttribute('viewBox', `${box.x} ${box.y} ${box.width} ${box.height}`);
// the <svg> element is in HTML context,
// so you need dimensions in relation to the page viewport
const viewport = el.getBoundingClientRect();
// retain height, recompute width in relation
const width = viewport.height * box.width / box.height;
el.style.width = `${width}px`;
}
}
Run Code Online (Sandbox Code Playgroud)
事实上,我发现了一种更干净的方法。魔法属性是显性基线,这里有提到。
HTML 中的 SVG(在元素dominant-baseline="hanging"上text):
<svg class="text" xmlns='http://www.w3.org/2000/svg'>
<text dominant-baseline="hanging">
My Text
</text>
</svg>
Run Code Online (Sandbox Code Playgroud)
JS:
<svg class="text" xmlns='http://www.w3.org/2000/svg'>
<text dominant-baseline="hanging">
My Text
</text>
</svg>
Run Code Online (Sandbox Code Playgroud)
...现在我可以在 CSS 中调整文本大小,例如:
/**
* Fit SVGs to their first text child's width and height
*/
fitSvgTextElements() {
const elements = document.querySelectorAll('svg.text');
for( const el of elements ) {
const box = el.querySelector('text').getBBox();
el.style.width = `${box.width}px`;
el.style.height = `${box.height}px`;
}
}
window.addEventListener('load', fitSvgTextElements);
window.addEventListener('resize', fitSvgTextElements);
Run Code Online (Sandbox Code Playgroud)