make-text-fit-it-s-parent-size-using-javascript-m40

原始地址:https://dev.to/jankapunkt/make-text-fit-it-s-parent-size-using-javascript-m40

‘’'*封面图片:
Amador Loureiro on Unsplash
将文本大小自动调整到其父容器的大小可能非常困难,如果您只想使用CSS,几乎是不可能的。
要了解这个问题的"流行程度",只需看看这些StackOverflow问题,请求几乎相同的结果:
https://stackoverflow.com/questions/4165836/javascript-scale-text-to-fit-in-fixed-div https://stackoverflow.com/questions/16056591/font-scaling-based-on-width-of-container https://stackoverflow.com/questions/14431411/pure-css-to-make-font-size-responsive-based-on-dynamic-amount-of-characters https://stackoverflow.com/questions/17001302/dynamically-resize-font-size-to-fit-container-size



有用于自动调整文本大小的工具
幸运的是,已经有一些资源和工具可以帮助您做这件繁重的工作:
https://css-tricks.com/fitting-text-to-a-container/ https://github.com/davatron5000/FitText.js https://github.com/STRML/textFit https://github.com/rikschennink/fitty https://github.com/jquery-textfill/jquery-textfill.github.io https://github.com/simplefocus/FlowType.JS
然而,这里的问题是:我尝试过其中几个,但没有一个能够完美地集成到我的代码中,至少没有太大的额外开销。因此,我觉得不如自己解决这个问题来节省时间和麻烦。
结果证明比我想象的要容易。



让我们自己试试
我遇到了四个使用案例,我想为每个案例展示一个潜在的实现以及额外的解释。
如果您感到不知所措,或者发现我使用的快捷方式没有解释得足够清楚,请在评论中留言,以便改进。最好同时打开像jsFiddle或CodePen这样的在线编辑器,以便可以交互式地跟踪这些步骤。
我要涵盖的使用案例是:
具有固定高度和固定宽度的容器 具有固定宽度和自动高度的容器 具有自动宽度和固定高度的容器 用户可以调整大小的容器
以下各节将使用相同的简单HTML示例来展示所有使用案例,这些示例主要通过不同的CSS来区别。


  1. 具有固定高度和固定宽度的容器
    对于这种情况,我们只需要检查文本包装元素(一个
    )是否在高度上溢出,如果没有溢出,则增加字体大小1像素。
    考虑以下两个面板:
