I have a "wall" of quare-sized Bootstrap button with one fontawesome icon and two lines of text (<span>
) below. Sometimes, the text for each line can be too long, so it wraps naturally. I want to prevent that. However, it is a requirement, that the full text must be displayed. I also don't want to break the tile layout by enlarging single tiles.
Therefore, my idea was to use a CSS transform: scaleX(?)
to squeeze the text in case. But I don't have a reference to the actual width of the text. Also, the with of the tiles is based on relative units, so I can't use any fixed pixel values.
Here's my current css declatation:
<style>
.flex-container .btn-lg {
width: 20vmin;
height: 20vmin;
margin: 8px;
font-size: 3.5vmin;
word-wrap: break-word;
white-space: normal;
}
.btn-tile > * {
display: flex;
justify-content: center;
}
</style>
<div data-bind="foreach: $data.entries" class="flex-container">
<button class="btn btn-secondary btn-lg btn-tile storageType-3" data-bind="click: e, class: 'storageType-' + d.type">
<i class="fas fa-ramp-loading" data-bind="class: d.icon"></i>
<span data-bind="text: d.desc1"></span>
<span data-bind="text: d.desc2" style=" /* Experimental */
transform: scaleX(.8);
white-space: nowrap;
">This text is way too long</span>
</button>
</div>
If the texts desc1
or desc2
are too long, a scaleX should be applied, so that they fit inside the fixed size button.
Is this even possible with pure CSS, or do I need to iterate over the tiles with Javascript, read the actual widths and calculate the scaling factor like that?
I'm using knockout binding, by the way.
Edit:
I did some experimenting, but I still can't calculate the correct scaling factor. The correct factor should be somewhere around .3 for a longer text. It returns 0.477, though.
1 / $('.btn-tile').first().children().last()[0].scrollWidth * ($('.btn-tile')[0].offsetWidth)
The idea is to use the difference in scrollWidth
and clientWidth
in overflowing elements to compute the ideal scaling that would fit the entire parent element, and apply that as a scaleX
transform to the overflowing element.
Don't forget to set the transform origin to the left side of the object, since it is overflowing on the right.
Unfortunately I don't think you can do this in pure CSS as you need to compute the scrollWidth and clientWidth. But here is a minimal example of how you can do this:
els = document.querySelectorAll(".possibly-scaled");
for (let el of els) {
let xScale = el.clientWidth / el.scrollWidth;
if (xScale < 1) {
el.style.transform = "scaleX(" + xScale + ")";
}
}
.fixed-width {
font-size: 30px;
margin: 8px;
padding: 4px;
text-align: center;
background-color: yellow;
/* necessary styling */
width: 80px;
white-space: nowrap;
}
.possibly-scaled {
/* necessary styling */
display: block;
transform-origin: 0 0;
}
<div class="fixed-width">
<span class="possibly-scaled">OK</span>
</div>
<div class="fixed-width">
<span class="possibly-scaled">Good</span>
</div>
<div class="fixed-width">
<span class="possibly-scaled">Fantastic!</span>
</div>
<div class="fixed-width">
<span class="possibly-scaled">Amazingly, this also fits.</span>
</div>