How are fonts sized when specifying "px" in CSS? [duplicate] - html

This question already has answers here:
What does font-size really correspond to?
(2 answers)
Closed 4 years ago.
I'm trying to pin down exactly what px means to font-size in terms of allocated space on the page, and the results I'm getting don't match my expectations.
I was under the impression that using pixels in conjunction with font-size meant that the vertical space taken up by the typography would match the value specified. For example, if I specified font-size: 16px, a line of text with that rule applied would have a height of 16px. Please note that I was not expecting the actual glyph to be 16px in height, but that the browser would allocate 16px to display the glyphs.
Here's some code to use as a reference so I can explain what I expected to see vs. what I'm actually seeing:
.style-it {
box-sizing: border-box;
margin: auto;
width: 500px;
height: 500px;
border: 5px solid black;
padding: 20px;
font-size: 150px;
font-family: sans-serif;
}
<html>
<div class="style-it">
<div>
CSS
</div>
<div>
IS
</div>
<div>
AWESOME
</div>
</div>
</html>
I have a static height of 500px set on my style-it div, which has a 5px border and 20px padding. Therefore, the content of my div has a height of 450px. With my previous understanding of font-size and px, I would expect three lines of text at a font-size of 150px to fill that 450px of content perfectly, but that isn't the case.
I've placed each line of text into their own div so we can clearly see that each line is slightly larger (173px in Chrome) than my 150px specification.
So, what's going on here? Is it that the glyphs themselves actually are 150px in height and the "box" around them adjusts arbitrarily based on some internal browser rule?
Is there a way that I would be able to know for sure that "I have container that is Xpx tall and I can fit Y lines of text perfectly in there by setting their font-size to Zpx"?
Just an interesting problem that I came across that I couldn't find a good answer to. I don't know if it's terribly useful in the real world, but I was interested to see if anyone could answer nonetheless.
EDIT: I should have been a little clearer on what I was asking. I'm not having trouble figuring out how to fit the text inside the div, but rather interested in why, as the duplicate linked article states, the font-size value is not the same size as the em-square. In other words, why is specifying a line-height of 1em even necessary in a situation like this?
For anyone who comes across this, the linked question has a great article that is just the sort of thing I was looking for: http://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align#lets-talk-about-font-size-first

Your line is not exactly 150px in height because line-height and text-size are two different things.
Use the CSS property line-height and set it to 1em (which means that the line height will be the same size as the text size), and your content will be exactly 450px in height.
.style-it {
box-sizing: border-box;
margin: auto;
width: 500px;
height: 500px;
border: 5px solid black;
padding: 20px;
font-size: 150px;
line-height: 1em; /* add this line */
font-family: sans-serif;
}
<html>
<div class="style-it">
<div>
CSS
</div>
<div>
IS
</div>
<div>
AWESOME
</div>
</div>
</html>

Related

Fractional border width sometimes causes a 1px "padding", how to fix?

