I'm having a hard time getting my head around font scaling.
I currently have this site with a body font-size
of 100%. 100% of what though? This seems to compute out at 16px.
I was under the impression that 100% would somehow refer to the size of the browser window, but apparently not because it's always 16px whether the window is resized down to a mobile width or full blown widescreen desktop.
How can I make the text on my site scale in relation to its container? I tried using em
but this doesn't scale either.
My reasoning is that things like my menu become squished when you resize, so I need to reduce the px font-size
of .menuItem
among other elements in relation to the width of the container. (E.g in the menu on a large desktop, 22px works perfectly. Move down to tablet width and 16px is more appropriate.)
I'm aware I can add breakpoints, but I really want the text to scale as WELL as having extra breakpoints, otherwise I'll end up with hundreds of breakpoints for every 100px decrease in width to control the text.
But what if the container is not the viewport (body)?
This question is asked in comment by Alex under the accepted answer.
That fact does not mean
vw
cannot be used to some extent to size for that container. Now to see any variation at all one has to be assuming that the container in some way is flexible in size. Whether through a direct percentagewidth
or through being 100% minus margins. The point becomes "moot" if the container is always set to, let's say,200px
wide--then just set afont-size
that works for that width.Example 1
With a flexible width container, however, it must be realized that in some way the container is still being sized off the viewport. As such, it is a matter of adjusting a
vw
setting based off that percentage size difference to the viewport, which means taking into account the sizing of parent wrappers. Take this example:Assuming here the
div
is a child of thebody
, it is50%
of that100%
width, which is the viewport size in this basic case. Basically, you want to set avw
that is going to look good to you. As you can see in my comment in the above css, you can "think" through that mathematically with respect to the full viewport size, but you don't need to do that. The text is going to "flex" with the container, because the container is flexing with the viewport resizing. UPDATE: here's an example of two differently sized containers.Example 2
You can help ensure viewport sizing by forcing the calculation based off that. Consider this example:
The sizing is still based off viewport, but is in essence set up based off the container size itself.
Should Sizing of the Container Change Dynamically...
If sizing of the container element ended up changing dynamically its percentage relationship either via
@media
break points or via javascript, then whatever the base "target" was would need recalculation to maintain the same "relationship" for text sizing.Take Example #1 above. If the
div
was switched to25%
width by either@media
or javascript, then at the same time, thefont-size
would need to adjust in either the media query or by javascript to the new calculation of5vw * .25 = 1.25
. This would put the text size at the same size it would have been had the "width" of the original50%
container been reduced by half from viewport sizing, but has now been reduced due to a change in its own percentage calculation.A Challenge
With the CSS3
calc()
function in use, it would become difficult to adjust dynamically, as that function does not work forfont-size
purposes at this time. So you could not do a pure CSS3 adjustment if your width is changing oncalc()
. Of course, a minor adjustment of width for margins may not be enough to warrant any change infont-size
, so it may not matter.Pure-CSS solution with
calc()
, CSS units and mathThis is precisely not what OP asks, but may make someone's day. This answer is not spoon-feedingly easy and needs some researching in developer end.
I came finally to get a pure-CSS solution for this using
calc()
with different units. You will need some basic mathematical understanding of formulas to work out your expression forcalc()
.When I worked this out, I had to get a full-page-width responsive header with some padding few parents up in DOM. I'll use my values here, replace them with your own.
To mathematics
You will need:
padding: 3em
and full width so this got to100wv - 2 * 3em
X is the width of container so replace it with your own expression or adjust the value to get full-page text. R is the ratio you will have. You can get it by adjusting the values in some viewport, inspecting element width and height and replacing them with your own values. Also, it is
width / heigth
;)And bang! It worked! I wrote
to my header and it adjusted nicely in every viewport.
But how does it work?
We need some constants up here.
100vw
means the full width of viewport, and my goal was to establish full-width header with some padding.The ratio. Getting a width and height in one viewport got me a ratio to play with, and with ratio I know what the height should be in other viewport width. Calculating them with hand would take plenty of time and at least take lots of bandwith so it's not a good answer.
Conclusion
I wonder why no-one has figured this out and some people are even telling that this would be impossible to tinker with CSS. I don't like to use Javascript in adjusting elements, so I don't accept JS or even jQuery answers without digging more. All in all, it's good that this got figured out and this is one step to pure-CSS implementations in website design.
I apologize of any unusual convention in my text, I'm not native speaker in english and also quite new to writing SO answers.
Edit: it should also be noted that we have evil scrollbars in some browsers. For example, when using Firefox I noticed that
100vw
means the full width of viewport, extending under scrollbar (where content cannot expand!), so the fullwidth text has to be margined carefully and preferably get tested with many browsers and devices.My own solution, jQuery based, works by gradually increasing the font size until the container gets a big increase in height (meaning it got a line break). It's pretty simple but works fairly well and it very easy to use. You don't have to know ANYTHING about the font being used, everything is taken care of by the browser.
You can play with it on http://jsfiddle.net/tubededentifrice/u5y15d0L/2/
The magic happens here:
My problem was similar but related to scaling text within a heading. I tried Fit Font but I needed to toggle the compressor to get any results, since it was solving a slightly different problem, as was Text Flow. So I wrote my own little plugin that reduces the font size to fit the container, assuming you have
overflow: hidden
andwhite-space: nowrap
so that even if reducing the font to the minimum doesn't allow showing the full heading, it just cuts off what it can show.This worked for me:
I try to approx font-size based on a width/heght got from setting font-size:10px. Basically the idea is "if i have 20px width and 11px height with font-size:10px, so what would it be the max font-size to math a container of 50px width and 30px height?"
The answer is a double proportion system:
{ 20:10=50:X, 11:10=30:Y } = { X= (10*50)/20 , Y= (10*30)/11 }
Now X is a font-size that will match width, Y is a font-size that will match height; take the smallest value
NB: the argument of the function must be a span element or an element wich is smaller than it's parent, otherwise if children and parent have both the same width/height function will fail
100% is relative to the base font size, which if you haven't set it would be the browser's user-agent default.
To get the effect you're after I would use a piece of javascript to adjust the base font size relative to the window dimensions.