如何用变宽字体模仿等宽字体?

问题描述 投票:0回答:2

我已经阅读了CSS - 让无衬线字体模仿等宽字体,但是CSS规则

letter-spacing
似乎还不够:

如何从标准无衬线字体模仿等宽固定字体?

这并不完美:

.text {
  font-family: sans-serif;
  letter-spacing: 10px;
}
<div class="text">
ABCDEFGHIJKLMNOPQR<br>
STUVWXYZ0123456789
</div>

html css fonts font-face letter-spacing
2个回答
2
投票

letter-spacing
只是在所有字母之间均匀地插入空格(...因此得名)。
它不会将字符/字形标准化为具有相同的宽度。
我们需要一个像
letter-width
这样的 css 属性,但它不存在

除了在字体编辑器中更改实际字体规格并编译新字体之外,您还可以通过 javaScript 将所有字母拆分为

<span>
元素数组。

emulateMonospace();

function emulateMonospace() {
  let monoWraps = document.querySelectorAll(".toMonospace");

  monoWraps.forEach(function(monoWrap, i) {
    //remove all "\n" linebreaks and replace br tags with "\n"
    monoWrap.innerHTML = monoWrap.innerHTML
      .replaceAll("\n", "")
      .replaceAll("<br>", "\n");
    let text = monoWrap.textContent;
    let letters = text.split("");


    //get font-size
    let style = window.getComputedStyle(monoWrap);
    let fontSize = parseFloat(style.fontSize);

    //find maximum letter width
    let widths = [];
    monoWrap.textContent = "";
    letters.forEach(function(letter) {
      let span = document.createElement("span");
      if (letter == "\n") {
        span = document.createElement("br");
      }
      if (letter == ' ') {
        span.innerHTML = '&nbsp;';
      } else {
        span.textContent = letter;
      }
      monoWrap.appendChild(span);
      let width = parseFloat(span.getBoundingClientRect().width);
      widths.push(width);
      span.classList.add("spanMono");
      span.classList.add("spanMono" + i);
    });

    monoWrap.classList.replace("variableWidth", "monoSpace");

    //get exact max width
    let maxWidth = Math.max(...widths);
    let maxEm = maxWidth / fontSize;
    let newStyle = document.createElement("style");
    document.head.appendChild(newStyle);
    newStyle.sheet.insertRule(`.spanMono${i} { width: ${maxEm}em }`, 0);
  });
}
body{
  font-family: sans-serif;
  font-size: 10vw;
  line-height: 1.2em;
  transition: 0.3s;
}

.monospaced{
    font-family: monospace;
}

.letterspacing{
  letter-spacing:0.3em;
}

.teko {
  font-family: "Teko", sans-serif;
}

.serif{
    font-family: "Georgia", serif;
}

.variableWidth {
  opacity: 0;
}

.monoSpace {
  opacity: 1;
}

.spanMono {
  display: inline-block;
  outline: 1px dotted #ccc;
  text-align: center;
  line-height:1em;
}
<link href="https://fonts.googleapis.com/css2?family=Teko:wght@300&display=swap" rel="stylesheet">

<h3 style="font-size:0.5em;">Proper monospace font</h3>
<div class="monospaced">
WiWi</br>
iWiW
</div>

<h3 style="font-size:0.5em;">Letterspacing can't emulate monospaced fonts!</h3>
<div class="letterspacing">
WiWi</br>
iWiW
</div>


<hr>

<h3 style="font-size:0.5em;">Text splitted up in spans</h3>

<div class="toMonospace variableWidth">
ABCDEFGHIJKLMNOPQR<br>
STUVWXYZ0123456789<br>
</div>

<div class="toMonospace variableWidth teko">
ABCDEFGHIJKLMNOPQR<br>
STUVWXYZ0123456789<br>
</div>

<div class="toMonospace variableWidth serif">
This is<br>
not a<br>
Monospace<br>
font!!!
</div>

每个字符都将包含在具有

inline-block
显示属性的范围内。

此外,所有字符均通过

text-align:center
居中。

上面的脚本还会比较所有字符的宽度,将最大的宽度设置为跨度宽度。

不可否认,这不是很方便
但这种方法可能足以满足设计/布局的目的,并且不会更改实际的字体文件。

如片段所示:
在等宽字体中,最宽的字母(如“W”)会被挤压(不会扭曲) 而较瘦的人喜欢 “i”在视觉上得到拉伸(例如通过添加底部衬线)。

因此,正确的等宽字体是完全不同的,并且无法真正模拟。


1
投票

我花了太多时间试图找到一种好的等宽字体,它可以与多个字母一起使用,并且具有我想要的外观。这些是我找到的解决方案(按推荐顺序):

  1. 找到您喜欢的等宽字体并使用它。
  2. 使用字体编辑器并将所有字母更改为相同的宽度(可能有一个Python程序可以做到这一点,但我还没有尝试过)。但是将字体更改为等宽字体看起来不太好,创建每个字母都有很多技巧,因此它可以正确地适合等宽框。
  3. 使用
    letter-spacing
    模拟简单的等宽字体。
© www.soinside.com 2019 - 2024. All rights reserved.