To create a rounded rectangle with a 3D-like effect, I have a div inside a div, as follows:
* {
box-sizing: border-box;
}
body {
font-size: 0.948px;
}
.outer {
font-size: inherit;
width: 20em;
height: 26em;
background: #fc6;
border: 1.4em solid #bad9d9;
border-radius: 3.98em;
line-height: 20.8em;
text-align: center;
}
.inner {
font-size: 8.64em;
height: 87%;
background: #fff;
border-radius: 2.844px;
}
<div class="outer">
<div class="inner">768</div>
</div>
In this code, I am trying to create this, but depending on the exact value of div.outer's font-size (set via JavaScript), a 1-pixel padding sometimes develops at the top and/or sides of the outer rectangle, as shown here. I believe this is caused by the browser rounding the fractional border width up for positioning elements, but rounding it down when drawing it on the screen. This effect (bug?) occurs in Chrome and Edge, but not Firefox.
Edit: I would like to clarify that almost all the styles are dynamically updated via JavaScript (this is part of a larger project). The border-width could shrink to 0em or expand to 4em, and I am looking for a workaround to this bug (I believe it is a rendering bug) that works for any border-width.
My question: is there a way to fix this without
Using JavaScript to convert from em values to rounded px values?
Using a third element to draw the border (pseudo- or otherwise)?
Gallery:
- original
- at 500% zoom
- with the border-width at 1.0em
- with the border-width at 0.8em (what I want)
- with the border removed
(all screenshots scaled up using Chrome's trackpad pinch-zoom)
This is a known and reported issue, but currently this is considered low priority by the Chromium development team, so there's not much hope this will be fixed any time soon, if ever.
Here's the change that causes this: Use floor instead of round for decimal border widths; here's an explainer for the change.
Adding your case and a reproducer to that issue might help.
I would prefer not to mix different types of Units use em everywhere.
In addition, make the inner width 100% so it always fills the outer and does not have extra space of the outer visible.

make link text same height as link background

Seems simple but I can't seem to do it, I would like to make the text of my link the same height as the background of the link.
<a href='link.htm' style='background-color: red; display: block; height: 30px; font-size: 30px;'>Link text</a>
The problem is there is always a margin around the text
I think it's because you are using text-decoration: underline.
If you remove height: 30px, the block will rezise to the size of font.
Here are examples: Width static height , Removed height property.
Or you can set text-decoration: none and then it will fit the block.
It it what you wanted? If not, please provide some screenshots with explanation.
The font-size doesn't reflect the physical height that the text occupies, you have to account for descenders as well. You could set the line-height:
<a href='link.htm' style='background-color: red; display: block;
height: 30px; font-size: 30px; line-height: 30px;'>Link text</a>
(You should use a stylesheet rather than inline styles, although this perhaps is just to demonstrate the issue?)
Setting the line-height does make the height setting redundant for this small example though and, usually, the line-height is larger than the font size, defaulting to roughly 1.2.

Why is 1em shorter than the default font size?

I was doing some experiments, and then I ran into this issue. I sat a div's height to 1em, and I expected the div to contain the whole height of the text within, but it did not. 1em is my browser is 16px.
When I did not specify the div's height, it successfully contained the whole height of the text, and when inspected, it turned to be of height 19px.
Is my understanding of em wrong, as I thought it should represent the default font height of the browser.
div {
margin: 0;
padding: 0;
}
.first {
height: 1em;
background: green;
}
.second {
background: orange;
}
<div class="first">سلامًا Say I Wantأًّ</div>
<br />
<div class="second">سلامًا Say I Wantأًّ</div>
https://jsfiddle.net/9t43kyu2/1/
The typographical line-height of a text isn't surely the actual height of the rendered text in pixels:
The line-height css parameter of a text contains only the height between "caps height" and the "baseline". It is on most cases 1em on my experience and also on most non-standard sources of the net. But its standardized details are better described in #web-tiki 's answer.
If there are characters which have parts over it or below it, they will result a text whose height (in pixels) is bigger as the line height (in pixels).
The text can have small details which are below or over the standard text line. For example, the lowest part of an y, or the uppest parts of a non-ascii Ű character. These causes continously problems in the positioning.
If you don't set the div height, it will be by default auto, which mean, the whole content will be in it. If you specify the div height to the actual line size, without padding, border and margin, then some pixel of your text will maybe overflow. You only didn't see it, because the default value of the overflow css-parameter is visible.
Best test for that: create a div with the following settings:
#divId {
height: 1em;
line-height: 1em;
overflow: hidden;
}
...and copy-paste an yŰ into its content (but characters are also okay). You will see it clipped on both sides.
The fact that the second div is higher is because of the default line-height property. It's default value is normal.
normal
Tells user agents to set the used value to a "reasonable" value
based on the font of the element. The value has the same meaning as
. We recommend a used value for 'normal' between 1.0 to 1.2.[...] [source w3.org]
This makes your second div ~=1.2em high depending on your user agent. You can set it's line-height:1em; to see the difference :
div {
margin: 0;
padding: 0;
}
.first {
height: 1em;
background: green;
}
.second {
background: orange;
line-height: 1em;
}
<div class="first">سلامًا Say I Wantأًّ</div>
<br />
<div class="second">سلامًا Say I Wantأًّ</div>

