0

I am trying to use a single letter as a logo, the problem is that the containing box of the letter, also called 'em-box' is too large and/or too small, like here:

enter image description here

I would like it to have the exact same size as the letter so that I can centre it perfectly into the circle, like the 'w' logo. The 'b' one, using the same css, is totally off.

@import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@200&family=Press+Start+2P&display=swap');
.container {
  display: flex;
  gap: 30px;
}

.circle {
  display: flex;
  height: 175px;
  width: 175px;
  justify-content: center;
  align-items: center;
  border-radius: 100px;
  background: #1231b3;
}

.text {
  display: flex;
  font-family: 'Press Start 2P';
  font-size: 120px;
  color: white;
  background-color: light-blue;
}

.light {
  background: #7c8dd7;
}
<div class="container">
  <div class="circle">
    <div class="text">b</div>
  </div>
  <div class="circle">
    <div class="text light">b</div>
  </div>
</div>
  • You have to post at least a snippet of the code used to render this boxes (html, css) – Ruber Jun 27 '22 at 13:19
  • The b has an ascender. I assume you are doing some sort of px or similar placement of the characters that do not have ascenders or descenders and it's working for them? Please show your CSS as it's impossible to know what you are doing without guessing at the moment. Note also that the solution may depend on the specific typeface being used so please make sure that is included. – A Haworth Jun 27 '22 at 14:31
  • Just added a code snipped, I hope it helps. – Bru Mas Ribera Jun 27 '22 at 17:58
  • 1
    I don't think CSS has any way of knowing what the actual height and width of a particular character is (where height is defined as the distance between the topmost visible point and the bottom most visible point etc). You may need to have an intermediary stage using canvas so you can calculate this youself. – A Haworth Jun 27 '22 at 21:32

2 Answers2

1

CSS doesn't know where a character begins and ends (in terms of its visible parts as opposed to its overall width/height).

To find out the top/bottom/left/right visible extremities of a character this snippet draws it on a canvas and then scans the canvas rows and columns to find the first points that have non-zero alpha settings.

A logo is taken to be the full rounded square and its contents. The inner circle is drawn as a before pseudo element.

The character is drawn not in the DOM but as content to the after pseudo element.That way its position can be adjusted depending on its visible dimensions.

Characters that have no ascenders (e.g. w and c in the example given in the question) are moved up slightly (depending on their overall visible height) so they are centered.

The typeface in question differs a bit from the standard typefaces in that the descenders hardly have any height so the position of the baseline in relation to an overall character is different.

This snippet cheats slightly by building in the height of a character with an ascender (a lowercase b in this case) as a guide for which characters need adjusting. It's therefore not a completely general solution for any typeface which might be thrown at it. A bit more work would need to be done to first ascertain the range of heights in any given font.

<!doctype html>
<html>

<head>
  <title>Chars as logos</title>
  <!-- https://stackoverflow.com/questions/72772445/remove-unused-space-from-letter -->
  <script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"></script>
  <style>
    body {
      font-family: 'Press Start 2P';
      letter-spacing: -4px;
      font-size: 30px;
    }
    /* container added just for demo */
    
    .container {
      display: flex;
      gap: 3vw;
      background: #eeeeee;
      rtext-align: center;
    }
    
    .logo {
      width: 70px;
      height: 70px;
      display: flex;
      justify-content: center;
      align-items: center;
      background-color: var(--col1);
      border-radius: 10px;
      position: relative;
      padding: 0;
      margin: 0;
      line-height: 1em;
    }
    
    .logo::before {
      content: '';
      width: 50px;
      height: 50px;
      background-color: var(--col2);
      border-radius: 50%;
      position: absolute;
      top: 10px;
      left: 10px;
      padding: 0;
      margin: 0;
    }
    
    .logo::after {
      content: var(--char1);
      font-family: 'Press Start 2P';
      font-size: 30px;
      height: calc(var(--h) * 1px);
      width: calc(var(--w) * 1px);
      padding: 0;
      margin: 0;
      display: inline-block;
      position: absolute;
      color: white;
      z-index: 1;
      text-align: center;
      margin-top: calc(var(--top) * 1px);
    }
    
    canvas {
      width: 200px;
      height: 200px;
    }
  </style>
</head>

