REM font size not adjusting below arbitrary threshold
In Safari 12.0.2 and Chrome 71.0.3578.98 on Mac Mojave 10.14.2, when setting the font-size
using rem
units, the actual size won't go below 9px
.
See this example:
https://codepen.io/stephenjwatkins/pen/OrbGxL
My browser's font size is set to the default (16px
) with a minimum font size set to 6px
:
Setting text-size-adjust
to none
doesn't affect the problem. Firefox renders the size correctly.
The only thing that I've found to fix the problem is setting font-size: 0;
to a parent element. For instance, if you add font-size: 0;
to .container
, the correct font size is rendered.
Does anyone know why it's not honoring the rem
size below a certain threshold?
css blink
|
show 5 more comments
In Safari 12.0.2 and Chrome 71.0.3578.98 on Mac Mojave 10.14.2, when setting the font-size
using rem
units, the actual size won't go below 9px
.
See this example:
https://codepen.io/stephenjwatkins/pen/OrbGxL
My browser's font size is set to the default (16px
) with a minimum font size set to 6px
:
Setting text-size-adjust
to none
doesn't affect the problem. Firefox renders the size correctly.
The only thing that I've found to fix the problem is setting font-size: 0;
to a parent element. For instance, if you add font-size: 0;
to .container
, the correct font size is rendered.
Does anyone know why it's not honoring the rem
size below a certain threshold?
css blink
When you add the vendor prefix of-webkit-text-size-adjust: none
still no love?
– Chris W.
Dec 19 '18 at 18:06
Still no love with the vendor prefixed-webkit-text-size-adjust: none;
.
– Stephen Watkins
Dec 19 '18 at 18:09
this is a known feature, I will try to find the duplicate question
– Temani Afif
Dec 19 '18 at 19:24
1
I believe this is a duplicate of stackoverflow.com/questions/21302069/… but I can't close vote due to the bounty.
– zzzzBov
Jan 2 at 19:49
1
This is not a duplicate of stackoverflow.com/questions/21302069/…. The minimum font size on the browser is set to6px
, but it isn't being honored withrem
units. For instance, I can set the font size to6px
if I usepx
explicitly, but not lower than6px
, as expected. This is a different problem.
– Stephen Watkins
Jan 2 at 21:52
|
show 5 more comments
In Safari 12.0.2 and Chrome 71.0.3578.98 on Mac Mojave 10.14.2, when setting the font-size
using rem
units, the actual size won't go below 9px
.
See this example:
https://codepen.io/stephenjwatkins/pen/OrbGxL
My browser's font size is set to the default (16px
) with a minimum font size set to 6px
:
Setting text-size-adjust
to none
doesn't affect the problem. Firefox renders the size correctly.
The only thing that I've found to fix the problem is setting font-size: 0;
to a parent element. For instance, if you add font-size: 0;
to .container
, the correct font size is rendered.
Does anyone know why it's not honoring the rem
size below a certain threshold?
css blink
In Safari 12.0.2 and Chrome 71.0.3578.98 on Mac Mojave 10.14.2, when setting the font-size
using rem
units, the actual size won't go below 9px
.
See this example:
https://codepen.io/stephenjwatkins/pen/OrbGxL
My browser's font size is set to the default (16px
) with a minimum font size set to 6px
:
Setting text-size-adjust
to none
doesn't affect the problem. Firefox renders the size correctly.
The only thing that I've found to fix the problem is setting font-size: 0;
to a parent element. For instance, if you add font-size: 0;
to .container
, the correct font size is rendered.
Does anyone know why it's not honoring the rem
size below a certain threshold?
css blink
css blink
edited Jan 3 at 0:31