Resize text based on div resizing?

To start things off, here is my code:
.header{
width: 100%;
height: 10%;
background-color: #FF4545;
}
.headertext{
font-family: 'Duru Sans', sans-serif;
font-size: 65px;
float:left;
margin-top: 0px;
margin-bottom: 0px;
}
.headermenu{
font-family: 'Duru Sans', sans-serif;
font-size: 65px;
float: right;
margin-top: 0px;
margin-bottom: 0px;
}
So both the .headertext and the .headermenu are html p statements that are embedded within the .header div. Now, the .header div has a bg color. When I resize my window, the div resizes (very clearly with the bg color) however the text does not resize. It makes sense that the text doesn't resize given that I have assigned a concrete font size for them. I wanted to ask how I can have the font size dynamically scale so that the text is always kept within the div? At this point it pokes out the bottom when you resize, meaning half the text is within the bg colored div and half of it is sticking out into whitespace. I hope this is clear enough, thanks!
Try to use change it like this:
1) Add "font-size: 65px;" to the class ".header"
2) Replace the definition of font-size in the class ".headertext" and ".headermenu" by "font-size: 1em;"
Thus, the child will get the same size of the parent node. Therefore, when the parent is resized, the children nodes will be resized too.
Defining your font size in pixels makes them definite sizes instead of something that will scale well with a fluid layout. Define your fonts in em instead of pixels. To find the proper em size you divide the font size by 16 which is the standard font size for browsers. For instance, your font size of 65 pixels would become 4.0625em (65 / 16 = 4.0625).
I think there is no CSS way to make font-size smoothly scale on window resize.
You might try CSS Media Query too set font-size relative to specific widths/heights
See example: http://jsfiddle.net/Ww4hB/
Otherwise, you need JavaScript to update font size on page load and window resize.
edit:
There is also something called viewport unit, but it isn't supported in all browsers.
See more: http://css-tricks.com/viewport-sized-typography/

Can i exactly set distance between div and div with text?

Suppose, I have two div's: first - rectangle, filled yellow color and second with text "World wide web" and font-size 46px. I need set distance 39px between bottom of first div and top of the capital letter "W" in second div. I set margin bottom 39px in first div's CSS rule, and measure result on the screen. I got 43px. Can I exactly set this distance? (of cource, I can tune margin of first div and make several attempts to set this distance, but I need another way). Sorry for my English.
<!doctype html>
<html>
<head>
<title>
test page
</title>
<style>
html {
line-height: 1;
}
#first {
background-color: yellow;
height: 200px;
margin-bottom: 39px;
width: 200px;
}
#second {
font-family: "Myriad Pro";
font-size: 46px;
}
</style>
</head>
<body>
<div id = "first">
</div>
<div id = "second">
World wide web
</div>
</body>
</html>
You might need to set the padding of the text in the second div to {padding: 0}. Any padding that you have not accounted for will increase the appearance of the margin. Have you tried adding a background-color to #second and then measuring the margin?
I think that the space is part of the font. The size of second div, font-size and line-height all are 46px. Also, the space between them is also 39px as you can see here. So, if you want to set the space to be exactly 39px, you might have to search for or make a font which doesn't has that extra space.
OR
you can set line-height: 30px; in second div, which will move it upward. But as value depends on font-size, you will have to change it whenever you change font-size. Maybe using ems can solve that issue
EDIT
Values in em would be:
font-size: 2.87em;
line-height: 0.655em;
Now changing font-size in em to any value will keep the gap to 39px, i.e. margin-bottom of div#first
DEMO