<body>

  <div class="container">
    <div class="logo" style="--char: g; --char1: 'g'; --col1: #c920df; --col2: #e48fef;"></div>
    <div class="logo" style="--char: w; --char1: 'w'; --col1: #df208d; --col2: #ef8fc6;"></div>
    <div class="logo" style="--char: b; --char1: 'b'; --col1: #1231b3; --col2: lightblue;"></div>
  </div>

  <script>
    const logos = document.querySelectorAll('.logo');

    function fontLoaded() {
      logos.forEach(logo => {
        let canvas = document.createElement("canvas");
        canvas.width = 200;
        canvas.height = 200;
        let ctx = canvas.getContext("2d");
        ctx.font = "30px 'Press Start 2P'";
        ctx.fillText(logo.style.getPropertyValue('--char'), 10, 60); //baseline of the character will be at 60

        let d = ctx.getImageData(0, 0, 200, 200);
        let foundTop = false;
        foundBottom = false;
        foundLeft = false;
        foundRight = false;
        let top = [];
        let bottom = [];
        let left = [];
        let right = [];
        let r, c;
        //// Find the visible height ////
        for (r = 0; r < 200; r++) {
          for (c = 3; c < (800 - 1); c += 4) {
            if (d.data[(r * 800) + c] != 0) {
              foundTop = true;
              top = [r, c];
              break;
            }
          }
          if (foundTop) break;
        }

        for (r = 200 - 1; r >= 0; r--) {
          for (c = (800 - 1); c >= 0; c -= 4) {
            if (d.data[(r * 800) + c] != 0) {
              foundBottom = true;
              bottom = [r, c];
              break;
            }
          }
          if (foundBottom) break;
        }
        //// now find the width ////

        for (c = 3; c < (800 - 1); c += 4) {
          for (r = 0; r < (200 - 1); r++) {
            if (d.data[(r * 800) + c] != 0) {
              foundLeft = true;
              left = [r, c];
              break;
            }
          }
          if (foundLeft) break;
        }

        for (c = (800 - 1); c >= 0; c -= 4) {
          for (r = 200 - 1; r >= 0; r--) {
            if (d.data[(r * 800) + c] != 0) {
              foundRight = true;
              right = [r, c];
              break;
            }
          }
          if (foundRight) break;
        }

        logo.style.setProperty('--h', bottom[0] - top[0]);
        logo.style.setProperty('--w', (right[1] - left[1] - 1) / 4);
        if ((bottom[0] - top[0]) < 26) logo.style.setProperty('--top', (top[0] - bottom[0]) / 2);
      });
    }

    WebFont.load({
      google: {
        families: ['Press Start 2P:300,400,700']
      },
      loading: function() {},
      active: function() {
        fontLoaded();
      }
    });
  </script>
</body>

</html>

Note: before a typeface is drawn on a canvas we have to be sure that it has been loaded, hence the use of the google library

A Haworth
  • 30,908
  • 4
  • 11
  • 14
  • That looks much better! I wonder what could be done with the w that is still not completely centred. It's crazy though that to make something that should be quite simple we need this big walk around. Thank you @a-haworth for the efforts. – Bru Mas Ribera Jun 29 '22 at 10:14
  • Needs a bit of refinement on some of the letters - it's a strange typeface with almost no descenders (but just a little bit on the g), the baseline is not where you'd expect it to be on some characters. Have to admit I slightly lost the will to live after plodding through the above, but you could look at the arithmetic for those characters with no descenders and no ascenders a bit more closely. – A Haworth Jun 29 '22 at 10:21
  • Indeed, it's a pity there is not a more simple solution. I believe this should be something accessible by CSS, much more straightforward. – Bru Mas Ribera Jul 01 '22 at 13:15
0

@ A Haworth's answer is awesome. I could never have come up with that. But if you want a quick and dirty css-only solution, get rid of the flex properties, set text-align to center, and massage the padding for the .text boxes. Use em measurements so the layout will scale without breaking.

Big Font: 120px

   @import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@200&family=Press+Start+2P&display=swap');

/* only used for this example */
.wrapper {
  display: flex;
  gap: 30px;
}

.container {
      font-size: 120px;
/*      font-size: 24px;*/
    display: inline-block;
    padding: .25em;
    border-radius: .5em;
}

.container.blue {
    background-color: #8fa1ef;
}

.container.purple {
    background-color: #e48fef;
}

.container.red {
    background-color: #ef8fc6;
}

.circle {
    height: 1.5em;
    width: 1.5em;
  border-radius: 1em;
}

.blue .circle {
  background-color: #1231b3;
}

.red .circle {
    background-color: #df208d;
}

.purple .circle {
    background-color: #c920df;
}

.text {
  font-family: 'Press Start 2P';
  color: white;
  text-align: center;
}

.blue .text {
  padding: .18em 0 0 .125em;
}

.red .text {
    padding: .08em 0 .04em .04em;
}

.purple .text {
    padding: .08em 0 0 .1em;
}
<div class="wrapper">

<div class="container blue">
  <div class="circle">
    <div class="text">b</div>
  </div>
</div>

<div class="container red">
  <div class="circle">
    <div class="text">c</div>
  </div>
</div>

<div class="container purple">
  <div class="circle">
    <div class="text">w</div>
  </div>
</div>

</div>

Small Font: Exactly the same, but the font size is set to 24px.

@import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@200&family=Press+Start+2P&display=swap');

/* Only used for this example */
.wrapper {
  display: flex;
  gap: 30px;
}

.container {
/*      font-size: 120px;*/
      font-size: 24px;
    display: inline-block;
    padding: .25em;
    border-radius: .5em;
}

.container.blue {
    background-color: #8fa1ef;
}

.container.purple {
    background-color: #e48fef;
}

.container.red {
    background-color: #ef8fc6;
}

.circle {
    height: 1.5em;
    width: 1.5em;
  border-radius: 1em;
}

.blue .circle {
  background-color: #1231b3;
}

.red .circle {
    background-color: #df208d;
}

.purple .circle {
    background-color: #c920df;
}

.text {
  font-family: 'Press Start 2P';
  color: white;
  text-align: center;
}

.blue .text {
  padding: .18em 0 0 .125em;
}

.red .text {
    padding: .08em 0 .04em .04em;
}

.purple .text {
    padding: .08em 0 0 .1em;
}
<div class="wrapper">

<div class="container blue">
  <div class="circle">
    <div class="text">b</div>
  </div>
</div>

<div class="container red">
  <div class="circle">
    <div class="text">c</div>
  </div>
</div>

<div class="container purple">
  <div class="circle">
    <div class="text">w</div>
  </div>
</div>

</div>
HomeSlice
  • 596
  • 2
  • 14