bishop
24.8k56892
24.8k56892
asked Dec 19 '18 at 17:58
Stephen WatkinsStephen Watkins
16.8k85392
16.8k85392
When you add the vendor prefix of-webkit-text-size-adjust: none
still no love?
– Chris W.
Dec 19 '18 at 18:06
Still no love with the vendor prefixed-webkit-text-size-adjust: none;
.
– Stephen Watkins
Dec 19 '18 at 18:09
this is a known feature, I will try to find the duplicate question
– Temani Afif
Dec 19 '18 at 19:24
1
I believe this is a duplicate of stackoverflow.com/questions/21302069/… but I can't close vote due to the bounty.
– zzzzBov
Jan 2 at 19:49
1
This is not a duplicate of stackoverflow.com/questions/21302069/…. The minimum font size on the browser is set to6px
, but it isn't being honored withrem
units. For instance, I can set the font size to6px
if I usepx
explicitly, but not lower than6px
, as expected. This is a different problem.
– Stephen Watkins
Jan 2 at 21:52
|
show 5 more comments
When you add the vendor prefix of-webkit-text-size-adjust: none
still no love?
– Chris W.
Dec 19 '18 at 18:06
Still no love with the vendor prefixed-webkit-text-size-adjust: none;
.
– Stephen Watkins
Dec 19 '18 at 18:09
this is a known feature, I will try to find the duplicate question
– Temani Afif
Dec 19 '18 at 19:24
1
I believe this is a duplicate of stackoverflow.com/questions/21302069/… but I can't close vote due to the bounty.
– zzzzBov
Jan 2 at 19:49
1
This is not a duplicate of stackoverflow.com/questions/21302069/…. The minimum font size on the browser is set to6px
, but it isn't being honored withrem
units. For instance, I can set the font size to6px
if I usepx
explicitly, but not lower than6px
, as expected. This is a different problem.
– Stephen Watkins
Jan 2 at 21:52
When you add the vendor prefix of
-webkit-text-size-adjust: none
still no love?– Chris W.
Dec 19 '18 at 18:06
When you add the vendor prefix of
-webkit-text-size-adjust: none
still no love?– Chris W.
Dec 19 '18 at 18:06
Still no love with the vendor prefixed
-webkit-text-size-adjust: none;
.– Stephen Watkins
Dec 19 '18 at 18:09
Still no love with the vendor prefixed
-webkit-text-size-adjust: none;
.– Stephen Watkins
Dec 19 '18 at 18:09
this is a known feature, I will try to find the duplicate question
– Temani Afif
Dec 19 '18 at 19:24
this is a known feature, I will try to find the duplicate question
– Temani Afif
Dec 19 '18 at 19:24
1
1
I believe this is a duplicate of stackoverflow.com/questions/21302069/… but I can't close vote due to the bounty.
– zzzzBov
Jan 2 at 19:49
I believe this is a duplicate of stackoverflow.com/questions/21302069/… but I can't close vote due to the bounty.
– zzzzBov
Jan 2 at 19:49
1
1
This is not a duplicate of stackoverflow.com/questions/21302069/…. The minimum font size on the browser is set to
6px
, but it isn't being honored with rem
units. For instance, I can set the font size to 6px
if I use px
explicitly, but not lower than 6px
, as expected. This is a different problem.– Stephen Watkins
Jan 2 at 21:52
This is not a duplicate of stackoverflow.com/questions/21302069/…. The minimum font size on the browser is set to
6px
, but it isn't being honored with rem
units. For instance, I can set the font size to 6px
if I use px
explicitly, but not lower than 6px
, as expected. This is a different problem.– Stephen Watkins
Jan 2 at 21:52
|
show 5 more comments
1 Answer
1
active
oldest
votes
Chrome and its Blink rendering engine seem to have some non-obvious font-scaling rules. I'm unaware of any official comprehensive documentation, so let's go to the source.
(Note that I'm not an expert on Chromium internals generally or Blink renderer particularly. I've just been tracing through the source code and speculating on the most probable answers to the questions as posed.)
It seems to me that the engine calls upon the FontBuilder
class during a redraw. This class has various dispatch methods that pass the DOM, zoom, and other relevant factors into what appears to be the crucial method: FontSize :: getComputedSizeFromSpecifiedSize
. In that method, we see some juicy comments that address the points you've raised:
1. Why does setting font-size: 0;
to a parent element fix it?
// Text with a 0px font size should not be visible and therefore needs to be
// exempt from minimum font size rules. Acid3 relies on this for pixel-perfect
// rendering. This is also compatible with other browsers that have minimum
// font size settings (e.g. Firefox).
2. Why is it not honoring the rem size below a certain threshold?
// We support two types of minimum font size. The first is a hard override
// that applies to all fonts. This is "minSize." The second type of minimum
// font size is a "smart minimum" that is applied only when the Web page can't
// know what size it really asked for, e.g., when it uses logical sizes like
// "small" or expresses the font-size as a percentage of the user's default
// font setting.
// With the smart minimum, we never want to get smaller than the minimum font
// size to keep fonts readable. However we always allow the page to set an
// explicit pixel size that is smaller, since sites will mis-render otherwise
// (e.g., http://www.gamespot.com with a 9px minimum).
3. For the curious, what are these minimum values when given relative units (eg x-small
)?
// Strict mode table matches MacIE and Mozilla's settings exactly.
static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin +
1][totalKeywords] = {
{9, 9, 9, 9, 11, 14, 18, 27}, {9, 9, 9, 10, 12, 15, 20, 30},
{9, 9, 10, 11, 13, 17, 22, 33}, {9, 9, 10, 12, 14, 18, 24, 36},
{9, 10, 12, 13, 16, 20, 26, 39}, // fixed font default (13)
{9, 10, 12, 14, 17, 21, 28, 42}, {9, 10, 13, 15, 18, 23, 30, 45},
{9, 10, 13, 16, 18, 24, 32, 48} // proportional font default (16)
};
// HTML 1 2 3 4 5 6 7
// CSS xxs xs s m l xl xxl
// |
// user pref
Interestingly, and a bit of an aside, the FontBuilder
class dispatches to TextAutosizer :: computeAutosizedFontSize to scale the font size. This method uses hard coded values and a variable scaling factor:
// Somewhat arbitrary "pleasant" font size.
const float pleasantSize = 16;
// Multiply fonts that the page author has specified to be larger than
// pleasantSize by less and less, until huge fonts are not increased at all.
// For specifiedSize between 0 and pleasantSize we directly apply the
// multiplier; hence for specifiedSize == pleasantSize, computedSize will be
// multiplier * pleasantSize. For greater specifiedSizes we want to
// gradually fade out the multiplier, so for every 1px increase in
// specifiedSize beyond pleasantSize we will only increase computedSize
// by gradientAfterPleasantSize px until we meet the
// computedSize = specifiedSize line, after which we stay on that line (so
// then every 1px increase in specifiedSize increases computedSize by 1px).
const float gradientAfterPleasantSize = 0.5;
From these facts, we see there are a good number of hard-coded pixel values, with 9
and 16
being commonly sprinkled about the relevant code. These hard-codes, the presence of several rules to scale the font down to a limit, with the ability to override using font-size all seem to match the observations and suggest it's behaving as intended -- if not necessarily intuitively.
Also, I've found that the most recent comment posted in Chrome bug #319623 very much resembles your report.
Possibly related: when using relative units on the html tag, rem-based values defined elsewhere will have a lower bound of 9px.
See CodePen: http://codepen.io/larrybotha/pen/wKYYXE
Workaround: absolute unit on html, em unit on body. rems everywhere else.
It may be prudent to watch that bug for further developments, though maybe not with breath held. The last update was in 2015.
1
Good research and write-up. While I can't say that I fully grok Blink's logic, based on the problem and the code you shared here, I agree with your conclusion.
– Stephen Watkins
Jan 4 at 17:51
Glad it helped, @StephenWatkins. I hope this analysis is at least in the ball-park, but I'd love a Chrome expert to phone in: this all seems a bit hacky to me.
– bishop
Jan 4 at 18:08
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53856831%2frem-font-size-not-adjusting-below-arbitrary-threshold%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Chrome and its Blink rendering engine seem to have some non-obvious font-scaling rules. I'm unaware of any official comprehensive documentation, so let's go to the source.
(Note that I'm not an expert on Chromium internals generally or Blink renderer particularly. I've just been tracing through the source code and speculating on the most probable answers to the questions as posed.)
It seems to me that the engine calls upon the FontBuilder
class during a redraw. This class has various dispatch methods that pass the DOM, zoom, and other relevant factors into what appears to be the crucial method: FontSize :: getComputedSizeFromSpecifiedSize
. In that method, we see some juicy comments that address the points you've raised:
1. Why does setting font-size: 0;
to a parent element fix it?
// Text with a 0px font size should not be visible and therefore needs to be
// exempt from minimum font size rules. Acid3 relies on this for pixel-perfect
// rendering. This is also compatible with other browsers that have minimum
// font size settings (e.g. Firefox).
2. Why is it not honoring the rem size below a certain threshold?
// We support two types of minimum font size. The first is a hard override
// that applies to all fonts. This is "minSize." The second type of minimum
// font size is a "smart minimum" that is applied only when the Web page can't
// know what size it really asked for, e.g., when it uses logical sizes like
// "small" or expresses the font-size as a percentage of the user's default
// font setting.
// With the smart minimum, we never want to get smaller than the minimum font
// size to keep fonts readable. However we always allow the page to set an
// explicit pixel size that is smaller, since sites will mis-render otherwise
// (e.g., http://www.gamespot.com with a 9px minimum).
3. For the curious, what are these minimum values when given relative units (eg x-small
)?
// Strict mode table matches MacIE and Mozilla's settings exactly.
static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin +
1][totalKeywords] = {
{9, 9, 9, 9, 11, 14, 18, 27}, {9, 9, 9, 10, 12, 15, 20, 30},
{9, 9, 10, 11, 13, 17, 22, 33}, {9, 9, 10, 12, 14, 18, 24, 36},
{9, 10, 12, 13, 16, 20, 26, 39}, // fixed font default (13)
{9, 10, 12, 14, 17, 21, 28, 42}, {9, 10, 13, 15, 18, 23, 30, 45},
{9, 10, 13, 16, 18, 24, 32, 48} // proportional font default (16)
};
// HTML 1 2 3 4 5 6 7
// CSS xxs xs s m l xl xxl
// |
// user pref
Interestingly, and a bit of an aside, the FontBuilder
class dispatches to TextAutosizer :: computeAutosizedFontSize to scale the font size. This method uses hard coded values and a variable scaling factor:
// Somewhat arbitrary "pleasant" font size.
const float pleasantSize = 16;
// Multiply fonts that the page author has specified to be larger than
// pleasantSize by less and less, until huge fonts are not increased at all.
// For specifiedSize between 0 and pleasantSize we directly apply the
// multiplier; hence for specifiedSize == pleasantSize, computedSize will be
// multiplier * pleasantSize. For greater specifiedSizes we want to
// gradually fade out the multiplier, so for every 1px increase in
// specifiedSize beyond pleasantSize we will only increase computedSize
// by gradientAfterPleasantSize px until we meet the
// computedSize = specifiedSize line, after which we stay on that line (so
// then every 1px increase in specifiedSize increases computedSize by 1px).
const float gradientAfterPleasantSize = 0.5;
From these facts, we see there are a good number of hard-coded pixel values, with 9
and 16
being commonly sprinkled about the relevant code. These hard-codes, the presence of several rules to scale the font down to a limit, with the ability to override using font-size all seem to match the observations and suggest it's behaving as intended -- if not necessarily intuitively.
Also, I've found that the most recent comment posted in Chrome bug #319623 very much resembles your report.
Possibly related: when using relative units on the html tag, rem-based values defined elsewhere will have a lower bound of 9px.
See CodePen: http://codepen.io/larrybotha/pen/wKYYXE
Workaround: absolute unit on html, em unit on body. rems everywhere else.
It may be prudent to watch that bug for further developments, though maybe not with breath held. The last update was in 2015.
1
Good research and write-up. While I can't say that I fully grok Blink's logic, based on the problem and the code you shared here, I agree with your conclusion.
– Stephen Watkins
Jan 4 at 17:51
Glad it helped, @StephenWatkins. I hope this analysis is at least in the ball-park, but I'd love a Chrome expert to phone in: this all seems a bit hacky to me.
– bishop
Jan 4 at 18:08
add a comment |
Chrome and its Blink rendering engine seem to have some non-obvious font-scaling rules. I'm unaware of any official comprehensive documentation, so let's go to the source.
(Note that I'm not an expert on Chromium internals generally or Blink renderer particularly. I've just been tracing through the source code and speculating on the most probable answers to the questions as posed.)
It seems to me that the engine calls upon the FontBuilder
class during a redraw. This class has various dispatch methods that pass the DOM, zoom, and other relevant factors into what appears to be the crucial method: FontSize :: getComputedSizeFromSpecifiedSize
. In that method, we see some juicy comments that address the points you've raised:
1. Why does setting font-size: 0;
to a parent element fix it?
// Text with a 0px font size should not be visible and therefore needs to be
// exempt from minimum font size rules. Acid3 relies on this for pixel-perfect
// rendering. This is also compatible with other browsers that have minimum
// font size settings (e.g. Firefox).
2. Why is it not honoring the rem size below a certain threshold?
// We support two types of minimum font size. The first is a hard override
// that applies to all fonts. This is "minSize." The second type of minimum
// font size is a "smart minimum" that is applied only when the Web page can't
// know what size it really asked for, e.g., when it uses logical sizes like
// "small" or expresses the font-size as a percentage of the user's default
// font setting.
// With the smart minimum, we never want to get smaller than the minimum font
// size to keep fonts readable. However we always allow the page to set an
// explicit pixel size that is smaller, since sites will mis-render otherwise
// (e.g., http://www.gamespot.com with a 9px minimum).
3. For the curious, what are these minimum values when given relative units (eg x-small
)?
// Strict mode table matches MacIE and Mozilla's settings exactly.
static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin +
1][totalKeywords] = {
{9, 9, 9, 9, 11, 14, 18, 27}, {9, 9, 9, 10, 12, 15, 20, 30},
{9, 9, 10, 11, 13, 17, 22, 33}, {9, 9, 10, 12, 14, 18, 24, 36},
{9, 10, 12, 13, 16, 20, 26, 39}, // fixed font default (13)
{9, 10, 12, 14, 17, 21, 28, 42}, {9, 10, 13, 15, 18, 23, 30, 45},
{9, 10, 13, 16, 18, 24, 32, 48} // proportional font default (16)
};
// HTML 1 2 3 4 5 6 7
// CSS xxs xs s m l xl xxl
// |
// user pref
Interestingly, and a bit of an aside, the FontBuilder
class dispatches to TextAutosizer :: computeAutosizedFontSize to scale the font size. This method uses hard coded values and a variable scaling factor:
// Somewhat arbitrary "pleasant" font size.
const float pleasantSize = 16;
// Multiply fonts that the page author has specified to be larger than
// pleasantSize by less and less, until huge fonts are not increased at all.
// For specifiedSize between 0 and pleasantSize we directly apply the
// multiplier; hence for specifiedSize == pleasantSize, computedSize will be
// multiplier * pleasantSize. For greater specifiedSizes we want to
// gradually fade out the multiplier, so for every 1px increase in
// specifiedSize beyond pleasantSize we will only increase computedSize
// by gradientAfterPleasantSize px until we meet the
// computedSize = specifiedSize line, after which we stay on that line (so
// then every 1px increase in specifiedSize increases computedSize by 1px).
const float gradientAfterPleasantSize = 0.5;
From these facts, we see there are a good number of hard-coded pixel values, with 9
and 16
being commonly sprinkled about the relevant code. These hard-codes, the presence of several rules to scale the font down to a limit, with the ability to override using font-size all seem to match the observations and suggest it's behaving as intended -- if not necessarily intuitively.
Also, I've found that the most recent comment posted in Chrome bug #319623 very much resembles your report.
Possibly related: when using relative units on the html tag, rem-based values defined elsewhere will have a lower bound of 9px.
See CodePen: http://codepen.io/larrybotha/pen/wKYYXE
Workaround: absolute unit on html, em unit on body. rems everywhere else.
It may be prudent to watch that bug for further developments, though maybe not with breath held. The last update was in 2015.
1
Good research and write-up. While I can't say that I fully grok Blink's logic, based on the problem and the code you shared here, I agree with your conclusion.
– Stephen Watkins
Jan 4 at 17:51
Glad it helped, @StephenWatkins. I hope this analysis is at least in the ball-park, but I'd love a Chrome expert to phone in: this all seems a bit hacky to me.
– bishop
Jan 4 at 18:08
add a comment |
Chrome and its Blink rendering engine seem to have some non-obvious font-scaling rules. I'm unaware of any official comprehensive documentation, so let's go to the source.
(Note that I'm not an expert on Chromium internals generally or Blink renderer particularly. I've just been tracing through the source code and speculating on the most probable answers to the questions as posed.)
It seems to me that the engine calls upon the FontBuilder
class during a redraw. This class has various dispatch methods that pass the DOM, zoom, and other relevant factors into what appears to be the crucial method: FontSize :: getComputedSizeFromSpecifiedSize
. In that method, we see some juicy comments that address the points you've raised:
1. Why does setting font-size: 0;
to a parent element fix it?
// Text with a 0px font size should not be visible and therefore needs to be
// exempt from minimum font size rules. Acid3 relies on this for pixel-perfect
// rendering. This is also compatible with other browsers that have minimum
// font size settings (e.g. Firefox).
2. Why is it not honoring the rem size below a certain threshold?
// We support two types of minimum font size. The first is a hard override
// that applies to all fonts. This is "minSize." The second type of minimum
// font size is a "smart minimum" that is applied only when the Web page can't
// know what size it really asked for, e.g., when it uses logical sizes like
// "small" or expresses the font-size as a percentage of the user's default
// font setting.
// With the smart minimum, we never want to get smaller than the minimum font
// size to keep fonts readable. However we always allow the page to set an
// explicit pixel size that is smaller, since sites will mis-render otherwise
// (e.g., http://www.gamespot.com with a 9px minimum).
3. For the curious, what are these minimum values when given relative units (eg x-small
)?
// Strict mode table matches MacIE and Mozilla's settings exactly.
static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin +
1][totalKeywords] = {
{9, 9, 9, 9, 11, 14, 18, 27}, {9, 9, 9, 10, 12, 15, 20, 30},
{9, 9, 10, 11, 13, 17, 22, 33}, {9, 9, 10, 12, 14, 18, 24, 36},
{9, 10, 12, 13, 16, 20, 26, 39}, // fixed font default (13)
{9, 10, 12, 14, 17, 21, 28, 42}, {9, 10, 13, 15, 18, 23, 30, 45},
{9, 10, 13, 16, 18, 24, 32, 48} // proportional font default (16)
};
// HTML 1 2 3 4 5 6 7
// CSS xxs xs s m l xl xxl
// |
// user pref
Interestingly, and a bit of an aside, the FontBuilder
class dispatches to TextAutosizer :: computeAutosizedFontSize to scale the font size. This method uses hard coded values and a variable scaling factor:
// Somewhat arbitrary "pleasant" font size.
const float pleasantSize = 16;
// Multiply fonts that the page author has specified to be larger than
// pleasantSize by less and less, until huge fonts are not increased at all.
// For specifiedSize between 0 and pleasantSize we directly apply the
// multiplier; hence for specifiedSize == pleasantSize, computedSize will be
// multiplier * pleasantSize. For greater specifiedSizes we want to
// gradually fade out the multiplier, so for every 1px increase in
// specifiedSize beyond pleasantSize we will only increase computedSize
// by gradientAfterPleasantSize px until we meet the
// computedSize = specifiedSize line, after which we stay on that line (so
// then every 1px increase in specifiedSize increases computedSize by 1px).
const float gradientAfterPleasantSize = 0.5;
From these facts, we see there are a good number of hard-coded pixel values, with 9
and 16
being commonly sprinkled about the relevant code. These hard-codes, the presence of several rules to scale the font down to a limit, with the ability to override using font-size all seem to match the observations and suggest it's behaving as intended -- if not necessarily intuitively.
Also, I've found that the most recent comment posted in Chrome bug #319623 very much resembles your report.
Possibly related: when using relative units on the html tag, rem-based values defined elsewhere will have a lower bound of 9px.
See CodePen: http://codepen.io/larrybotha/pen/wKYYXE
Workaround: absolute unit on html, em unit on body. rems everywhere else.
It may be prudent to watch that bug for further developments, though maybe not with breath held. The last update was in 2015.
Chrome and its Blink rendering engine seem to have some non-obvious font-scaling rules. I'm unaware of any official comprehensive documentation, so let's go to the source.
(Note that I'm not an expert on Chromium internals generally or Blink renderer particularly. I've just been tracing through the source code and speculating on the most probable answers to the questions as posed.)
It seems to me that the engine calls upon the FontBuilder
class during a redraw. This class has various dispatch methods that pass the DOM, zoom, and other relevant factors into what appears to be the crucial method: FontSize :: getComputedSizeFromSpecifiedSize
. In that method, we see some juicy comments that address the points you've raised:
1. Why does setting font-size: 0;
to a parent element fix it?
// Text with a 0px font size should not be visible and therefore needs to be
// exempt from minimum font size rules. Acid3 relies on this for pixel-perfect
// rendering. This is also compatible with other browsers that have minimum
// font size settings (e.g. Firefox).
2. Why is it not honoring the rem size below a certain threshold?
// We support two types of minimum font size. The first is a hard override
// that applies to all fonts. This is "minSize." The second type of minimum
// font size is a "smart minimum" that is applied only when the Web page can't
// know what size it really asked for, e.g., when it uses logical sizes like
// "small" or expresses the font-size as a percentage of the user's default
// font setting.
// With the smart minimum, we never want to get smaller than the minimum font
// size to keep fonts readable. However we always allow the page to set an
// explicit pixel size that is smaller, since sites will mis-render otherwise
// (e.g., http://www.gamespot.com with a 9px minimum).
3. For the curious, what are these minimum values when given relative units (eg x-small
)?
// Strict mode table matches MacIE and Mozilla's settings exactly.
static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin +
1][totalKeywords] = {
{9, 9, 9, 9, 11, 14, 18, 27}, {9, 9, 9, 10, 12, 15, 20, 30},
{9, 9, 10, 11, 13, 17, 22, 33}, {9, 9, 10, 12, 14, 18, 24, 36},
{9, 10, 12, 13, 16, 20, 26, 39}, // fixed font default (13)
{9, 10, 12, 14, 17, 21, 28, 42}, {9, 10, 13, 15, 18, 23, 30, 45},
{9, 10, 13, 16, 18, 24, 32, 48} // proportional font default (16)
};
// HTML 1 2 3 4 5 6 7
// CSS xxs xs s m l xl xxl
// |
// user pref
Interestingly, and a bit of an aside, the FontBuilder
class dispatches to TextAutosizer :: computeAutosizedFontSize to scale the font size. This method uses hard coded values and a variable scaling factor:
// Somewhat arbitrary "pleasant" font size.
const float pleasantSize = 16;
// Multiply fonts that the page author has specified to be larger than
// pleasantSize by less and less, until huge fonts are not increased at all.
// For specifiedSize between 0 and pleasantSize we directly apply the
// multiplier; hence for specifiedSize == pleasantSize, computedSize will be
// multiplier * pleasantSize. For greater specifiedSizes we want to
// gradually fade out the multiplier, so for every 1px increase in
// specifiedSize beyond pleasantSize we will only increase computedSize
// by gradientAfterPleasantSize px until we meet the
// computedSize = specifiedSize line, after which we stay on that line (so
// then every 1px increase in specifiedSize increases computedSize by 1px).
const float gradientAfterPleasantSize = 0.5;
From these facts, we see there are a good number of hard-coded pixel values, with 9
and 16
being commonly sprinkled about the relevant code. These hard-codes, the presence of several rules to scale the font down to a limit, with the ability to override using font-size all seem to match the observations and suggest it's behaving as intended -- if not necessarily intuitively.
Also, I've found that the most recent comment posted in Chrome bug #319623 very much resembles your report.
Possibly related: when using relative units on the html tag, rem-based values defined elsewhere will have a lower bound of 9px.
See CodePen: http://codepen.io/larrybotha/pen/wKYYXE
Workaround: absolute unit on html, em unit on body. rems everywhere else.
It may be prudent to watch that bug for further developments, though maybe not with breath held. The last update was in 2015.
edited Jan 3 at 2:55
answered Jan 2 at 20:40


