6

I have a form where I use several plus and minus buttons to add new elements to the form as needed by the user. I've used a custom button style. I've used this site to get the necessary css to make sure the text is centered. But this only seems to work in some instances of the button.

function unhide(id) {
  var myForm = document.forms.mrform;
  var myControls = myForm.elements[id.concat('[]')];
  for (var i = 0; i < myControls.length; i++) {
    var aControl = myControls[i];
    if ($(aControl).is(':hidden')) {
      $("#".concat(id.concat(i+1).replace(/ /g, "_"))).show();
   break;
    }
  }
}

function hide(id) {
  var myForm = document.forms.mrform;
  var myControls = myForm.elements[id.concat('[]')];
  for (var i = myControls.length; i > 0 ; i--) {
    var aControl = myControls[i];
    if ($(aControl).is(':visible')) {
      $("#".concat(id.concat(i+1).replace(/ /g, "_"))).hide();
   break;
    }
  }
}
.pmbutton {
  background-color: greenyellow;
  border: none;
  color: black;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 10px;
  height: 17px;
  width: 17px;
  padding: 0px;
  margin: 0px 0px 0px 4px;
  vertical-align: middle;
  line-height: 17px;
  box-sizing: border-box;
}

.hideme {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id='mrform' action='report_generator.php' method='post' autocomplete='off' onkeypress='return event.keyCode != 13;'>
<table class='subform'>
  <tr id='Objective_Item1'><td class='prompt text'>Objective Item #1 :</td><td class='input'><input class='inputbox text' type='text' name='Objective Item[]'><button type='button' class='pmbutton' onclick='unhide("Objective Item")'>+</button><button type='button' class='pmbutton' onclick='hide("Objective Item")'>-</button></td></tr>
  <tr id='Objective_Item2' class='hideme'><td class='prompt text'>Objective Item #2 :</td><td class='input'><input class='inputbox text' type='text' name='Objective Item[]'></td></tr>
  <tr id='Objective_Item3' class='hideme'><td class='prompt text'>Objective Item #3 :</td><td class='input'><input class='inputbox text' type='text' name='Objective Item[]'></td></tr>
  <tr id='Objective_Item4' class='hideme'><td class='prompt text'>Objective Item #4 :</td><td class='input'><input class='inputbox text' type='text' name='Objective Item[]'></td></tr>
  <tr id='Objective_Item5' class='hideme'><td class='prompt text'>Objective Item #5 :</td><td class='input'><input class='inputbox text' type='text' name='Objective Item[]'></td></tr>
  <tr id='Objective_Item6' class='hideme'><td class='prompt text'>Objective Item #6 :</td><td class='input'><input class='inputbox text' type='text' name='Objective Item[]'></td></tr>
  <tr id='Objective_Item7' class='hideme'><td class='prompt text'>Objective Item #7 :</td><td class='input'><input class='inputbox text' type='text' name='Objective Item[]'></td></tr>
  <tr id='Objective_Item8' class='hideme'><td class='prompt text'>Objective Item #8 :</td><td class='input'><input class='inputbox text' type='text' name='Objective Item[]'></td></tr>
  <tr id='Objective_Item9' class='hideme'><td class='prompt text'>Objective Item #9 :</td><td class='input'><input class='inputbox text' type='text' name='Objective Item[]'></td></tr>
  <tr id='Objective_Item10' class='hideme'><td class='prompt text'>Objective Item #10 :</td><td class='input'><input class='inputbox text' type='text' name='Objective Item[]'></td></tr>
</table>
</form>

The functionality is fine, but the text is not vertically centered in the button in some instances and IS in others. Seems to be a single pixel off in random buttons. I've viewed it in Firefox and Chrome (which seems to be worse). Any suggestions as to the cause?

Edit: Adding an image of several renderings of the same button on one page of the site. The only property I change between some of them is the background color. Both vertical and horizontal alignment vary, it seems.

Button Renderings

Additional Button renderings

Lee Blake
  • 341
  • 1
  • 2
  • 15

5 Answers5

7

Before you read. I am not a font professional and I'm giving the answer based on my several hours research on the topic. I might be wrong in some places and I will gladly accept any improvement of the answer.

TL;DR

In my opinion, your safest approach would be to create images of + and and use them as buttons instead.


How fonts work

To answer your question you need to know how fonts work first.

Each character in the font is fitted into its own space container. In traditional metal type this container was the actual metal block of each character. The height of each character piece was uniform, allowing the characters to be set neatly into rows and blocks. This space is called "em-space" and it originates from the width of the uppercase M character. It was made so that the proportions of this letter would be square.

In digital type, em-space is defined like so:

  • In an OpenType font it is usually set at 1000 units.
  • In TrueType fonts it is by convention a power of two, generally set to 1024 or 2048 units.

When the font is used to set type, the em is scaled to the desired point size.

Each character in your font also has these elements:

  • Baseline is the line which defines the bottom of the character. With certain exceptions like g and q characters do not cross the baseline.
  • Cap height is the line which defines the top of a capital letter. Those are usually flat letters like H or I, whilst O or A might overshoot.
  • X-height is the height of a lower-case letter. Typically, this is the height of the letter x in the font, hence the name.
  • Ascender is the part of a lower-case letter that is taller than the font's x-height. Think of b and d characters.
  • Descender is the portion of a letter that extends below the baseline of a font. I already mentioned g and q.

All those elements are contained inside em-space.

Now, what happens when you try to scale the font down to 10px (based on your font-size: 10px; setting). Unless you changed your browser settings, the browser default font size is 16px (1 em = 2048 units for Times New Roman you seemingly use).

But Times New Roman uses 1825 ascent and 443 descent, which makes 2268 units in a 2048 unit em-square on Windows. Mac seems to use the HHead values, which are the same for Times New Roman. Here's the screenshot showing those values:

Times New Roman font info

What does it mean? It means that when you specify font-size: 10px the actual size of Times New Roman would be absolutely different. If I'm right with my calculations, it would be 11.07421875 rounded down to 11px (already an "ouch", right?)

line-height and vertical-align

Okay, next, when your button is rendered on screen, it can be composed of many lines, according to its width. Each line is made up of one or many inline elements (eg. span elements with different font settings) and is called a line-box. The height of a line-box is based on its children’s height. The browser computes the height for each inline element and chooses the tallest child as the "template" for the line-box. This ensures you see all the characters on your screen when the element is rendered.

This behavior differs from Word or Photoshop. In those programs, line-height is not based on line-box. Instead it is the distance between baselines. But in CSS it is not. In css your line-height is your line-box.

It should be noted, that CSS does not specify default value of line-height. Default value is 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. The computed value is 'normal'.

And this is the specs for vertical-align:

This property affects the vertical positioning inside a line box of the boxes generated by an inline-level element.

From all the information above we can conclude, that it's the content-area being centered vertically, not the character purely.

Indeed

I've checked + and - in font editing software and it looks like this:

Plus and Hyphen in Times New Roman

While + seems symmetrical, it's still lowered a bit inside it's content area; and - is lowered down towards baseline. So the answer for - is obvious. Based on everything I've researched and posted above - you will not be able to center it vertically, it will always be slightly lower. On small font sizes it might be a pixel or two; on huge font size you will see it right away.

Note, that the - you are used to typing (top right key on num pad; or key right of 0) is not minus, it's hyphen. Minus and hyphen looks differently: vs. -.

Would − (minus) look differently? It surely has more symmetry to it:

Plus and Minus in Times New Roman

Here you can see more clearly, that + and − (minus) are closer to the base line.

Flexboxes as possible solution?

Let's take a look at flexbox. When you define display: flex, a box is generated called flex container. In-flow children of a flex container are called flex items and are laid out inside flex lines.

Unlike block and inline layout, whose layout calculations are biased to the block and inline flow directions, flex layout is biased to the flex directions.

flex container and flex items

Now, flex lines, apart from line-boxes, work differently:

Once content is broken into lines, each line is laid out independently; flexible lengths and the justify-content and align-self properties only consider the items on a single line at a time.

In a multi-line flex container (even one with only a single line), the cross size of each line is the minimum size necessary to contain the flex items on the line (after alignment due to align-self), and the lines are aligned within the flex container with the align-content property. In a single-line flex container, the cross size of the line is the cross size of the flex container, and align-content has no effect. The main size of a line is always the same as the main size of the flex container’s content box.

So, when you define align-items: center,

The flex item’s margin box is centered in the cross axis within the line.

And finally, if I understood the specification correctly, when you specify align-items: center, the baseline is generated dynamically, allowing you to actually perfectly center the + and .

In conclusion

You should use flexboxes and use div, not a button, as button seems to behave differently (I'd welcome a documented suggestion why). Even though if you specify huge numbers (like width and height to 400px and font-size to 750px) you will see slight shifting towards the bottom. But on small sizes everything seems to work perfectly.

In my opinion, your safest approach would be to create images of + and and use them as buttons instead.


Sources I researched:

App to show the font info - https://fontforge.github.io/en-US/

Kevin Kopf
  • 13,327
  • 14
  • 49
  • 66
  • 2
    Further to this, when using a 'plus' character, its opposite is 'minus', not 'hyphen'. Plus and minus in most fonts will better align with each other vertically. – Arthur Apr 20 '19 at 07:52
  • @Arthur thank you, I completely missed the fact, that it's hyphen and not minus. I updated my answer. – Kevin Kopf Apr 20 '19 at 12:12
  • Also, monospace fonts have the characteristic where each letter/symbol have identical widths. I.e. an 'i' will take up the same space as an 'm'. – NSTuttle Apr 21 '19 at 18:24
  • @Illdapt width-wise, yes. Not height-wise. – Kevin Kopf Apr 21 '19 at 18:46
  • Thank you for the very thorough answer. This explains why the text is not well centered. I changed the `-` to `−` which fixed the misalignment between the two. However, this does not explain why there is a difference from one + button to the other. (See my additional image in my question edit). I have decided to take your advice and use an image for the buttons instead. But I'm interested in solving or at least explaining the initial problem. – Lee Blake Apr 24 '19 at 05:14
  • The difference between alignment from one button to the next, eliminates the use of padding to "fix" the centering, which is why doing so (as suggested elsewhere) would not solve my issue. – Lee Blake Apr 24 '19 at 05:19
  • As an experiment, I just changed the font size from 11 to 12 as I thought it might have something to do with using a non-standard size for the font(s). This made all the buttons consistent in their horizontal alignment (though they're not centered), but now the buttons are inconsistent in their vertical alignment in much the same way as they were horizontally before. Very strange behavior. I'm going to try changing them to divs. Will report back. – Lee Blake Apr 24 '19 at 05:35
  • The inconsistencies are because of rounding the font size during scaling. I think it's somehow stacking to the previous scaling and therefore it's off by a pixel to the left and then to the right. – Kevin Kopf Apr 24 '19 at 07:59
  • Changed them to divs which had no effect. I had the same thought about the scaling, so I double checked my monitor to make sure I didn't have any. – Lee Blake Apr 24 '19 at 08:21
2

I believe this may be because of the button element itself:

When placing the + inside a seperate span, and aligning the span perfectly in the center,
by using flexboxes, the +is still not exactly in the center. When I do the same with a div element,
the + is exactly centered.

Check this fiddle to see what I mean.
Therefore I recommend using a div with a click event instead of a button.

Also, if you want have a minus sign which is vertically aligned at the same height as the plus,
you should use &minus; instead of - inside your element.

Ignace Vau
  • 532
  • 4
  • 19
  • 1
    Thank you for the tip. I've done more research and updated my answer to include flexboxes. – Kevin Kopf Apr 20 '19 at 15:36
  • I made the change to the `−` which fixed the disparity between the plus and the minus. Thank you. – Lee Blake Apr 24 '19 at 05:19
  • It's still unclear since in php you should make mathematical functions to get the value like 1-2 = -1 in first colum then second... In such case how to adapt all the answers posted here to write + - in table i.e. It will work if the code is HTML code not php output. – Creative87 Apr 25 '19 at 17:49
  • @Creative87 In the case you want a `-` to be replaced with `minus;`, you could simply use Javascript to modify the output before applying it. `text = output.replace('-', '−')` – Ignace Vau Apr 27 '19 at 10:47
1

You need specify the font-family in .pmbutton,

you can choose a widely using web safe font or you can declare your own font-face

.pmbutton {
   font-family:arial;
}
Sajan
  • 813
  • 9
  • 14
1

Maybe you could do instead of hard coded height and width, use padding for the spacing.. If the font-size is 10px then just give it a padding of 4px

Thijs
  • 103
  • 1
  • 2
  • 11
0

As I understand you need to place your values in central position According to HTML code you have posted above You can't place your Text in center position unless you do the following:

<td class = "test" align = "center">+<td>

You should use align="center" to get text in center position and don't use CSS for this it will not work just use it as above Now you need to place text in center position vertically This step can be achieved by CSS

.test { padding-top = 2px; padding-bottom = 2px;}

As above in CSS vertical position is adjusted by padding.

Another way if not work with HTML5

Use span inside the tag

<td class ="test"><span>+</span></td>

Then use CSS

.test > span { padding-top = 2px; padding-bottom = 2px; padding-right = 2px padding-left = 2px;}

Update

Look in case you ask about Mac OS and iPhone also the reset of this device so here my advice Don't used td tag with these devices they will not work fine and this related to app development not for devices itself. If you use Firefox on iPhone it may work fine So use this type of tags Example

<dl>
<dt>Coffee</dt>
<dd>Black hot drink</dd>
<dt>Milk</dt>
<dd>White cold drink</dd>
</dl>

dt is better than td

Reason :

Possible reasons for this behavior I search around and ask some friends why this could be happening in some browsers while other not? And I got this conclusion:

This is because sometimes Safari webview Zooms text automatically because it though its a good idea.

To disable this Use this CSS Style:

-webkit-text-size-adjust:none;

Now your characters should be displayed without interrupting .

Creative87
  • 125
  • 9
  • 1
    `align` property is not supported in HTML5 and therefore `+` will not be centered horizontally. – Kevin Kopf Apr 21 '19 at 17:39
  • I have updated answer with another I think it should work fine – Creative87 Apr 21 '19 at 18:16
  • sorry, I still think it's crutch-based development. The default font is different in different browser on different machines; your solution will hardly work on macos... Besides, you fail to explain the cause of OP's problem (and he's asking about the cause) – Kevin Kopf Apr 21 '19 at 18:49
  • He use td and by the way td tag on not just mac also on iPhone don't work fine and don't display symbols right I just try to give away around that but if you search for the cause not for solution then you right my answer is not the cause. – Creative87 Apr 21 '19 at 18:57
  • I have updated answer with the cause. If you have update or new ideas then add comment to let me know. – Creative87 Apr 22 '19 at 00:01