Bru Mas Ribera
Bru Mas Ribera

Reputation: 59

Remove unused space from letter

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>

Upvotes: 0

Views: 103

Answers (2)

HomeSlice
HomeSlice

Reputation: 612

@ 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>

Upvotes: 0

A Haworth
A Haworth

Reputation: 36467

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

Upvotes: 1

Related Questions