Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to make text characters flush to the top of their bounding box in HTML5?

Here is a Label element in HTML and the red dotted outline shows it's bounding box. Notice that the characters are not flush with the top edge of their bounding box:

line-height:1.2; /* default */

enter image description here
Here is the JSFiddle showing the image above http://jsfiddle.net/6gLQU/16/.

Here is the same text where the line-height style is set to 1 or 100% (it is better but still not flush):

line-height:1;

enter image description here

Finally, if I set the line-height style to .8 (80%), as in this code example, it is flush except for a small but acceptable single pixel difference in the last test text. This is great but if there is more than one line of text (multiline) then the next line is pulled up too high because that makes each line height 80% of it's actual height.

line-height:.8;

enter image description here

Here is the JSFiddle code http://jsfiddle.net/6gLQU/16/.


(You can skip this paragraph if you don't know Flash) In Flash TLF (FTE or Flash Text Engine) if you add a text field, using FTE or TLF as it's engine, the text characters are aligned flush to the very top of the bounding rectangle. They look like the text in the last picture (the characters are snug up against the top border of the bounding box).


In HTML the text character is not aligned flush to the top of the bounding rectangle as shown in the examples above. When you increase the font size you also increase the gap from the top of the character to the top of the bounding box rectangle.

In my research in the text used in HTML and CSS the font style line-height will adjust the position of the characters of text inside their bounding box (as shown in the pictures above). In Flash the line-height style does not affect the characters in the first line of text but does adjust the following lines as well as in HTML (so it does not work in HTML or Flash for multiline).

I've determine that if I set line-height to .8 or 80% in HTML the font fits flush up against the top of the bounding box (as shown above). Great! That's what I want but it does not work for multiple lines of text. If there is more than one line, the next line is "pulled up" and overlaps the preceding line because, obviously, I'm giving each line only 80 percent of it's actual height.


Anyway, my question is:

  1. Is there an alternative approach that I can use to make HTML characters flush to the top of the bounding box? The hack that I am using with line-height causes multiple lines of text to be too close together.
  2. Is there a setting in Flash TLF to make it behave and appear like an HTML text line? That is, make it so it doesn't pull up the text characters to the top of the bounding box (match HTML layout rules).

I found an alternative that uses a negative margin space but I must manually enter it. It's not ideal because it's a different value for each font size (found by trial and error) and it moves the text box up, not the characters. With the line-height hack I can use .8 and I know it will be positioned correct.

Here is a link to the code and picture using negative margin. I only applied it to the last element. Notice the red border:

font-size:64px;
line-height:1.2;
margin-top:-14px;

enter image description here

Here is another test and another using multiples of 12 using negative margin percentage. Again, each negative margin value is different and found by trial and error:

font-size:12px;
line-height:1.2;
margin-top:-.19%;

enter image description here

Here is information on the FTE engine. I read it for an hour and I realize now I know a few of those words.

PS Sorry this question is so long. I'm trying to win the longest post award, apparently. Also, I added two questions because there is the actual problem and then there is the workaround question that might not be necessary if the actual problem is solvable. I'm not sure what this is called but someone told me it's a common thing with programming questions on SO. Also, adding the Firefox tag since it's running in Firefox and one of the Firefox developers might see it and know how this all works.

Update 2019:
I have another question posted about this somewhere but the accepted fix works for specific fonts but not every font.

IIUC The top edge of the text character, called a glyph, is called the caps height and the height of the container around the glyph is the em height. The caps heights are different for each font since fonts are different styles and created by different authors.

IIUC Browsers don't position according to em or font size and caps height is not considered.

A feature request I have for browsers would be to support aligning the first line of a text of a paragraph or label at the caps height so the text is flush to the top edge. That might be a negative text margin. This would make browsers accurately reproduce what many design tools support.

// something like any of these: 
align-caps-height: true;  
first-line-position: caps-height;
margin-top: caps-height;
like image 613
1.21 gigawatts Avatar asked Oct 31 '22 10:10

1.21 gigawatts


1 Answers

Font spacing is not the problem here because text gets scaled evenly. The problem is created by margin in percentage. Percent margins are calculated as percent of width. So as you can expect, there will be no relation between the percent margin and

Method I

What you can do is, find the margin in pixel for one block. Then let k = font_size/ margin for that block. Divide font-size by k to get margin of other blocks.


Method II

Instead of using percent margin, try using transform: translate; using em values:

Relevant code

label { /* added properties*/
  transform: translateY(-0.2em);
}

Updated Fiddle 1


Method III

I realized, bit late though, that transform is not required. You can simply use margin-top: -0.2em;

Relevant code

label { /* added properties*/
  margin-top: -0.2em;
}

Updated Fiddle 2

#BorderContainer1711  {
	position:absolute;
	left:32px;
	top:60px;
	width:500px;
	height:160px;
	background-color:#FFFFFF;
	background-alpha:1;
	border-width:1px;
	border-style:solid;
	border-color:#00DD00;
	color:#000000;
}

label { /* added properties*/
   margin-top: -0.2em;
}

#Label1551  {
	position:absolute;
	left:46px;
	top:60px;
	color:#000000;
	font-weight:normal;
	font-family:Arial;
	font-size:12px;
}

#Label1613  {
	position:absolute;
	left:123px;
	top:60px;
	width:61px;
	color:#000000;
	font-weight:normal;
	font-family:Arial;
	font-size:24px;
}

#Label937  {
	position:absolute;
	left:220px;
	top:60px;
	color:#000000;
	font-weight:normal;
	font-family:Arial;
	font-size:36px;
}

#Label2125  {
	position:absolute;
	left:342px;
	top:60px;
	color:#000000;
	font-weight:normal;
	font-family:Arial;
	font-size:64px;
}



*, *:before, *:after {
  -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
}


*, *:before, *:after {
  outline:1px dotted red;
}
	<div id="BorderContainer1711">

	</div>
	<label id="Label1551">[12px]</label>
	<label id="Label1613">[24px]</label>
	<label id="Label937">[36px]</label>
	<label id="Label2125">[64px]<br>nextline</label>
like image 135
Max Payne Avatar answered Nov 15 '22 05:11

Max Payne