<p>我正在开发一个带有图标和文本的按钮组件。</p>
<p>图标位于按钮的左侧,文本在按钮中间对齐。</p>
<p>如果文本无法适应按钮,它不应该换行,而是可以被截断。</p>
<p>截断文本的关键条件是,文本距离按钮边缘的距离应与图标距离按钮边缘的距离相同。</p>
<p>所以你不能在按钮中添加相等的内联填充。</p>
<p>如果文本没有被截断,它将在按钮中间对齐。</p>
<p>然而,一旦它开始重叠图标或无法适应按钮,文本将被截断。</p>
<p>换句话说,在正常状态下,图标的位置不变,但当文本没有足够的空间时,图标会将文本推到被截断的位置。</p>
<p>按钮的可视化示例</p>
<p>我尝试使用CSS来实现这个效果,但失败了。</p>
<p>最后,我为每个按钮添加了一个ResizeObserver,用于计算文本是否有足够的空间。</p>
<p>如果没有足够的空间,将应用不同的样式到图标上。</p>
<p>我的ResizeObserver解决方案,请尝试调整窗口大小</p>
<p>CodePen</p>
<pre class="brush:php;toolbar:false;">const CLASS_TEXT = `button__text`;
const CLASS_NO_FREE_SPACE = `button_no-free-space`;
const FREE_SPACE_SIZE = 70;
const buttons = document.querySelectorAll(`.${CLASS_ROOT}`);
const handleButtonResize = (entries) => {
entries.forEach((entry) => {
const { target } = entry;
const text = target.querySelector(`.${CLASS_TEXT}`);
const { width: widthButton } = entry.contentRect;
if (!(text instanceof HTMLElement)) {
return;
}
const widthText = text.offsetWidth;
const freeSpaceLeft = (widthButton - widthText) / 2;
const noFreeSpace = freeSpaceLeft <= FREE_SPACE_SIZE;
target.classList.toggle(CLASS_NO_FREE_SPACE, noFreeSpace);
});
};
const resizeObserver = new ResizeObserver(handleButtonResize);
[...buttons].forEach((button) => {
resizeObserver.observe(button);
});</pre>
<p><strong>我的问题是:</strong></p>
<p>是否可以使用纯CSS实现相同的效果?</p>
由于图标的宽度始终相同(
2em),我们可以使用::after伪元素作为右侧空间平衡的“缓冲区”。将
.button__icon设置为弹性布局流。这在“推动”其他元素时至关重要。给它margin-right来平衡按钮的左填充。创建一个具有
flex-basis: calc(2em + 20px)的::after伪元素。其中2em是.button__icon的宽度,20px是.button__icon的margin-right。这样可以在.button__text较短时平衡左右空间。将
justify-content: space-between应用于父元素,以帮助平衡.button__icon、.button__text和::after当.button__text较短时。添加
flex-shrink: 999,一个巨大的收缩因子,以便布局引擎在.button__text较长时优先收缩::after元素。*, *::before, *::after { box-sizing: border-box; } body { padding: 20px; min-height: 100vh; display: flex; flex-direction: column; } .grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; margin: auto 0; } .button { position: relative; display: flex; justify-content: space-between; align-items: center; cursor: pointer; outline: none; border: 1px solid #808080; padding: 20px; width: 100%; background-color: transparent; min-height: 80px; } .button::before { content: ""; width: 1px; position: absolute; top: 0; left: 50%; bottom: 0; background-color: red; } .button::after { flex: 0 999 calc(2em + 20px); content: ""; } .button__icon { flex-shrink: 0; margin-right: 20px; } .button__text { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; min-width: 0; text-align: center; border: 1px solid blue; }<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"/> <div class="grid"> <button class="button"> <i class="fa-solid fa-heart fa-2xl button__icon"></i> <span class="button__text"> 长文本,应该被截断 </span> </button> <button class="button"> <i class="fa-solid fa-thumbs-up fa-2xl button__icon"></i> <span class="button__text"> 中等长度 </span> </button> <button class="button"> <i class="fa-solid fa-house fa-2xl button__icon"></i> <span class="button__text"> 短 </span> </button> </div>