如何实现基于容器高度的响应式自动适配字体大小?
问题描述
由于CSS没有自动调整字体大小的功能,我尝试编写代码实现以下逻辑:当容器内元素溢出容器高度时,每次迭代将字体大小减小1px,直到内容不再溢出。
原代码如下:
JavaScript
document.addEventListener( 'DOMContentLoaded', function() { jQuery ( function($) { function GetResponsiveValue() { return parseFloat($('body').css('--responsive-value')); } function SetResponsiveZoomValue(value) { $('body').css('--responsive-value', value + 'px'); // 这里不知道为什么不生效,理论上应该可以... } $('.responsive-container').each( function(i, value) { var timeout = 0; while (value.offsetHeight < value.scrollHeight && timeout <= 100) { var currentResponsiveValue = GetResponsiveValue(); SetResponsiveZoomValue(currentResponsiveValue - 1); timeout++; } // 实际字体大小要等迭代完成后才变化,而不是每次迭代过程中更新 } ); } ); } );
CSS
body { --responsive-value: 10px; } .responsive-container { height: 100px; width: 300px; background-color: yellow; } .txt-1 { display: block; font-size: calc(20px + var(--responsive-value)); } .txt-2 { display: block; font-size: calc(30px + var(--responsive-value)); }
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script> <body> <div class="responsive-container"> <span class="txt-1"> Text size calc(20px + var(--responsive-value)) </span> <span class="txt-2"> Text size calc(30px + var(--responsive-value)) </span> </div> </body>
遇到的问题
实际字体大小会在迭代完成后才发生变化,无法在每次迭代过程中更新并检查容器是否还溢出。
问题原因
浏览器的重排/重绘操作是异步执行的。在同步的while循环中,即使修改了CSS变量,浏览器也不会立刻更新元素的尺寸(offsetHeight和scrollHeight),而是会等到当前同步代码块执行完毕后,才一次性完成渲染更新。这就导致循环中每次检查的都是初始尺寸,无法触发实时调整。
解决方案
改用异步方式执行每一步调整,让浏览器有时间完成渲染更新后再进行下一次检查。可以使用requestAnimationFrame(和浏览器渲染周期同步,推荐)来实现递归式的迭代。
修正后的代码如下:
修正后的JavaScript
document.addEventListener('DOMContentLoaded', function() { jQuery(function($) { function GetResponsiveValue() { return parseFloat($('body').css('--responsive-value')); } function SetResponsiveZoomValue(value) { $('body').css('--responsive-value', value + 'px'); } $('.responsive-container').each(function(i, container) { function adjustFontSize(timeout) { // 超过最大次数就停止 if (timeout > 100) return; // 检查是否溢出 if (container.offsetHeight < container.scrollHeight) { var currentValue = GetResponsiveValue(); SetResponsiveZoomValue(currentValue - 1); // 等待浏览器渲染更新后,再执行下一次调整 requestAnimationFrame(function() { adjustFontSize(timeout + 1); }); } } // 启动调整流程 adjustFontSize(0); }); }); });
修正逻辑说明
- 把原来的同步
while循环改成递归函数adjustFontSize,每次调整后通过requestAnimationFrame触发下一次检查。 requestAnimationFrame会在浏览器下一次重绘前执行回调,确保修改CSS变量后,元素尺寸已经更新,此时再检查溢出状态才是准确的。- 保留了最大迭代次数(100次)的限制,避免无限递归。
内容的提问来源于stack exchange,提问作者user3014233
相关产品推荐
相关产品推荐