bishopbishop
24.8k56892
24.8k56892
1
Good research and write-up. While I can't say that I fully grok Blink's logic, based on the problem and the code you shared here, I agree with your conclusion.
– Stephen Watkins
Jan 4 at 17:51
Glad it helped, @StephenWatkins. I hope this analysis is at least in the ball-park, but I'd love a Chrome expert to phone in: this all seems a bit hacky to me.
– bishop
Jan 4 at 18:08
add a comment |
1
Good research and write-up. While I can't say that I fully grok Blink's logic, based on the problem and the code you shared here, I agree with your conclusion.
– Stephen Watkins
Jan 4 at 17:51
Glad it helped, @StephenWatkins. I hope this analysis is at least in the ball-park, but I'd love a Chrome expert to phone in: this all seems a bit hacky to me.
– bishop
Jan 4 at 18:08
1
1
Good research and write-up. While I can't say that I fully grok Blink's logic, based on the problem and the code you shared here, I agree with your conclusion.
– Stephen Watkins
Jan 4 at 17:51
Good research and write-up. While I can't say that I fully grok Blink's logic, based on the problem and the code you shared here, I agree with your conclusion.
– Stephen Watkins
Jan 4 at 17:51
Glad it helped, @StephenWatkins. I hope this analysis is at least in the ball-park, but I'd love a Chrome expert to phone in: this all seems a bit hacky to me.
– bishop
Jan 4 at 18:08
Glad it helped, @StephenWatkins. I hope this analysis is at least in the ball-park, but I'd love a Chrome expert to phone in: this all seems a bit hacky to me.
– bishop
Jan 4 at 18:08
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53856831%2frem-font-size-not-adjusting-below-arbitrary-threshold%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
When you add the vendor prefix of
-webkit-text-size-adjust: none
still no love?– Chris W.
Dec 19 '18 at 18:06
Still no love with the vendor prefixed
-webkit-text-size-adjust: none;
.– Stephen Watkins
Dec 19 '18 at 18:09
this is a known feature, I will try to find the duplicate question
– Temani Afif
Dec 19 '18 at 19:24
1
I believe this is a duplicate of stackoverflow.com/questions/21302069/… but I can't close vote due to the bounty.
– zzzzBov
Jan 2 at 19:49
1
This is not a duplicate of stackoverflow.com/questions/21302069/…. The minimum font size on the browser is set to
6px
, but it isn't being honored withrem
units. For instance, I can set the font size to6px
if I usepx
explicitly, but not lower than6px
, as expected. This is a different problem.– Stephen Watkins
Jan 2 at 21:52