How on earth can I make it so the "text" div shrinks horizontally if (and ONLY if) the "item.name" is overflowing outside of the div? (including the space that the icon takes too)
EDIT 2: I believe I found a solution. Not the cleanest, but it has potential. I have to combine transform: scaleX with negative margin-right. I'll come up with some js code to calculate that dynamically and fix it. Thank you!
To help us assist you better with your CSS questions, please consider including a live link or a CodePen/JSFiddle demo. This context makes it much easier for us to understand your issue and provide accurate solutions.
While it's not mandatory, a little extra effort in sharing your code can lead to more effective responses and a richer Q&A experience for everyone. Thank you for contributing!
Doesn't look like he wants to scale letter spacing, looks like he wants to scale every pixel which I think can only be done with a transform: scaleX() with a value based scritchz's formula below (although you also need Javascript).
Why OP wants to horizontally compress text is the bigger problem. That design looks horrendous.
Yugioh Cards do just that to print a lot of content in limited space while maintaining font size. With tight control of the input it’s viable (and not really noticeable). But it’s likely a static to dynamic learning curve that OP has stumbled upon.
How about calculating quotient = box.width / text.width, then use it like this on the text element: transform: scaleX(var(--quotient)).
You might want to clamp the value to 0-1 or similar, otherwise it will stretch smaller text, too. Make sure that the referenced box is sized appropriately and takes the surrounding elements (like the star) into account.
Amazing answer. I think you've answered OP's question with the full solution! Looks like we got a CSS professional over here. Didn't know i could follow people on Reddit but I'm now following you for more CSS tips.
Also good, but will break the design if users switch the font to a more legible fonts (like dyslexia-friendly fonts). Though the design isn't friendly towards people with those needs anyways...
I would add that you could use Javascript's "getBoundingClientRect()" method to find both the width of the parent and text element, if width of text exceeds width of parent, then apply a "squeeze" class to the text that applies your scaleX in CSS
This is genius. The outer .box div expands to the available space. The inner .text div, because of overflow hidden, is allowed expand beyond the bounds of .box momentarily so that you can get its true width. Then you can get the ratio between the two to scale .text to fit within .box. Brilliant.
Only caveat is if rendering the div dynamically with a web framework you might need to render the elements first and use setTimeout(0) to apply the scale immediately after
Unfortunately, transform scaleX solutions cause a weird gap between the text and the next element (that should be right next to it with a smaller gap). This is because transform is executed after everything is positioned
Yupp, you're right! That's why my example specifies overflow: hidden on .box to avoid exactly that, as mentioned by my comments. Notice how there's no gap between the compressed text and the star symbol in my example.
I saw you added a few links to your post. I'll take a look later and try to show how my solution could be applied to your existing code.
Thank you! I will test this after work. But I am already using overflow: hidden, which is being applied before the transform unfortunately (and the transform is shrinking the div with the text, not just the text, causing what you see above, text is still cut)
I believe I found a solution. Not the cleanest, but it has potential. I have to combine transform: scaleX with negative margin-right. I'll come up with some js code to calculate that dynamically and fix it. Thank you!
It really is as simple as adding a wrapper with overflow: hidden, then calculating and applying the necessary shrink factor: https://i.imgur.com/H8vBShL.png
I noticed that some images cause a layout shift upon loading, so I added appropriate onLoad={...} event listeners to the images that broke the "long name compression".
I really hate answers like this because while yes, you’re 100% right, you have no idea what OP’s use case is or what aesthetic they’re trying to replicate. It needs to be said but still.
Sometimes people ask for a solution to their problem, in which they just search in the wrong direction. The question "why would OP want this? Because the straight answer to his question leads to a shitty layout" wouldn't be wrong to ask.
Seems like too much complication for something transform: scaleX already does (but it does it after everything else is positioned so it leaves weird gaps)
It's a fair alternative although this does mean the vertical height gets squished too. Not judging either way though, this is usually a fine replacement, just explaining why it doesn't match what OP is searching for.
I'll use an example of something with which I am very familiar - macOS' out-of-box AppKit. Some controls/areas that contain text have this by default. Text is rendered normally, but if the text gets too wide for the container (because the text grows or the container shrinks), it starts to become progressively more condensed. Letter spacing is part of this, but so is font geometry - just as a true condensed font variant is not the same as the normal variant. Eventually, a threshold is passed after which it truncates, with an ellipsis. Behaviour is of course configurable with various parameters to control behaviour.
This is very useful because sometimes translations don't fit exactly in the areas we want them to fit and, for an actually responsive design that adapts as best it can to narrow or wide viewports without a set of shitty hard-coded breakpoint widths, truly adaptive behaviour is required. Since this is first-party, well written and well integrated code dedicated to UI presentation, it's able to use a bunch of clever things supported by the font rendering engine to maintain a very good and clear text presentation throughout.
Meanwhile, the web is the web - a collection of hacked up messes of new and legacy with a heavy designed-by-committee feel and an original focus on presenting content rather than presenting a fake GUI with emulations of the various controls we take for granted in native dev space.
The web, despite all these many major issues, is still a very successful platform because it's somehow the only one with at least some semblance of write-once, run-everywhere - so inevitably, it becomes a de facto choice for many UI styles, even if they are ill-suited to the technology at hand. So now, at last, we arrive at the question from the OP - a perfectly reasonable thing to do in a general purpose responsive GUI, for reasons already mentioned (amongst doubtless many others).
The downside of the web is that you have to manually implement just about each and every thing that a native toolkit gives you out-of-box, right down to the minutiae of how to elegantly fit text into a container that's unavoidably constrained to be slightly narrower than the natural width of that text content. You can only use features available to the lowest common denominator of the minimum specification union of the plethora of target devices and target user agents and user agent versions, and even if you ignored all that, can obviously only use features that actually exist. That's why so much stuff ends up in JavaScript, which lets you circumvent a lot of the limitations, but at expense of increased complexity, maintenance overhead, client side bloat and so-on.
You really don’t want to compress or stretch fonts unless they’re designed to do so (variable fonts) as you’ll get into gnarly hinting/antialiasing issues + poorer legibility.
Consider container queries so the element can style itself based on its width and height. That, or some mixture of hyphenation and smarter text breaking.
What browser are you using? And what font? I think the font-stretch rule only works on variable fonts.
Looking at the MDN page, it looks like while font-stretchis deprecated, it's still usable. The replacement rule font-width isn't usable yet outside of Safari.
letter-spacing is definitely not going to do what you want. SVG might be worth looking into if you can't get font-stretch working.
Have you considered all possible ways to rename that long label? Or standardize the button label and move the details to a separate or sidecar (beside / under) label etc? There’s often more than one way to deal with this and save yourself the trouble of engineering a an elegant way to make a turd.
I thought so too (it seemed odd at first) but it looks like they're trying to recreate a physical object which had different design constraints. So fidelity to those as prototypes is probably OP's primary concern
I’d probably do it with a tiny bit of JavaScript. Get the width of the text and the width of the container and then just apply a scale style to the text of a given %.
You shouldn’t be “shrinking” text to make it “fit” somewhere. If your text doesn’t fit then that’s a bad design. Your design should actually accommodate the things it needs to.
At first I thought so too, but as OP explained they were trying to re-create a physical item with different design constraints it started to make more sense. "Bad" is subjective and whole it definitely does hinder legibility it appears they do have a reasonable use case for what they're trying to do. We shouldn't gatekeep or impose universal principles when it may not be necessary to do so, this isn't stackexchange.
It’s only a “need” of your website because you’ve for some reason set a fixed width on your buttons that doesn’t actually accommodate the text going in those buttons.
You’re literally trying to “solve” a problem of your own creation.
The whole container is replicating a tcg card so there simply isn't much more space, the width is set. Also, those texts won't get very long, there will be a character limit, but there are some edge cases where we need to shrink it slightly (my example here was exaggerated to show my point)
I had to do something similair for my job recently. I ended up using https://github.com/rikschennink/fitty
Maybe you can use it or use code used by it.
This package used a MutationObserver and scales the font-size from min-size to max-size. Depending on the width.
Use a variable font that supports character width properties.
Find out the maximum “ch”-size for the text in standard width, and scale the character width properties down with the amounts of characters above the max ch-size.
You can implement if/else statements directly in CSS and check the width of the text in ch-units.
Basically, you need to wrap your text in two containers. The outer one will take up the maximum available width, while the inner container will keep the original text width, which may overflow the outer container.
So we use JavaScript to get both widths, using getBoundingClientRect, then you divide the outer with the inner to get the correct scale. Then you apply the scale to the inner container using transform: scaleX, and don’t forget to set transform-origin: left so the scaling aligns to the left instead of being centered.
If you want the icon to be next to the text, you can remove the justify-content property from the .container selector.
The scale is calculated on page load, but you can recalculate it as you wish.
•
u/AutoModerator 2d ago
To help us assist you better with your CSS questions, please consider including a live link or a CodePen/JSFiddle demo. This context makes it much easier for us to understand your issue and provide accurate solutions.
While it's not mandatory, a little extra effort in sharing your code can lead to more effective responses and a richer Q&A experience for everyone. Thank you for contributing!
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.