This Text is a bit longer and should be wrapped correctly
This text
考虑以下CSS样式: .parent { margin: 2%; width: 300px; height: 50px; padding: 15px; background: grey; color: white; display: block; } .text-container { width: 100%; height: 100%; } .text { font-size: 12px; display: block; } 面板中的默认大小文本当前如下所示: 我们可以利用文本相对于其容器(具有 text-container 类的div)的"溢出"。让我们稍微更改CSS(以获得更好的可视化效果): .text-container { border: 1px solid; width: 100%; height: 100%; } .text { font-size: 32px; display: block; } body { background: #33A; } 现在,文本明显溢出了其容器: ### [ ](https://dev.to#calculate-the-overflow) 计算溢出情况 如果我们可以计算DOM元素的溢出量,我们可以进一步利用这一点: const isOverflown = ({ clientHeight, scrollHeight }) => scrollHeight > clientHeight 利用这种情况,我们可以为文本调整大小功能定制算法逻辑: 我们可以"尝试"逐步增加字体大小1像素,并再次测试元素是否溢出其父级容器。 如果元素溢出,则我们知道上一步(少1个像素)不会溢出,并且是最合适的字体大小。 ### [ ](https://dev.to#a-first-implementation) 第一个实现 上述描述的逻辑暗示了一个函数,该函数接收一个元素和其父级元素,并从最小值(12,对应于12px)迭代到最大值(比如128),并将 style.fontSize 属性设置为当前迭代索引,直到发生溢出。然后重新赋值为最后一次迭代的索引。 一个简单的实现可能是这样的: const resizeText = ({ element, parent }) => { let i = 12 // 让我们从12px开始 let overflow = false const maxSize = 128 // 非常巨大的文本大小 while (!overflow && i < maxSize) { element.style.fontSize = `${i}px` overflow = isOverflown(parent) if (!overflow) i++ } // 回滚到没有溢出的最后状态: element.style.fontSize = `${i - 1}px` } 对于第一个 文本元素及其父元素调用此函数会产生一个不错的结果: resizeText({ element: document.querySelector('.text'), parent: document.querySelector('.text-container') }) ### [ ](https://dev.to#add-more-options) 添加更多选项 当然,我们希望更加灵活,因此使函数更具配置性: - 允许只添加一个querySelector或querySelectorAll,并自动解析父元素 - 允许传递自定义的最小和最大值 - 允许使用不同于1的步长(为了更精确的拟合,可以使用浮点值) - 允许使用不同于px 的单位 最终的代码可能如下所示: const isOverflown = ({ clientHeight, scrollHeight }) => scrollHeight > clientHeight const resizeText = ({ element, elements, minSize = 10, maxSize = 512, step = 1, unit = 'px' }) => { (elements || [element]).forEach(el => { let i = minSize let overflow = false const parent = el.parentNode while (!overflow && i < maxSize) { el.style.fontSize = `${i}${unit}` overflow = isOverflown(parent) if (!overflow) i += step } // 回滚到没有溢出的最后状态 el.style.fontSize = `${i - step}${unit}` }) } 让我们对所有的 .text 元素调用它,并使用 0.5 的步长以增加精确度: resizeText({ elements: document.querySelectorAll('.text'), step: 0.5 }) 最终,它适用于两个元素: ## [ ](https://dev.to#2-container-with-fixed-width-and-auto-height) 2. 具有固定宽度和自动高度的容器 但是,HTML保持相同,CSS略有不同: body { background: #A33; } .parent { margin: 2%; width: 150px; height: auto; min-height: 50px; padding: 15px; background: grey; color: white; display: block; } .text-container { width: 100%; height: 100%; border: 1px solid; } .text { font-size: 12px; display: block; } 这些容器具有固定的宽度,最小高度,但是如果内容溢出,可以动态增长(height: auto)。尚未调整的文本如下所示: 让我们看看如果我们手动增加字体大小会出现什么情况: .text { font-size: 48px; display: block; } ### [ ](https://dev.to#add-horizontal-overflow-checks) 添加水平溢出检查 高度"增长"了,但宽度现在溢出。 幸运的是,我们可以只对我们先前的代码进行轻微修改就可以了。它目前只检查垂直溢出(使用高度值),我们只需要添加对水平溢出的检查: const isOverflown = ({ clientWidth, clientHeight, scrollWidth, scrollHeight }) => (scrollWidth > clientWidth) || (scrollHeight > clientHeight) 就是这样。结果现在看起来也很好: resizeText({ elements: document.querySelectorAll('.text'), step: 0.25 }) ## [ ](https://dev.to#3-container-with-fixed-height-and-auto-width) 3. 具有固定高度和自动宽度的容器 对于这种情况,我们只需要更改CSS,函数已经可以正常工作了。 默认情况如下所示: body { background: #3A3; } .parent { margin: 2%; width: auto; min-width: 50px; height: 50px; min-height: 50px; padding: 15px; background: grey; color: white; display: inline-block; } .text-container { width: 100%; height: 100%; border: 1px solid; } .text { font-size: 12px; display: block; } 手动更改字体大小的结果如下: .text { font-size: 48px; display: block; } 使用我们的函数,我们终于得到了正确的结果: resizeText({ elements: document.querySelectorAll('.text'), step: 0.25 }) 这里不需要额外的代码。🎉 ## [ ](https://dev.to#4-container-that-can-be-resized-by-users) 4. 用户可以调整大小的容器 这是最棘手的部分,但由于CSS3和新的Web标准,我们只需添加几行额外的代码即可解决。考虑以下CSS: body { background: #333; } .parent { margin: 2%; width: 150px; height: 150px; padding: 15px; background: grey; color: white; overflow: auto; resize: both; } .text-container { width: 100%; height: 100%; border: 1px solid; display: block; } .text { font-size: 12px; display: block; } resize 属性允许我们调整最上层父容器的大小: 调整大小功能在(大多数)现代浏览器中都有原生实现,并且还显示在容器的右下角。 现在,用户可以自由调整容器的大小,因此,我们的逻辑稍微有所改变: - 观察容器的变化,由调整大小事件引起 - 如果发生了变化,调用一个函数,调整文本大小 - 可选地使用限流机制来减少每秒调整大小的次数 ### [ ](https://dev.to#observe-changes-using-raw-mutationobserver-endraw-) 使用 MutationObserver 观察变化 对于观察部分,我们使用本地的 [Mutation Observer实现](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver),所有现代浏览器都支持该实现。 然而,我们不能观察到 .text 的变化,只能观察到最外层的容器,也就是我们的例子中的 .parent。此外,MutationObserver需要一个要观察的单个节点,因此我们需要遍历所有的 .parent 容器以支持多个元素: const allParents = document.querySelectorAll('.parent') allParents.forEach(parent => { // 为每个父容器创建一个新的观察器 const observer = new MutationObserver(function (mutationList, observer) { mutationList.forEach( (mutation) => { // 获取文本元素,请参考顶部的HTML代码 const parent = mutation.target const textContainer = parent.firstElementChild const text = textContainer.firstElementChild // 调整文本大小 resizeText({ element: text, step: 0.5 }) }); }) // 仅观察我们所需的属性 observer.observe(parent, { attributeFilter: ['style'] }) }) 大多数时间都表现得非常好: 注意!调整大小时仍然存在一些小问题: 通过应用不同的 overflow CSS 属性,我们实际上可以解决99.9%的问题: .parent { margin: 2%; width: 150px; height: 150px; padding: 15px; background: grey; color: white; overflow-x: auto; overflow-y: hidden; resize: both; } 如果有人知道更好的方法以完全消除这些小问题,请留言 :-) ### [ ](https://dev.to#optional-add-throttling) 可选:添加节流功能 为了减少调用 resizeText 方法的次数,我们可以添加一个 [节流功能](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_throttle): const throttle = (func, timeFrame) => { let lastTime = 0 return (...args) => { const now = new Date() if (now - lastTime >= timeFrame) { func(...args) lastTime = now } } } const throttledResize = throttle(resizeText, 25) 在observer中使用它而不是 resizetText: // ... const parent = mutation.target const textContainer = parent.firstElementChild const text = textContainer.firstElementChild throttledResize({ element: text, step: 0.5 }) // ... ## [ ](https://dev.to#summary) 总结 我总结了我在动态调整文本大小方面的第一次经验,希望能帮助人们了解该主题并了解机制,以便评估现有的库。 这绝对不是一个足够通用的方法,以成为一种一刀切的解决方案。然而,本文表明,即使没有第三方代码的情况下,现代浏览器已经提供了足够的功能,可以使用约50行代码来构建您自己的调整大小工具。 非常欢迎提出改进的建议,我希望读者从这篇文章中获得一些东西。 ## [ ](https://dev.to#resources-used-by-the-author-for-this-article) 作者在本文中使用的资源 [https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes](https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes) [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) [https://developer.mozilla.org/en-US/docs/Web/CSS/resize](https://developer.mozilla.org/en-US/docs/Web/CSS/resize) [https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) [https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_throttle](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_throttle) [https://stackoverflow.com/questions/5712596/how-can-i-let-a-div-automatically-set-it-own-width](https://stackoverflow.com/questions/5712596/how-can-i-let-a-div-automatically-set-it-own-width) 我定期在dev.to上发布关于 **Meteor**和**JavaScript**的文章。如果您喜欢您正在阅读的内容并希望支持我,您可以[通过PayPal给我打赏](https://paypal.me/kuesterjan)。 您也可以在 [GitHub](https://github.com/jankapunkt/)上找到我(并与我联系)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值