Font scaling based on width of container
我很难理解字体缩放。
我目前这个网站的主体
我的印象是,100%会以某种方式引用浏览器窗口的大小,但显然不是因为它总是16像素,无论窗口是否调整为移动宽度或完整的宽屏桌面。
如何使我的网站上的文本与其容器相关?我尝试使用
我的理由是,当你调整大小时,我的菜单之类的东西会变得模糊,所以我需要减少与容器宽度相关的其他元素中的
我知道我可以添加断点,但我真的希望文本可以扩展以及有额外的断点,否则我最终会为每100个像素的宽度减少数百个断点来控制文本。
编辑:如果容器不是主体CSS Tricks涵盖了将文本拟合到容器中的所有选项。
如果容器是正文,那么您要查找的是视口百分比长度:
The viewport-percentage lengths are relative to the size of the initial containing block. When the height or width of the initial containing block is changed, they are scaled accordingly. However, when the value of overflow on the root element is auto, any scroll bars are assumed not to exist.
价值观是:
-
vw (视口宽度的百分比) -
vh (视口高度的百分比) -
vi (在根元素的内联轴方向上视口大小的1%) -
vb (根元素块轴方向视口大小的1%) -
vmin (vw 或vh 中的较小者) -
vmax (较大或vw 或vh )
1 v *等于初始包含块的1%。
使用它看起来像这样:
1 2 3 | p { font-size: 4vw; } |
如您所见,当视口宽度增加时,font-size也会增加,而无需使用媒体查询。
这些值是一个大小单位,就像
浏览器支持非常好,但您可能需要回退,例如:
1 2 3 4 | p { font-size: 16px; font-size: 4vw; } |
查看支持统计信息:http://caniuse.com/#feat=viewport-units。
另外,请查看CSS-Tricks以获得更广泛的外观:Viewport Sized Typography
这是一篇很好的文章,关于设置最小/最大尺寸并对尺寸进行更多控制:精确控制响应式排版
这里有一篇关于使用calc()设置大小的文章,以便文本填充视口:http://codepen.io/CrocoDillon/pen/fBJxu
另外,请查看这篇文章,该文章使用了一种名为"熔化前导"的技术来调整线高。在CSS中熔化领先
但是如果容器不是视口(正文)怎么办?
Alex根据接受的答案在评论中提出了这个问题。
这个事实并不意味着
例1
然而,对于柔性宽度的容器,必须认识到,在某种程度上,容器仍然在视口外的尺寸。因此,需要根据与视口的百分比大小差异来调整
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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; } |
假设
例2
您可以通过强制执行基于此计算的计算来帮助确保视口大小调整。考虑这个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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; } |
大小调整仍然基于视口,但实质上是根据容器大小本身设置的。
应该动态调整集装箱的大小......
如果容器元素的大小最终通过
以上面的例子#1为例。如果
一个挑战
使用CSS3
SVG解决方案:
1 2 3 4 | <svg width="100%" height="100%" viewBox="0 -200 1000 300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <text font-size="300" fill="black">Text</text> </svg> |
https://jsfiddle.net/qc8ht5eb/
使用
1 2 3 4 5 6 7 | <svg viewBox="0 0 100 100"> <foreignObject width="100%" height="100%"> heading lorem ipsum dolor sit amet </foreignObject> </svg> |
https://jsfiddle.net/2rp1q0sy/
在我的一个项目中,我使用vw和vh之间的"混合"来根据我的需要调整字体大小,例如:
1 | font-size: calc(3vw + 3vh); |
我知道这不能回答OP的问题,但也许它可以成为其他任何人的解决方案。
这个问题有一个很大的哲学。
最简单的做法是给身体一个字体大小(我推荐10),然后所有其他元素的字体都在
我会举个例子来了解这些单位。
1 2 3 | 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 */ |
1 2 3 | 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像素字体大小的
其他解决方案将使用媒体查询,以便您可以设置不同宽度的字体。
但我建议的解决方案是使用一个可以帮助你的JavaScript库。到目前为止我发现的fittext.js。
这是功能:
1 2 3 4 5 | document.body.setScaledFont = function(f) { var s = this.offsetWidth, fs = s * f; this.style.fontSize = fs + '%'; return this }; |
然后将所有文档子元素字体大小转换为
然后在代码中添加类似的内容以设置基本字体大小。
1 2 3 4 | document.body.setScaledFont(0.35); window.onresize = function() { document.body.setScaledFont(0.35); } |
http://jsfiddle.net/0tpvccjt/
带有
这正是OP所要求的,但可能会成为某人的一天。这个答案并非易于使用,需要对开发人员进行一些研究。
我最终使用不同单位的
当我解决这个问题时,我不得不得到一个整页宽度响应的标题,其中一些填充在DOM中的父母很少。我会在这里使用我的值,用你自己的值替换它们。
对数学
你会需要:
- 在某些视口中调整好的比例。我使用320像素,因此我得到24像素高和224像素宽,因此比率为9.333 ...或28/3
-
容器宽度,我有
padding: 3em 和全宽,所以这到100wv - 2 * 3em
X是容器的宽度,因此请将其替换为您自己的表达式,或者调整该值以获取整页文本。
1 2 3 4 5 6 7 8 | 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 |
砰!有效!我写
1 | font-size: calc((75vw - 4.5rem) / 7) |
到我的标题,它在每个视口中调整得很好。
但它是如何工作的?
我们需要一些常量。
比例。在一个视口中获得宽度和高度让我得到一个比率,并且我知道在其他视口宽度中的高度应该是多少。用手计算它们需要花费大量时间,至少需要大量带宽,所以这不是一个好的答案。
结论
我想知道为什么没有人想到这一点,有些人甚至说这不可能修补CSS。我不喜欢在调整元素时使用JavaScript,所以我不接受JavaScript甚至jQuery的答案而不需要更多。总而言之,这一点很好,这是网站设计中纯CSS实现的一步。
我为我的文本中的任何不寻常的约定道歉,我不是英语母语,也是编写StackOverflow答案的新手。
还应该注意的是,在某些浏览器中我们有邪恶的滚动条。例如,当使用Firefox时,我注意到
没有JavaScript,有一种方法可以做到这一点!
您可以使用内联SVG图像。如果SVG是内联的,您可以在SVG上使用CSS。您必须记住,使用此方法意味着您的SVG图像将响应其容器大小。
尝试使用以下解决方案......
HTML
1 2 3 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360.96 358.98"> <text>SAVE $500</text> </svg> |
CSS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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/
这可能不太实用,但是如果你想让一个字体成为父类的直接函数,而没有任何监听/循环(间隔)的JavaScript来读取div / page的大小,那么有一种方法可以做到这一点。 。 I帧。
iframe中的任何内容都会将iframe的大小视为视口的大小。因此,诀窍是只创建一个iframe,其宽度是您希望文本的最大宽度,其高度等于特定文本的纵横比的最大高度*。
抛开视口单元不能同时出现文本的旁边父单元的限制(如同,%大小的行为与其他人一样),视口单元确实提供了一个非常强大的工具:能够获得最小/最大尺寸。你不能在其他地方做到这一点 - 你不能说......让这个div的高度成为父*的宽度。
话虽这么说,诀窍是使用vmin,并设置iframe大小,以便当高度是限制尺寸时,[fraction] *总高度是一个好的字体大小,当宽度是时,[fraction] *总宽度限制尺寸。这就是为什么高度必须是宽度和纵横比的乘积。
对于我的具体例子,你有
1 2 3 4 5 6 7 8 9 10 | .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附加我想要的规则。
1 2 3 | 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都只是我的自定义点击拖动功能。
使用
这是我刚刚根据@ tnt-rox'回答写的一个脚本,试图自动化人类的触摸:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | $('#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) |
1 2 3 4 5 6 7 8 9 10 11 12 13 | div { width: 50%; background-color: tomato; font-family: 'Arial'; } h2 { white-space: nowrap; } h2:nth-child(2) { font-style: italic; } |
1 2 3 4 5 6 7 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"> <input type="button" id="controller" value="Apply" /> Lorem ipsum dolor Test String Sweet Concatenation Font Scaling |
它基本上将字体大小减小到
的jsfiddle
我自己的解决方案,基于jQuery,通过逐渐增加字体大小,直到容器的高度大幅增加(意味着它有一个换行符)。
它非常简单,但效果相当好,而且非常易于使用。您不必了解正在使用的字体,浏览器会处理所有内容。
你可以在http://jsfiddle.net/tubededentifrice/u5y15d0L/2/上玩它
魔术发生在这里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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; }; |
你可能在寻找这样的东西:
http://jsfiddle.net/sijav/dGsC9/4/
http://fiddle.jshell.net/sijav/dGsC9/4/show/
我使用了flowtype,它工作得很好(但它是JavaScript而不是纯CSS解决方案):
1 2 3 4 5 6 7 | $('body').flowtype({ minFont: 10, maxFont: 40, minimum: 500, maximum: 1200, fontRatio: 70 }); |
此Web组件更改字体大小,以使内部文本宽度与容器宽度匹配。检查演示。
你可以像这样使用它:
1 | <full-width-text>Lorem Ipsum</full-width-text> |
试试http://simplefocus.com/flowtype/。这是我用于我的网站,它完美地工作。
在CSS内部,尝试在底部添加此项,在设计开始破坏的任何地方更改320像素宽度:
1 2 3 4 5 | @media only screen and (max-width: 320px) { body { font-size: 1em; } } |
然后根据需要在"px"或"em"中给出font-size。
100%是相对于基本字体大小的,如果您尚未设置,则将是浏览器的用户代理默认值。
为了获得你想要的效果,我将使用一段JavaScript代码来调整相对于窗口尺寸的基本字体大小。
我已经使用CSS变换而不是font-size准备了一个简单的缩放函数。您可以在任何容器内使用它,您不必设置媒体查询等。:)
博客文章:
全宽CSS和JS可扩展标头
代码:
1 2 3 4 5 6 7 8 9 10 11 12 | 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
我的问题很相似,但与标题中的缩放文本有关。我试过Fit Font,但是我需要切换压缩器以获得任何结果,因为它解决了一个稍微不同的问题,就像Text Flow一样。
所以我编写了自己的小插件,减小了字体大小以适应容器,假设你有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | (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); |
使用CSS变量
还没有人提到CSS变量,这种方法对我来说效果最好,所以:
假设您的页面上有一列是移动用户屏幕宽度的100%,但是
1 | document.documentElement.style.setProperty('--column-width', Math.min(window.innerWidth, 800)+'px'); |
现在您可以使用该变量(而不是内置的
1 2 3 | p { font-size: calc( var(--column-width) / 100 ); } |
它不是纯粹的CSS方法,但它非常接近。
尝试使用fitText插件,因为Viewport大小不是此问题的解决方案。
只需添加库:
1 | <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"> |
并通过设置文本系数来更改font-size以获得正确:
1 | $("#text_div").fitText(0.8); |
您可以设置文本的最大值和最小值:
1 | $("#text_div").fitText(0.8, { minFontSize: '12px', maxFontSize: '36px' }); |
看看我的代码。它使
但我认为这不会带来良好的用户体验
1 2 3 4 5 6 7 8 9 10 11 12 | 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); } }); |
这对我有用:
我尝试根据设置`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是一个匹配高度的字体大小;取最小的价值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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元素或小于其父元素的元素,否则如果children和parent具有相同的width / height函数将失败。
始终拥有包含此属性的元素:
JavaScript:
要么
CSS:
当您全屏显示时,您应该已经计算了比例变量(比例> 1或比例= 1)。然后,全屏:
1 | document.body.style.fontSize = (scale * 100) +"%"; |
它与很少的代码很好地协作。
对于动态文本,此插件非常有用:
http://freqdec.github.io/slabText/
只需添加CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | .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; } |
和剧本:
1 | $('#mydiv').slabText(); |
如果它对任何人都有帮助,那么这个主题中的大多数解决方案都是将文本包装成多行,形式为e。
但后来我发现了这个,它起作用了:
https://github.com/chunksnbits/jquery-quickfit
用法示例:
作为JavaScript后备(或您唯一的解决方案),您可以使用我的jQuery Scalem插件,它允许您通过传递
HTML
1 | test |
用于最大化字体大小的JavaScript代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | el = document.getElementById('qwe'); maxFontPixels = 50; maxHeight = el.parentElement.offsetHeight; fontSize = Number(maxFontPixels || maxHeight); el.style.width = '100%'; el.style.overflowWrap = 'break-word'; var minFS = 3, maxFS = fontSize; while (fontSize != minFS) { el.style.fontSize = `${fontSize}px`; if (el.offsetHeight < maxHeight) { minFS = fontSize; } else { maxFS = fontSize; } fontSize = Math.floor((minFS + maxFS)/2); } el.style.fontSize = `${minFS}px`; |
我没有看到任何关于CSS flex属性的答案,但它也非常有用。
为了使font-size适合它的容器而不是窗口,请参阅我在这个问题中共享的
Vanilla JavaScript:调整字体大小以适应容器
JavaScript的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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动态分配
将
在添加window resize事件侦听器之前触发该函数。然后,任何不适合其容器的文本将在页面加载时以及调整大小时缩小。
注意:默认
直接的媒体查询似乎是一个更简单,更容易理解的解决方案,根据可能是动态的容器大小调整字体大小。
下面将字体大小调整为容器的大小,无论容器是否缩放到视口的大小,或者是否达到其最大值。如果您有非100%宽的容器,则可以相应地调整
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | .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方法就是这样(假设包装最大宽度为1000像素)
1 2 3 4 5 6 7 8 9 | .specialText{ font-size: 2.4vw; } @media only screen and (min-width: 1000px) { .specialText { width: 24px; } } |
因此,对于小于容器最大宽度的任何屏幕,它都是自动调整大小的,并且当屏幕较宽时(例如几乎所有台式机和笔记本电脑)都固定大小。
但是如果容器不是视口(正文)怎么办?
真正的答案是在transform属性中允许您通过倾斜,旋转,平移或缩放来可视地操作元素: