0

I don't understand why vertical-align: middle makes an icon not being centered, but a little lower.

HTML:

<ul class="operatorscreen__buttons">
  <li class="operatorscreen__single-button">
    <a class="operatorscreen__link button-link button-block button-link_outline" href="#">First icon</a>
  </li>
  <li class="operatorscreen__single-button">
    <a class="operatorscreen__link button-link button-block button-link_outline" href="#">Second</a>
  </li>
</ul>

scss:

.operatorscreen {
    &__single-button {
      &:first-child {
        margin-bottom: 10px;
      }
    }

    &__link {
    color: black;
    text-decoration: none;
    font-size: 18px;

    &:before {
      content: "";
      display: inline-block;
      width: 16px;
      height: 20px;
      font-size: 100px;
      margin-right: 12px;
      vertical-align: middle;
      background-color: red;
    }

  }
}

enter image description here

As you can see, a red background is little lower than text, though it should be right in the center vertically.

Alexander Kim
  • 17,304
  • 23
  • 100
  • 157

3 Answers3

1

Try it:

li:not(:last-child) {
  margin-bottom: 10px;
}

li::before {
  content: '';
  width: 16px;
  height: 20px;
  display: inline-block;
  vertical-align: sub;
  background-color: red;
}
<ul>
  <li>First icon</li>
  <li>Second icon</li>
</ul>
meine
  • 260
  • 5
  • 15
1

When I use a ruler to measure, it looks like vertical-align: middle is behaving correctly: it is in the middle of the lower case letters.

If you want it to be "perfect" then you may need to be more precise. There are many ideas, one quick one being:

position: relative;
top: -1px; // adjust to your desire

More on vertical-align of inline elements here: https://css-tricks.com/almanac/properties/v/vertical-align/

BenHerbert
  • 171
  • 2
  • 11
  • I usually used relative position either, but is it ok to do that? Seems hacky for me. – Alexander Kim Jan 20 '19 at 15:24
  • Yes, it is a hack because it is not something you can standardise for re-use across different icons. If you ask me, I don't think it looks bad how you have it. Depending on the actual icon you use, it will look more or less aligned anyway due to the shape of the icon / negative space. I would normally do it exactly as you already have done, using `vertical-align: middle`. – BenHerbert Jan 20 '19 at 15:27
  • Great, thats 'superscript', which makes text appear half a character above the normal line. Glad it solved your query! :-) – BenHerbert Jan 20 '19 at 15:43
1

It's actually in the middle but you need to know what is the middle.

Aligns the middle of the element with the baseline plus half the x-height of the parent.ref

Here is an illustration to show the middle of the element aligned with the baseline plus half the x-height.

.operatorscreen__single-button:first-child {
  margin-bottom: 10px;
}

.operatorscreen__link {
  color: black;
  text-decoration: none;
  font-size: 18px;
  background: 
    /*plus half x-height*/
    linear-gradient(green,green) 0 calc(16px - 0.5ex)/100% 1px no-repeat,
    /*the baseline*/
    linear-gradient(#000,#000)0 16px/100% 1px no-repeat;
}

.operatorscreen__link:before {
  content: "";
  display: inline-block;
  width: 16px;
  height: 20px;
  font-size: 100px;
  margin-right: 12px;
  vertical-align: middle;
  background:
    linear-gradient(#000,#000) center/100% 1px no-repeat;
  background-color: red;
}
<ul class="operatorscreen__buttons">
  <li class="operatorscreen__single-button">
    <a class="operatorscreen__link button-link button-block button-link_outline" href="#">First icon</a>
  </li>
  <li class="operatorscreen__single-button">
    <a class="operatorscreen__link button-link button-block button-link_outline" href="#">Second</a>
  </li>
</ul>

In your particular case, use top (or text-top, text-bottom, sub) instead of middle and you will be closer to the middle you expect:

.operatorscreen__single-button:first-child {
  margin-bottom: 10px;
}

.operatorscreen__link {
  color: black;
  text-decoration: none;
  font-size: 18px;
  background: linear-gradient(#000,#000)center/100% 1px no-repeat;
}

.operatorscreen__link:before {
  content: "";
  display: inline-block;
  width: 16px;
  height: 20px;
  font-size: 100px;
  margin-right: 12px;
  vertical-align: top;
  background:linear-gradient(#000,#000) center/100% 1px no-repeat;
  background-color: red;
}
<ul class="operatorscreen__buttons">
  <li class="operatorscreen__single-button">
    <a class="operatorscreen__link button-link button-block button-link_outline" href="#">First icon</a>
  </li>
  <li class="operatorscreen__single-button">
    <a class="operatorscreen__link button-link button-block button-link_outline" href="#">Second</a>
  </li>
</ul>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • You're right, indeed, in my case `vertical-align: sub` centered it. But why? Could you explain? I've seen your website, seems like you're a CSS guru :) – Alexander Kim Jan 20 '19 at 15:28
  • @AlexanderKim check the update, not only sub .. top/text-top and text-bottom will also make what you want ;) – Temani Afif Jan 20 '19 at 15:29
  • Still, top is a bit higher now :D Sub is ideal – Alexander Kim Jan 20 '19 at 15:31
  • 1
    @AlexanderKim it depend on the browser and the font and also the height of the pseudo element. change the height and you will see that even sub will not give you the middle you want ;) basically vertical align don't consider the middle of the element like you may think but there is other reference, here is a good reading if you want to get more details : https://stackoverflow.com/a/54190413/8620333 (you can also follow the links) – Temani Afif Jan 20 '19 at 15:37
  • thanks for explanation, too many variables there: height, font size, etc... So there's no silver bullet rule for all icons at once? – Alexander Kim Jan 20 '19 at 15:49
  • @AlexanderKim the silver and gold rule is to avoid centring using vertical-align :) .. use other stuffs like flexbox, position, etc and you will have more accurate result – Temani Afif Jan 20 '19 at 15:51
  • Is it ok to use flexbox for icon in my case? I thought it's not a good practice. – Alexander Kim Jan 20 '19 at 15:58
  • @AlexanderKim if you use it correctly there is no issue. With flexbox you will have the dead center better than vertical align: https://jsfiddle.net/5z2qpm7v/ – Temani Afif Jan 20 '19 at 16:11