提问人:Francesca 提问时间:4/17/2013 最后编辑:TylerHFrancesca 更新时间:8/15/2023 访问量:2084287
基于容器大小的字体缩放
Font scaling based on size of container
问:
我很难弄清楚字体缩放。
我目前有一个网站,正文是 100%。100%的呢?这似乎是在 16 像素处计算出来的。font-size
我的印象是 100% 会以某种方式指浏览器窗口的大小,但显然不是,因为无论窗口大小调整为移动宽度还是成熟的宽屏桌面,它始终是 16 像素。
如何使网站上的文本与其容器相关?我尝试使用 ,但这也无法扩展。em
我的理由是,当你调整大小时,像我的菜单这样的东西会被压扁,所以我需要减少与容器宽度相关的其他元素。(例如,在大桌面上的菜单中,可以完美运行。向下移动到平板电脑宽度,更合适。px
font-size
.menuItem
22px
16px
我知道我可以添加断点,但我真的希望文本能够缩放并具有额外的断点,否则,我最终会因为宽度每减少 100 像素而产生数百个断点来控制文本。
答:
100% 是相对于基本字体大小的,如果您尚未设置,则该字体大小将是浏览器的用户代理默认值。
为了获得您想要的效果,我会使用一段 JavaScript 代码来调整相对于窗口尺寸的基本字体大小。
在你的CSS中,试着在底部添加这个,改变320像素的宽度,以适应你的设计开始中断的地方。
@media only screen and (max-width: 320px) {
body { font-size: 1em; }
}
然后根据需要在“px”或“em”中给出字体大小。
容器查询现在可能是最佳选择,具体取决于您的用例,并且支持所有主要浏览器。在此处查看支持级别:https://caniuse.com/mdn-css_properties_container
现在非常容易控制
.module h2 {
font-size: 1em;
container-name: sidebar
}
@container sidebar (min-width: 700px) {
.module h2 {
font-size: 2em;
}
}
请查看 MDN 文章 容器查询 了解更多详情: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries
您可以完成的任务的更多示例: https://css-tricks.com/a-few-times-container-size-queries-would-have-helped-me-out/
=========================
旧答案
如果容器不是正文,则 CSS Tricks 涵盖了 Fitting Text to a Container 中的所有选项。
如果容器是正文,则要查找的是视口百分比长度:
视口百分比长度与初始包含块的大小有关。当初始包含块的高度或宽度发生变化时,它们会相应地缩放。但是,当根元素上的溢出值为 auto 时,假定任何滚动条都不存在。
这些值为:
vw
(视口宽度的百分比)vh
(视口高度的百分比)vi
(根元素内联轴方向的视口大小的 1%)vb
(根元素块轴方向上视口大小的 1%)vmin
(或vw
vh
)vmax
(以较大者或 或vw
vh
)
1 v* 等于初始包含块的 1%。
使用它看起来像这样:
p {
font-size: 4vw;
}
如您所见,当视口宽度增加时,,font-size
这些值是一个大小调整单位,就像 或 一样,因此它们也可用于调整其他元素的大小,例如宽度、边距或填充。px
em
浏览器支持相当不错,但您可能需要回退,例如:
p {
font-size: 16px;
font-size: 4vw;
}
查看支持统计信息:http://caniuse.com/#feat=viewport-units。
另外,请查看 CSS-Tricks 以获得更广泛的了解: 视口大小的排版
这是一篇关于设置最小/最大尺寸和对尺寸进行更多控制的好文章: 精确控制响应式排版
这是一篇关于使用 calc() 设置大小以使文本填充视口的文章: http://codepen.io/CrocoDillon/pen/fBJxu
另外,请查看这篇文章,该文章也使用一种称为“熔融引导”的技术来调整行高。熔融在CSS中的领先地位
评论
font-size: calc(1rem + 2vw)
container-type
container-name
container
@container
@container
但是,如果容器不是视口(正文)呢?
Alex 在 2507rkt3 的回答下的评论中提出了这个问题。
这一事实并不意味着不能在某种程度上用于该容器的大小。现在,要看到任何变化,必须假设容器在某种程度上是灵活的。无论是通过直接百分比还是通过 100% 减去利润。如果容器始终设置为宽,那么这一点就变得“没有意义”了,那么只需设置一个适用于该宽度的容器即可。vw
width
200px
font-size
示例 1
但是,对于灵活宽度的容器,必须意识到容器在某种程度上仍会根据视口调整大小。因此,需要根据视口的大小差异百分比来调整设置,这意味着要考虑父包装器的大小。举个例子:vw
div {
width: 50%;
border: 1px solid black;
margin: 20px;
font-size: 16px;
/* 100 = viewport width, as 1vw = 1/100th of that
So if the container is 50% of viewport (as here)
then factor that into how you want it to size.
Let's say you like 5vw if it were the whole width,
then for this container, size it at 2.5vw (5 * .5 [i.e. 50%])
*/
font-size: 2.5vw;
}
假设这里 是 的子项,它的宽度是这个基本情况下的视口大小。基本上,你想设置一个对你来说看起来不错的。正如你在上面的CSS内容中的评论中看到的那样,你可以从数学上“思考”整个视口的大小,但你不需要这样做。文本将与容器一起“弯曲”,因为容器会随着视口大小的调整而弯曲。下面是两个不同大小的容器的示例。div
body
50%
100%
vw
示例 2
您可以通过强制基于视口进行计算来帮助确保视口大小。请看这个例子:
html {width: 100%;} /* Force 'html' to be viewport width */
body {width: 150%; } /* Overflow the body */
div {
width: 50%;
border: 1px solid black;
margin: 20px;
font-size: 16px;
/* 100 = viewport width, as 1vw = 1/100th of that
Here, the body is 150% of viewport, but the container is 50%
of viewport, so both parents factor into how you want it to size.
Let's say you like 5vw if it were the whole width,
then for this container, size it at 3.75vw
(5 * 1.5 [i.e. 150%]) * .5 [i.e. 50%]
*/
font-size: 3.75vw;
}
大小调整仍然基于视口,但实质上是基于容器大小本身设置的。
如果容器的大小动态变化...
如果容器元素的大小最终通过断点或 JavaScript 动态更改其百分比关系,那么无论基本“目标”是什么,都需要重新计算以保持文本大小的相同“关系”。@media
以上面的 #1 为例。如果 通过 或 JavaScript 将 切换到 width,则同时需要在媒体查询或 JavaScript 中调整为 .这将使文本大小与原始容器的“宽度”从视口大小减少一半时的大小相同,但现在由于其自身百分比计算的更改而减小。div
25%
@media
font-size
5vw * .25 = 1.25
50%
挑战
使用 CSS calc()
函数时,动态调整将变得困难,因为该函数目前不适用于目的。因此,如果您的宽度正在更改,则无法进行纯粹的CSS调整。当然,对边距宽度的微小调整可能不足以保证 的任何更改,因此这可能无关紧要。font-size
calc()
font-size
评论
试试 http://simplefocus.com/flowtype/。这是我用于我的网站的,它运行良好。
您可能正在寻找这样的东西:
http://jsfiddle.net/sijav/dGsC9/4/ http://fiddle.jshell.net/sijav/dGsC9/4/show/
我使用了 flowtype,它运行良好(但它是 JavaScript 而不是纯粹的 CSS 解决方案):
$('body').flowtype({
minFont: 10,
maxFont: 40,
minimum: 500,
maximum: 1200,
fontRatio: 70
});
这个问题有一个很大的哲学。
最简单的方法是给 body 指定一定的字体大小(我建议 10),然后所有其他元素的字体都在 or 中。
我举个例子来理解这些单位。 始终相对于其父级:em
rem
Em
body{font-size: 10px;}
.menu{font-size: 2em;} /* That means 2*10 pixels = 20 pixels */
.menu li{font-size: 1.5em;} /* That means 1.5*20 pixels = 30 pixels */
Rem
始终相对于身体:
body{font-size: 10px;}
.menu{font-size: 2rem;} /* That means 2*10 pixels = 20 pixels */
.menu li{font-size: 1.5rem;} /* that means 1.5*10 pixels = 15 pixels */
然后,您可以创建一个脚本,该脚本将修改相对于容器宽度的字体大小。
但这不是我推荐的。因为例如,在一个 900 像素宽的容器中,你会有一个字体大小为 12 像素的元素。根据你的想法,这将成为一个 300 像素宽的容器,字体大小为 4 像素。必须有一个下限。p
其他解决方案是使用媒体查询,以便您可以设置不同宽度的字体。
但我推荐的解决方案是使用一个 JavaScript 库来帮助您解决这个问题。还有到目前为止我找到的 fittext.js。
功能如下:
document.body.setScaledFont = function(f) {
var s = this.offsetWidth, fs = s * f;
this.style.fontSize = fs + '%';
return this
};
然后将所有文档子元素字体大小转换为 's 或 .em
%
然后将类似这样的内容添加到代码中以设置基本字体大小。
document.body.setScaledFont(0.35);
window.onresize = function() {
document.body.setScaledFont(0.35);
}
我自己的解决方案,基于jQuery,通过逐渐增加字体大小来工作,直到容器的高度大幅增加(这意味着它有一个换行符)。
它非常简单,但效果很好,而且非常易于使用。您不必对所使用的字体一无所知,一切都由浏览器处理。
您可以在 http://jsfiddle.net/tubededentifrice/u5y15d0L/2/ 上玩它
神奇的事情发生在这里:
var setMaxTextSize=function(jElement) {
// Get and set the font size into data for reuse upon resize
var fontSize=parseInt(jElement.data(quickFitFontSizeData)) || parseInt(jElement.css("font-size"));
jElement.data(quickFitFontSizeData, fontSize);
// Gradually increase font size until the element gets a big increase in height (i.e. line break)
var i = 0;
var previousHeight;
do
{
previousHeight=jElement.height();
jElement.css("font-size", "" + (++fontSize) + "px");
}
while(i++ < 300 && jElement.height()-previousHeight < fontSize/2)
// Finally, go back before the increase in height and set the element as resized by adding quickFitSetClass
fontSize -= 1;
jElement.addClass(quickFitSetClass).css("font-size", "" + fontSize + "px");
return fontSize;
};
这可能不是非常实用,但如果你想让字体成为父字体的直接函数,而没有任何 JavaScript 来侦听/循环(间隔)来读取 div/page 的大小,有一种方法可以做到这一点。iframe。
iframe 中的任何内容都会将 iframe 的大小视为视口的大小。因此,诀窍是制作一个 iframe,其宽度是您希望文本的最大宽度,并且其高度等于最大高度 * 特定文本的纵横比。
撇开视口单位不能与文本的父单位并列的限制不谈(例如,让 % 大小的行为与其他所有人一样),视口单位确实提供了一个非常强大的工具:能够获得最小/最大尺寸。你不能在其他任何地方这样做——你不能说......使此 div 的高度为父级 * 的宽度。
话虽如此,诀窍是使用 vmin,并设置 iframe 大小,以便当高度为限制尺寸时,[fraction] * total height 是一个好的字体大小,而当宽度是限制尺寸时,[fraction] * total width。这就是为什么高度必须是宽度和纵横比的乘积。
对于我的具体例子,你有
.main iframe{
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: calc(3.5 * 100%);
background: rgba(0, 0, 0, 0);
border-style: none;
transform: translate3d(-50%, -50%, 0);
}
这种方法的小麻烦是你必须手动设置 iframe 的 CSS。如果附加整个CSS文件,则会占用许多文本区域的大量带宽。所以,我要做的是直接从我的CSS中附加我想要的规则。
var rule = document.styleSheets[1].rules[4];
var iDoc = document.querySelector('iframe').contentDocument;
iDoc.styleSheets[0].insertRule(rule.cssText);
您可以编写获取 CSS 规则/所有会影响文本区域的 CSS 规则的小函数。
我想不出另一种方法,如果没有一些循环/收听 JavaScript。真正的解决方案是让浏览器提供一种方法来缩放文本作为父容器的函数,并提供相同的 vmin/vmax 类型功能。
JSFiddle:https://jsfiddle.net/0jr7rrgm/3/(单击一次将红色方块锁定到鼠标上,再次单击可松开)
小提琴中的大多数 JavaScript 只是我的自定义点击拖动功能。
SVG 解决方案:
.resizeme {
resize: both;
margin: 0;
padding: 0;
height: 75px;
width: 500px;
background-color: lightblue;
overflow: hidden;
}
<div class="resizeme">
<svg
width="100%"
height="100%"
viewBox="0 0 500 75"
preserveAspectRatio="xMinYMid meet"
style="background-color:green"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<text
x="0"
y="75"
font-size="75"
fill="black"
>█Resize This█</text>
</svg>
</div>
SVG和文本换行的解决方案,使用:foreignObject
.resizeme {
resize: both;
margin: 0;
padding: 0;
height: 200px;
width: 500px;
background-color: lightblue;
overflow: hidden;
}
<div class="resizeme">
<svg
width="100%"
height="100%"
viewBox="0 0 500 200"
preserveAspectRatio="xMinYMin meet"
>
<foreignObject width="100%" height="100%" xmlns="http://www.w3.org/1999/xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="background-color:lightgreen;">
<h1>heading</h1>
<p>Resize the blue box.</p>
</div>
</foreignObject>
</svg>
</div>
我的问题与此类似,但与缩放标题内的文本有关。我尝试了 Fit Font,但我需要切换压缩器才能获得任何结果,因为它解决了一个略有不同的问题,就像 Text Flow 一样。
所以我写了我自己的小插件,减小字体大小以适应容器,假设你有,这样即使将字体减小到最小不允许显示完整的标题,它也只是切断了它可以显示的内容。overflow: hidden
white-space: nowrap
(function($) {
// Reduces the size of text in the element to fit the parent.
$.fn.reduceTextSize = function(options) {
options = $.extend({
minFontSize: 10
}, options);
function checkWidth(em) {
var $em = $(em);
var oldPosition = $em.css('position');
$em.css('position', 'absolute');
var width = $em.width();
$em.css('position', oldPosition);
return width;
}
return this.each(function(){
var $this = $(this);
var $parent = $this.parent();
var prevFontSize;
while (checkWidth($this) > $parent.width()) {
var currentFontSize = parseInt($this.css('font-size').replace('px', ''));
// Stop looping if min font size reached, or font size did not change last iteration.
if (isNaN(currentFontSize) || currentFontSize <= options.minFontSize ||
prevFontSize && prevFontSize == currentFontSize) {
break;
}
prevFontSize = currentFontSize;
$this.css('font-size', (currentFontSize - 1) + 'px');
}
});
};
})(jQuery);
在我的一个项目中,我使用 vw 和 vh 之间的“混合”来调整字体大小以满足我的需要,例如:
font-size: calc(3vw + 3vh);
我知道这并不能回答 OP 的问题,但也许它可以成为其他任何人的解决方案。
如果问题是字体在宽屏桌面上变得太大,我认为最简单的 CSS 方法是这样的(假设包装器最大宽度为 1000 像素)
.specialText{
font-size: 2.4vw;
}
@media only screen and (min-width: 1000px) {
.specialText {
width: 24px;
}
}
因此,对于任何小于容器最大宽度的屏幕,它都会自动调整大小,当屏幕较宽时,它会固定大小(就像几乎所有台式机和笔记本电脑一样)。
具有 、 CSS 单位和数学的纯 CSS 解决方案calc()
这恰恰不是 OP 所要求的,但可能会让某人开心。这个答案并不容易,需要开发人员进行一些研究。
我终于得到了一个纯CSS解决方案,用于不同的单元。您将需要对公式有一些基本的数学理解才能计算出 的表达式。calc()
calc()
当我解决这个问题时,我必须得到一个全页宽度的响应式标题,并在 DOM 中填充一些父级。我将在这里使用我的值,用你自己的值替换它们。
到数学
您将需要:
- 在某些视口中很好地调整了比例。我使用了 320 像素,因此我得到了 24 像素高和 224 像素宽,所以比例是 9.333......或 28 / 3
- 容器宽度,我有和全宽,所以这得到了
padding: 3em
100wv - 2 * 3em
X 是容器的宽度,因此请将其替换为您自己的表达式或调整值以获得整页文本。 是您将拥有的比率。您可以通过调整某些视口中的值、检查元素宽度和高度并将它们替换为您自己的值来获得它。此外,它是R
width / heigth
;)
x = 100vw - 2 * 3em = 100vw - 6em
r = 224px/24px = 9.333... = 28 / 3
y = x / r
= (100vw - 6em) / (28 / 3)
= (100vw - 6em) * 3 / 28
= (300vw - 18em) / 28
= (75vw - 4.5rem) / 7
砰!成功了!我写了
font-size: calc((75vw - 4.5rem) / 7)
到我的标题,它在每个视口中都很好地调整了。
但它是如何工作的呢?
我们需要一些常量。 表示视口的全宽,我的目标是建立带有一些填充的全宽标题。100vw
比率。在一个视口中获取宽度和高度可以让我使用比率,并且通过比率,我知道其他视口宽度的高度应该是多少。手动计算它们需要花费大量时间,并且至少需要大量带宽,因此这不是一个好的答案。
结论
我想知道为什么没有人弄清楚这一点,有些人甚至说这不可能修补CSS。我不喜欢使用 JavaScript 来调整元素,所以我不接受 JavaScript(并且忘记 jQuery)答案,而无需深入挖掘。总而言之,这很好,这是在网站设计中实现纯CSS的一个步骤。
对于我的文本中任何不寻常的约定,我深表歉意,我的母语不是英语,而且对编写 Stack Overflow 答案也很陌生。
还应该注意的是,我们在某些浏览器中有邪恶的滚动条。例如,在使用Firefox时,我注意到这意味着视口的整个宽度,延伸到滚动条下(内容无法扩展!),因此全角文本必须仔细留边距,最好在许多浏览器和设备上进行测试。100vw
评论
始终使元素具有以下属性:
JavaScript的:element.style.fontSize = "100%";
或
CSS:style = "font-size: 100%;"
当您进入全屏模式时,您应该已经计算出一个比例变量(比例 > 1 或比例 = 1)。然后,在全屏模式下:
document.body.style.fontSize = (scale * 100) + "%";
它只需很少的代码即可很好地工作。
此 Web 组件更改字体大小,使内部文本宽度与容器宽度匹配。查看演示。
你可以像这样使用它:
<full-width-text>Lorem Ipsum</full-width-text>
作为 JavaScript 后备(或您的唯一解决方案),您可以使用我的 jQuery Scalem 插件,它允许您通过传递选项来相对于父元素(容器)进行缩放。reference
我准备了一个简单的缩放函数,使用 CSS transform 而不是 font-size。您可以在任何容器内使用它,不必设置媒体查询等。 :)
博客文章:全宽 CSS 和 JS 可缩放标头
代码:
function scaleHeader() {
var scalable = document.querySelectorAll('.scale--js');
var margin = 10;
for (var i = 0; i < scalable.length; i++) {
var scalableContainer = scalable[i].parentNode;
scalable[i].style.transform = 'scale(1)';
var scalableContainerWidth = scalableContainer.offsetWidth - margin;
var scalableWidth = scalable[i].offsetWidth;
scalable[i].style.transform = 'scale(' + scalableContainerWidth / scalableWidth + ')';
scalableContainer.style.height = scalable[i].getBoundingClientRect().height + 'px';
}
}
工作演示:https://codepen.io/maciejkorsan/pen/BWLryj
评论
看看我的代码。它使那里的任何东西。font size smaller
fit
但我认为这并不能带来良好的用户体验
var containerWidth = $("#ui-id-2").width();
var items = $(".quickSearchAutocomplete .ui-menu-item");
var fontSize = 16;
items.each(function(){
// Displaying a value depends sometimes on your case. You may make it block or inline-table instead of inline-block or whatever value that make the div take overflow width.
$(this).css({"whiteSpace": "nowrap", "display": "inline-block"});
while ($(this).width() > containerWidth){
console.log("$(this).width()" + $(this).width() + "containerWidth" + containerWidth)
$(this).css("font-size", fontSize -= 0.5);
}
});
如果它对任何人都有帮助,此线程中的大多数解决方案都是将文本包装成多行,形式为 e。
但后来我发现了这一点,它奏效了:
https://github.com/chunksnbits/jquery-quickfit
用法示例:
$('.someText').quickfit({max:50,tolerance:.4})
尝试使用 fitText 插件,因为视口大小不是这个问题的解决方案。
只需添加库:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
并通过设置文本系数来更改字体大小以使其正确:
$("#text_div").fitText(0.8);
您可以设置文本的最大值和最小值:
$("#text_div").fitText(0.8, { minFontSize: '12px', maxFontSize: '36px' });
使用 , & co. 肯定有效,但 IMO 它总是需要人工的触摸来微调。vw
em
这是我刚刚根据 @tnt-rox 的答案编写的脚本,它试图自动化人类的触摸:
$('#controller').click(function(){
$('h2').each(function(){
var
$el = $(this),
max = $el.get(0),
el = null
;
max =
max
? max.offsetWidth
: 320
;
$el.css({
'font-size': '1em',
'display': 'inline',
});
el = $el.get(0);
el.get_float = function(){
var
fs = 0
;
if (this.style && this.style.fontSize) {
fs = parseFloat(this.style.fontSize.replace(/([\d\.]+)em/g, '$1'));
}
return fs;
};
el.bigger = function(){
this.style.fontSize = (this.get_float() + 0.1) + 'em';
};
while (el.offsetWidth < max) {
el.bigger();
}
// Finishing touch.
$el.css({
'font-size': ((el.get_float() -0.1) +'em'),
'line-height': 'normal',
'display': '',
});
}); // end of (each)
}); // end of (font scaling test)
div {
width: 50%;
background-color: tomato;
font-family: 'Arial';
}
h2 {
white-space: nowrap;
}
h2:nth-child(2) {
font-style: italic;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="button" id="controller" value="Apply" />
<div>
<h2>Lorem ipsum dolor</h2>
<h2>Test String</h2>
<h2>Sweet Concatenation</h2>
<h2>Font Scaling</h2>
</div>
它基本上将字体大小减小到,然后开始递增 0.1,直到达到最大宽度。1em
对于动态文本,这个插件非常有用:
http://freqdec.github.io/slabText/
只需添加 CSS:
.slabtexted .slabtext
{
display: -moz-inline-box;
display: inline-block;
white-space: nowrap;
}
.slabtextinactive .slabtext
{
display: inline;
white-space: normal;
font-size: 1em !important;
letter-spacing: inherit !important;
word-spacing: inherit !important;
*letter-spacing: normal !important;
*word-spacing: normal !important;
}
.slabtextdone .slabtext
{
display: block;
}
还有脚本:
$('#mydiv').slabText();
为了使 font-size 适合其容器,而不是窗口,请参阅我在此问题中分享的功能(其他答案的组合,其中大部分已经链接在这里)。它是使用 触发的。resizeFont()
window.addEventListener('resize', resizeFont);
Vanilla JavaScript:调整 font-awesome 的大小以适合容器
JavaScript的:
function resizeFont() {
var elements = document.getElementsByClassName('resize');
console.log(elements);
if (elements.length < 0) {
return;
}
_len = elements.length;
for (_i = 0; _i < _len; _i++) {
var el = elements[_i];
el.style.fontSize = "100%";
for (var size = 100; el.scrollHeight > el.clientHeight; size -= 10) {
el.style.fontSize = size + '%';
}
}
}
您也许可以使用 vw/vh 作为后备,因此您可以使用 JavaScript 动态分配 or 单位,确保在禁用 JavaScript 时字体确实会缩放到窗口。em
rem
将该类应用于包含要缩放的文本的所有元素。.resize
在添加窗口调整大小事件侦听器之前触发该函数。然后,任何不适合其容器的文本都将在页面加载时以及调整其大小时缩小。
注意:默认值必须设置为 ,或 才能获得正确的结果。font-size
em
rem
%
这对我有用:
我尝试根据设置“font-size: 10px”获得的宽度/高度来估算字体大小。基本上,这个想法是“如果我有 20 像素宽度和 11 像素高度,并且'font-size: 10px',那么计算一个 50 像素宽度和 30 像素高度的容器的最大字体大小是多少?
答案是双比例系统:
{ 20:10=50:X, 11:10=30:Y } = { X= (10*50)/20, Y= (10*30)/11 }
现在 X 是与宽度匹配的字体大小,Y 是与高度匹配的字体大小;取最小值
function getMaxFontSizeApprox(el){
var fontSize = 10;
var p = el.parentNode;
var parent_h = p.offsetHeight ? p.offsetHeight : p.style.pixelHeight;
if(!parent_h)
parent_h = 0;
var parent_w = p.offsetHeight ? p.offsetWidth : p.style.pixelWidth;
if(!parent_w)
parent_w = 0;
el.style.fontSize = fontSize + "px";
var el_h = el.offsetHeight ? el.offsetHeight : el.style.pixelHeight;
if(!el_h)
el_h = 0;
var el_w = el.offsetHeight ? el.offsetWidth : el.style.pixelWidth;
if(!el_w)
el_w = 0;
// 0.5 is the error on the measure that JavaScript does
// if the real measure had been 12.49 px => JavaScript would have said 12px
// so we think about the worst case when could have, we add 0.5 to
// compensate the round error
var fs1 = (fontSize*(parent_w + 0.5))/(el_w + 0.5);
var fs2 = (fontSize*(parent_h) + 0.5)/(el_h + 0.5);
fontSize = Math.floor(Math.min(fs1,fs2));
el.style.fontSize = fontSize + "px";
return fontSize;
}
注意:函数的参数必须是 span 元素或小于其父元素的元素,否则如果子元素和父元素具有相同的宽度/高度函数将失败。
有一种方法可以在没有 JavaScript 的情况下做到这一点!
您可以使用内联 SVG 图像。如果 SVG 是内联的,则可以在 SVG 上使用 CSS。您必须记住,使用此方法意味着您的 SVG 图像将响应其容器大小。
尝试使用以下解决方案...
[HTML全文]
<div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360.96 358.98" >
<text>SAVE $500</text>
</svg>
</div>
CSS的
div {
width: 50%; /* Set your container width */
height: 50%; /* Set your container height */
}
svg {
width: 100%;
height: auto;
}
text {
transform: translate(40px, 202px);
font-size: 62px;
fill: #000;
}
示例:https://jsfiddle.net/k8L4xLLa/32/
想要更华丽的东西吗?
SVG 图像还允许您使用形状和垃圾做一些很酷的事情。看看这个可扩展文本的好用例......
https://jsfiddle.net/k8L4xLLa/14/
评论
我没有看到任何关于CSS flex属性的答案,但它也非常有用。
评论
直接媒体查询似乎是一种更简单、更易于理解的解决方案,可以根据可能是动态的容器大小调整字体大小。
下面将字体大小调整为容器的大小,无论容器是否缩放到视口的大小,或者它是否已达到其最大值。如果您有非 100% 宽的容器,则可以相应地进行调整。vw
.container {
width: 100%;
max-width: 600px;
}
.headline {
font-size: 20vw;
}
.subhead {
font-size: 5vw;
}
@media (min-width:600px) {
.headline {
font-size: 120px;
}
.subhead {
font-size: 32px;
}
}
使用 CSS 变量
还没有人提到CSS变量,这种方法最适合我,所以:
假设您的页面上有一列,其宽度为移动用户屏幕宽度的 100%,但像素为 800 像素,因此在桌面上,该列的两侧都有一些空间。把它放在页面的顶部:max-width
<script> document.documentElement.style.setProperty('--column-width', Math.min(window.innerWidth, 800)+'px'); </script>
现在,您可以使用该变量(而不是内置单元)来设置字体的大小。例如vw
p {
font-size: calc( var(--column-width) / 100 );
}
这不是一种纯粹的CSS方法,但它非常接近。
评论
但是,如果容器不是视口(正文)呢?
真正的答案在于 transform 属性允许您通过倾斜、旋转、平移或缩放来直观地操作元素:
https://css-tricks.com/almanac/properties/t/transform/
评论
let textElement = document.getElementById('text1');
let parentElement = textElement.parentElement;
const parentClientHeight = parentElement.clientHeight;
const parentClientWidth = parentElement.clientWidth;
textElement.style.padding = "unset";
textElement.style.margin = "auto";
let fontSize = parentClientHeight;
let minFS = 3,
maxFS = fontSize;
while (fontSize != minFS) {
textElement.style.fontSize = `${fontSize}px`;
if (
parentElement.scrollHeight <= parentClientHeight &&
parentElement.scrollWidth <= parentClientWidth
) {
minFS = fontSize;
} else {
maxFS = fontSize;
}
fontSize = Math.floor((minFS + maxFS) / 2);
}
textElement.style.fontSize = `${minFS}px`;
<div style="height:200px; width:300px;">
<div id='text1'>
test
</div>
</div>
从艺术上讲,如果您需要在相同的宽度内容纳两行或多行文本,而不管它们的字符数如何,那么您有不错的选择。
最好找到一个动态的解决方案,这样无论输入什么文本,我们最终都会得到一个漂亮的显示。
让我们看看我们该如何接近。
var els = document.querySelectorAll(".divtext"),
refWidth = els[0].clientWidth,
refFontSize = parseFloat(window.getComputedStyle(els[0],null)
.getPropertyValue("font-size"));
els.forEach((el,i) => el.style.fontSize = refFontSize * refWidth / els[i].clientWidth + "px")
#container {
display: inline-block;
background-color: black;
padding: 0.6vw 1.2vw;
}
.divtext {
display: table;
color: white;
font-family: impact;
font-size: 4.5vw;
}
<div id="container">
<div class="divtext">THIS IS JUST AN</div>
<div class="divtext">EXAMPLE</div>
<div class="divtext">TO SHOW YOU WHAT</div>
<div class="divtext">YOU WANT</div>
</div>
我们所做的就是获取第一行的宽度 () 和字体大小 () 作为参考,然后相应地计算后续行的字体大小。els[0].clientWidth
parseFloat(window.getComputedStyle(els[0],null).getPropertyValue("font-size"))
我刚刚创建了一个演示如何做到这一点。它用于通过一些监视元素调整大小的 JS 来实现这一点。很好地满足了我的需求。transform:scale()
在某种程度上,纯CSS是可能的。
.auto-sized-text {
content:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='1.3em' width='10em'><text x='0' y='0.9em' fill='red'>Here is a resizing text</text></svg>");
background-color: rgba(0,0,0,0.06);
animation: grow 2s infinite alternate both;
}
@keyframes grow {
from { width: 100px; }
to { width: 300px; }
}
<div class="auto-sized-text">
</div>
解释
content
规则设置元素的内容,它可以是图像的 URL,包括 SVG 图像。SVG 图像可以包含文本,因此基本上您有一个背景图像,其中包含根据其父级大小调整大小的文本。您也可以使用属性,但与此不同的是,它对元素的布局没有贡献,因此您需要定义父元素的大小。background-image
content
这种方法的问题是,您需要定义 SVG 中文本的颜色、大小和位置。它们不会从父母那里继承。但是你可以用 Sass 和 Less 变得聪明。此解决方案还可能存在辅助功能问题。
我不建议到处使用它。但在某些情况下,它应该相当有用。
这又如何呢?
将父级的字体大小设置为等于其宽度,然后对文本元素字体大小使用百分比。
.element {
width: 400px;
font-size: 400px; /* equal to width */
}
.text {
width: 10%; /* will be 40px */
}
我发现这真的很容易,特别是当你处理图标时,但也适用于文本。
/* start of styling */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.box {
display: block;
background: cornflowerblue;
height: max-content;
margin-bottom: 32px;
}
/* end of styling */
.box p {
font-size: 20%;
}
<div class="box" style="width: 400px; font-size: 400px">
<p>Text</p>
</div>
<div class="box" style="width: 128px; font-size: 128px">
<p>Text</p>
</div>
<div class="box" style="width: 10vw; font-size: 10vw">
<p>Text</p>
</div>
<div class="box" style="width: 64px; font-size: 64px">
<p>Text</p>
</div>
这是一个纯 CSS 解决方案,您承认断点是必要的,但也希望文本缩放:
我知道我可以添加断点,但我真的希望文本缩放 以及有额外的断点,否则......
下面是一种使用的方法:
- 自定义属性
- 断点的媒体查询
clamp()(
2022 年 2 月的浏览器支持率相当不错,达到 93%)calc()
如果可以使用一个通用的缩放因子来控制每个屏幕容器内的所有文本缩放,那么您需要做的就是按 缩放自定义属性,并将此因子应用于 1 个计算。max-width
max-width
基本设置是这样开始的:
:root {
--scaling-factor: 1
}
.parent {
font-size: 30px
}
.largest {
font-size: clamp(60%, calc(var(--scaling-factor) * 100%), 100%);
}
.middle {
font-size: clamp(60%, calc(var(--scaling-factor) * 85%), 100%);
}
.smallest {
font-size: clamp(60%, calc(var(--scaling-factor) * 70%), 100%);
}
然后嵌套你的媒体查询,像这样的东西(或你需要的断点的任何内容):
@media (max-width: 1200px) {
:root {
--scaling-factor: 0.9
}
@media (max-width: 800px) {
:root {
--scaling-factor: 0.8
}
@media (max-width: 600px) {
:root {
--scaling-factor: 0.5 /* nope, because the font-size is floored at 60% thanks to clamp() */
}
}
}
}
这样可以最大程度地减少媒体查询标记。
优势
- 一个自定义属性控制所有缩放...无需为每个媒体断点添加多个声明
- 使用 of 设置了应该是什么的下限,因此您可以确保文本永远不会太小(此处的下限是父级的 60%
clamp()
font-size
font-size
)
请参阅此 JSFiddle 的演示。调整窗口大小,直到以最小的宽度,段落都相同。font-size
如果要将其放入特定容器(如 div)中,请使用:
width: max-content;
调整也有很大帮助,例如.font-size
font-size: 75%
您可以插入窗口宽度的字体大小:
font-size: calc(
${minFontSizeInPixel} *
(
1px -
clamp(
0px,
(100vw - ${minWindowWidth}px) /
(${maxWindowWidth} - ${minWindowWidth}),
1px
)
) + ${maxFontSizeInPixel} *
clamp(
0px,
(100vw - ${minWindowWidth}px) /
(${maxWindowWidth} - ${minWindowWidth}),
1px
)
);
我想喜欢公认的答案,但从根本上说,符合我标准的答案都使用了库。我没有熟悉另一个库,然后弄清楚如何使用它并准备调试它,如果它不起作用,我决定编写一个对我来说非常有效的简单函数。
理论:
- 传入需要适合的字符串
- 传入要从中继承文本样式的父级
- (可选)传入自定义属性(例如,您将从中继承字体和其他属性的类/ID,或者仅传递自定义内联样式)
- 函数将在屏幕外创建一个文本元素,其中包含该文本、该父项和这些属性,字体大小为 1px,并对其进行测量
- 然后,在一个循环中,它将逐个像素地增加字体大小,直到超过宽度限制;一旦完成此操作,它将返回最后一个适合的
- 然后,它删除测试元素
- 当然,这一切都发生在眨眼之间
局限性:
- 我不在乎动态调整屏幕大小,因为这与我的上下文无关。在生成文本时,我只关心运行时的屏幕大小。
- 我依赖于一个小的辅助函数,我也在代码的其他地方使用,它基本上作为 mithril.js 的单函数版本存在;老实说,我几乎在每个项目中都使用这个小函数,它本身就值得学习。
function findMaxFontSize(
string="a string",
parent=document.body,
attributes={id:'font-size-finder',class:'some-class-with-font'}
) {
// by using parent, we can infer the same font inheritance;
// you can also manually specify fonts or relevant classes/id with attributes if preferred/needed
attributes.style = 'position:absolute; left:-10000; font-size:1px;' + (attributes.style || "");
let testFontEl = createEl('p', attributes, string);
parent.appendChild(testFontEl);
let currentWidth = testFontEl.offsetWidth;
let workingFontSize = 1;
let i = 0;
while (currentWidth < maxWidth && i < 1000) {
testFontEl.style.fontSize = Number(testFontEl.style.fontSize.split("px")[0]) + 1 + "px";
currentWidth = testFontEl.offsetWidth;
if (currentWidth < maxWidth) {
workingFontSize = testFontEl.style.fontSize;
}
i++; // safety to prevent infinite loops
}
console.log("determined maximum font size:",workingFontSize,'one larger would produce',currentWidth,'max width allowed is',maxWidth,'parent is',parent);
parent.removeChild(testFontEl);
return workingFontSize.split("px")[0];
}
// utility function, though you could easily modify the function above to work without this.
// normally these have no default values specified, but adding them here
// to make usage clearer.
function createEl(tag="div", attrs={class:'some-class'}, children=[]) {
let el = document.createElement(tag);
if (attrs) {
Object.keys(attrs).forEach(attr => {
el.setAttribute(attr, attrs[attr])
})
}
if (children) {
children = Array.isArray(children) ? children : [children];
for (let child of children) {
if (typeof child === "number") child = ""+child;
if (typeof child === "string") {
el.insertAdjacentText("afterbegin", child);
}
else {
try {
el.appendChild(child)
} catch (e) {
debugger
}
}
}
}
return el;
};
用:
const getUsername = () => "MrHarry";
const username = getUsername();
const anchor = document.querySelector('.container');
const titleFontSize = findMaxFontSize(`Welcome, ${username}`, anchor, {style:'font-weight:900;'});
const titleFontStyle = `font-size:${titleFontSize}px;`;
CSS 容器查询
2022 年末对 CSS 功能集的添加使使用容器缩放字体大小变得简单明了。
容器查询带有一组新的 CSS 单元 / (container query width/height)。要使用它们,您需要在要使用其大小的父元素上设置属性(不必是直接父元素)。最小示例:cqw
cqh
container-type
<div>
<p>Lorem ipsum dolor sit amet</p>
</div>
<style>
div {
container-type: inline-size;
}
p {
font-size: 5cqw;
}
</style>
字体大小将随着容器的增长而平滑增加。在 1000px 容器宽度时,字体大小将为 .p
1000px / 100 * 5 = 50px
container-type
可以是 或 . 跟踪容器的高度和宽度,允许您同时使用 和 。
在网络上,大多数时候,高度是根据内容计算的,您只需指定宽度。为了节省浏览器的一些工作,您通常希望设置浏览器仅跟踪内联尺寸,该尺寸通常是宽度(除非您将书写模式
设置为垂直)。size
inline-size
size
cqw
cqh
container-type: inline-size;
浏览器对容器查询的支持正在迅速增长:
- 2023-01-01: 75%
- 2023-04-03: 83%
- 2023-11-24: 90%
评论