strml / textfit Goto Github PK
View Code? Open in Web Editor NEWA jQuery-free component that quickly fits single and multi-line text to the width (and optionally height) of its container.
Home Page: https://textfit.strml.net
A jQuery-free component that quickly fits single and multi-line text to the width (and optionally height) of its container.
Home Page: https://textfit.strml.net
Sometimes scrollbars which are initially visible disappear when adjusting text size. This breaks the logic and forces the smallest possible text size.
The issue is here:
// Binary search for best fit
while (low <= high) {
mid = parseInt((low + high) / 2, 10);
innerSpan.style.fontSize = mid + 'px';
if(innerSpan.scrollWidth <= originalWidth && (settings.widthOnly || innerSpan.scrollHeight <= originalHeight)){
low = mid + 1;
} else {
high = mid - 1;
}
}
When text becomes smaller, scrollbars which are initially visible may disappear. Then innerSpan.scrollWidth
becomes larger than originalWidth
, thus forcing to make the text size even smaller.
The problem is: this library replaces the original elements in a way that breaks those frameworks.
Please add support for them as they're quite popular nowadays
Hi, thank you first of all for writing this awesome tool!
For most window sizes textFit works perfect for me. But when I increase my browser window step by step, at some window sizes textFit suddenly does not work anymore, but takes the minimum text size although there is plenty of space in the element. Also the behaviour of the other buttons becomes unpredictable.
The behaviour is also dependent on the text content in the right button and, strangely enough, also on the text content in the other buttons.
The problem is the same in the jquery version.
C.f. the jsfiddle here: http://jsfiddle.net/dqLuqh7y/1/
and a screenshot here: https://www.dropbox.com/s/ia0q49pgxi0jbcf/screenshot.png?dl=0
unfortunately, you have to play with the window size yourself, because jsfiddle does not save the window size.
I want to use your tool for a responsive website / mobile app, but it is crucial that it works steadily. Can you help me?
This plugin is great work and super helpful on the products my company uses. Unfortunately, as of v2-noJQuery the plugin no longer works in IE8. I wasn't able to get the linked example/test page to work in IE8 either.
Hopefully you can get this figured out!
On larger texts (many characters) it keeps the lowest possible font size;
It'd be great if this didn't depend on jQuery, and thus could be used with/without any framework. Would be a great component to have.
Hello, I really like your plugin and it has saved half of my day.
Please remove false
from this line because it prevents module to be included with requirejs:
if (false && typeof define === "function" && define.amd) {
The example page mentioned in README (links to this page) does not show resized text, all text samples appear very tiny.
Tested with Firefox 76.0 and Edge (Chromium) Version 81.0.416.72 (Official build) (64-bit)
Note: It works correctly on this page, although this page's certificate is expired.
It works only half the time in safari,
I've spent about two days trying to figure out how to resize user-inputted and -formatted text of extremely varying length and markup to fit a container with a rigidly set height. Absolutely none of the other plugins I have tried (fitText, flowtype, fillText, any other combination of the words fit, text, and resize with a .js at the end) can do this, because they mostly focus on container width and/or only deal with one level of nesting, usually they just want a container div with a single span
inside. My own attempts were not very successful either.
textFit was the very last thing that I found before giving up, and I can't remember what bizarre combination of search terms led me here. I may have even overlooked it previously thinking that it was one I had already tried. It worked instantly without me needing to do anything at all and I am still reeling from the shock. Have you considered maybe giving this INCREDIBLE plugin a less generic name so that it doesn't get swallowed up among all the others that pop up when you type the words fit and text into google? The world needs to know about this! You've solved the unsolveable!
Anyway. Really I just wanted to say thank you so much for making this fantastic and beautiful thing, but I couldn't open an issue just for that. But thank you. I am extremely grateful.
Thanks for this! Great plugin. Would be nice to be able to specify the size of the font-size 'steps', so that, for instance, half-pixel values could result. I've been trying to modify the plugin to do this without much success.
The text got resize too small and it white cover entire background + bottom and left border can you tell me what i do wrong ?
Quite often, I find that setting an explicit width is inconvenient, because of unknown screen widths, but I hate a pretty good idea of what the height should be. Would it be possible to have a mode where we can expand vertically, and just leave the width to the browser?
Thanks!
This is how I'm trying to implement things:
jQuery("#form-field-text").on("change keyup paste", function(){
jQuery('.canvas-text').text(jQuery(this).val());
textFit(jQuery(".canvas-text"), {widthOnly: false});
});
So a user fills text in the input box at #form-field-text, it automatically gets inserted into .canvas-text at every keypress, and after that textFit runs. It's doing its job, but the text is only appearing on a single line. Check out the codepen here:
Hi there, I've got an interesting one for you here, with a PR on the way!
To recreate for this specific jsfiddle ( https://jsfiddle.net/y6xej9kv/2/ ) , you need to be on Windows + Chrome, set your OS-level display scaling to 175% (display settings), then in your browser, zoom to 67%. I'm sorry it's a bit obscure but this is how it's recreated for that specific sample.
Any OS, on Chrome zoom to 75%
When all this is done you will see this:
but we're actually expecting this:
and this is likely what you will see if you open the "bugged" jsfiddle without any of the scaling/zoom settings anyway.
So what's going on here is that as soon as you mess around with scaling, some dimensions will fall on floating points, but textfit is using scrollWidth
and clientWidth
to determine dimensions, which are not only always pure integers, but also rounded differently internally by the browser, which is the root cause of this bug.
If you're running the "bugged" JSfiddle with the settings I mentioned, these will be the values
Meaning that the while loop that determines the fitted size can never fulfill correctly.
There are a couple ways to solve this, but in the PR ( fiddle example here https://jsfiddle.net/wh6q7yxb/1/ )I'll opt for replacing both clientWidth and scrollWidth (also clientHeight and scrollHeight to prevent a similar issue) with .getBoundingClientRect() which will always return the exact rendered values as a float. I understand .getBoundingClientRect is not the same as .scrollHeight/width, I don't think using that property there is actually not of much use, because it's a span, by default these can't scroll in any direction so only if someone explicitly made a display: block; out of it can this be a issue.
.textFitAlignVert has position:absolute and that doesn't respect padding
Hi, First of all, such an amazing plugin this is!
Though it works on most of use cases, it does not seem to be resizing when applied on an ordered/ unordered list.
Any workaround for the same?
maybe just me...
chrome OSX newest of now
Error: Set a static height and width on the target element <a class="c1 arial" style="width: 400px; height: 20px;">Text</a>
before using textFit!
As CLEARLY seen above, I have set the width and height. But it is still giving errors.
Is it possible to fit all the p elements inside a div?
I have a div with fixed width and height 300px and 600px, with many p elements inside, I tried with textFit(document.querySelectorAll(".box" + "p"));
but nothing changes.
If I remove p tags and just do textFit(document.querySelectorAll(".box"));
it works, but I really need paragraphs.
Any way to do this?
I had to change this line
innerSpan = $(originalText).find('span.textfitted');
to
innerSpan = $(this).find('span.textfitted');
to make it work.
Otherwise the innerSpan.width() would be null.
Great plugin. I must have gone through several dozen plugins claiming to adjust font size before I found this one.
FYI at really small font sizes it breaks. If you set a div to 5px tall by 500px wide, the line-height
of the div is never modified, this pushes the span to a new line, like this JSFiddle I made to show the issue: https://jsfiddle.net/zhtt7t8p/5/
You can see there the span doesn't line up. I fixed it in my code by forking your code & setting the line-heights. For the "parent", I do this in the binary search [probably crap code but shows the fix]:
$(innerSpan).parent().css('line-height', '0px'); // set parent's line height to 0
$(innerSpan).css('line-height', mid + 'px'); // set child line height to same as font size
This was required to ensure that the inner span doesn't overflow it's parent. I also modified the part after the binary search:
// Sub 1 at the very end, this is closer to what we wanted.
$(innerSpan).css('line-height', (mid-1) + 'px');
innerSpan.style.fontSize = (mid - 1) + 'px';
Since your plugin runs the sizing logic once when invoked, and doesn't bind to any resize events, I wrote my own plugin that runs yours when invoked, and again when the elements are resized. However your algorithm causes more resizes to fire, which causes an infinite loop. I worked around this by setting overflow:hidden
to prevent unwanted resize events. Since your algorithm is asynchronous (it takes time to try the different font sizes until it is done), the resize events can fire while the algorithm is still running, creating race conditions where different instances of the algorithm are fighting over the same piece of text simultaneously. To workaround this my plugin simply wraps your plugin in Underscore's _.throttle()
method to ensure it won't be called more frequently than once a second.
If your plugin simply had a callback for when it was done sizing the text, I as a user could unbind the resize event while your algorithm is "working" to only rebind it when your algorithm is "done". This would fix a lot of race conditions & make it easier to bind the plugin to resize events of it's parent element.
I'm still working on this one but sometimes if the parent has some width (let's say 500px), and you put the span of text there inside it & start iterating through font sizes, sometimes I've seen Chrome set the span's width to 501px (1px overflowing its parent). I think it depends on some font settings or letter spacing. Still debugging.
The problem this causes is that your algorithm responds to this by continuing to decrease the font size. For some reason, independent of font size, Chrome is always rendering the inner span at 501px until the font-size is decreased enough for all text to fit on one line.
The only workarounds I can think of are
In the binary search when it's checking if the width/height are acceptable, compare it to the parent's size +3px to give it some "wiggle room" (this can make the fonts too big in 99% of cases).
I noticed another thing we can use to detect this "situation" (browser bug). If the size of the inner span (501px in our case) has not changed between multiple iterations of the binary search (and that size is within some acceptable threshold of the target size), we can conclude that the font size is acceptable, and assume that the 1px overflow is due to a browser bug that will not be affected by any further font-size decreases (at least not without making the text so undesirably small that it defeats the purpose of the plugin)
I found that line-height can break the script if the line-height is larger than the element size. To work around this (I need to adjust the line height to get the font to center), I set the line-height style to normal then call the script and clear the normal setting after completion.
I am getting inconsistent results on the first execution of a fresh browser window. The same element on first calculation of a fresh browser instance will result in 32px but in later calculations, the correct result of 35px is achieved. I thought this would be because the function does not return fast enough so I tried wrapping it into a promise. Does the script have callbacks perhaps onComplete?
I am trying to fit a single line of text ({ minFontSize: 16, maxFontSize: 30 }
). But the text is often smaller than it needs to be, and when I increase the font-size
property by 1px
it still fits in the container. The library seems to skip odd font-sizes for some reason.
I suspect the binary search algorithm may be the problem.
i'm really happy to have found this. it's exactly what i need.
but my text i want to make huge is marked as h1 and that overwrites the font-size.
my idea was to add !important
to the font-site added by textFit but don't know where.
if you delete the h1
it works as it should.
can you fix it?
I have seen some cases where a long URL is limiting the increase of font size because it is not being split. If the URL were able to be broken up, then the text would grow in font size to be larger, to fill the available box space.
Can this be accommodated?
Hello,
Thanks for this nice tool! :-)
One issue still I have:
If I do a textFit for an array : textFit(document.getElementsByClassName('box'));
It does not work.
But if I do a textFit to an element only it works:
textFit(document.getElementsByClassName('box')[0]);
Would you have any idea why?
I am using Chrome. Here is my code:
<div data-role="page" id="main" class="cl_main_page">
<div data-role="content">
<div class="responsive_levelbackground"><span>Shop</span></div>
<div class="responsive_levelbackground lbl" id="f0"></div>
<div class="responsive_levelbackground lbl" id="f1"></div>
<div class="responsive_levelbackground lbl" id="f2"></div>
<div class="responsive_levelbackground lbl" id="f3"></div>
<div class="responsive_levelbackground lbl" id="f4"></div>
<div class="responsive_levelbackground">Online Quizz</div>
</div><!-- /content -->
</div><!-- /page -->
(I have text being filled into DIvs depending on IDs too..)
Then
textFit(document.getElementsByClassName('responsive_levelbackground'));
does not work
but textFit(document.getElementsByClassName('responsive_levelbackground')[0]);
textFit(document.getElementsByClassName('responsive_levelbackground')[1]);
...
work fine..
Thank you
Seems like you don't call callback at the end
I'm getting the set a static height and width on target ellement when I change the text and re run textfit:
Set a static height and width on the target element
I have my initial div set up with text in it and it works just fine. But if I use jquery to change the text value of the div with jquery's text() function, it tells me to set the width and height first, then th next time the text is changed ti works. Eveyr other time I change the text it goes from working, to giving me that error.
Hello,
In my use case, the size of the divs vary depending on the resolution of the user's screen and how they decide to display the page, so I can't use fixed sizes for min and max font-size.
Do you have any plans to allow for 'em' units for these options?
Cheers!
Seb
Most TypeScript users are using @types/textFit
as an alternative.
The latest version was released 3 year ago without type definition file.
However, the type definition file was added in a recent commit, Could you publish new version include these changes?
⬆️ files in node_modules/textFit
2.4.0
In case the innerWidth or height of an element is zero, the lib throws an error :
Line 104 in 7a1eed6
Trying to hook this up with to a resize event but it doesn't seem to adjust the sizing. I tried setting reProcess to true but that wouldn't do much either. Do you have a demo or something for handling text resizing on browser resize events?
Thanks for a great piece of code, and that you're so keen on helping out :)
Hello again,
Great that you were able to solve the other trouble I had with the script not working in Firefox. I've stumbled upon what seems to be another bug.
I got it working when using an unique id, but if I use:
textFit(document.getElementsByClassName('content'));
or even textFit($('.content'));
TypeError: el.getAttribute is not a function
if (el.length === 0 || (!settings.reProcess && el.getAttribute('boxfitted'))) {
This is present both in Firefox and in Webkit.
right now it accepts element i.e. $('.box') or document.getElementsByClassName('box')
please allow us to pass the string directly with box class
thank you
Hi, I'm trying to solve this problem in my app that using textFit but my every try ended with fail :(
How to force textFit to make new line? For example textFit get text from textarea, user using enter makes new line but textFit don't create new line. Any tips for solve this problem?
Is this published on any js cdn so we can use it easily with script import? I can't find it in readme or in the site.
I have a couple divs that I show/hide using element.hidden = true
etc. My code sets all the text, then unhides. If I run the textFit(myElement)
before setting hidden
to false, then it defaults to the smallest text size.
Is there a way to make this work on hidden elements?
Is it possible to set max lines option to not exceed X lines when scaling text down?
The version slug in textFit.js still describes itself as "textFit v2.1.1"
Should be textFit v2.3.0
I am running into an issue where Safari isn't considering the height of the box, but only the width.
For very short labels this will render the font much larger. In Firefox or Chrome, the result is correct.
In the CSS, I specify height of box, as well as line-height.
Any idea, what to adapt to make this work, or is this a known issue?
Hi, what is the current status of this project? Is it still maintained?
There is an issue with el.clientWidth and el.clientHeight.
On Chrome 69, theses functions always return 0 (in my case), even if I set style="width:300px;height:300px" on my box.
So the script doesn't know how to get width and heigth.
Thanks for an awesome library, works great!
I want to use the resulting font size after textFit()
has been executed, something like this:
fitText(...);
doSomethingElse();
I'm finding that doSomethingElse()
is being called before fitText()
has done it's thing, so the I'm getting the original font size. Wrapping doSomethingElse()
in a timeout helps, but introduces a lag into the UI.
Is there a way to set-up a callback so that doSomethingElse()
is only run after fitText()
has finished?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.