使用CSS将非等宽字体强制转换为固定宽度

Jon*_*sch 38 css fonts typography

有没有办法强制使用CSS使字体等宽?

我的意思是,使用非等宽字体,你可以强制浏览器以固定宽度渲染每个字符吗?

ver*_*y_p 25

如果这是用于对齐表格中的数字,其中某些字体(使用传统的排版)默认使用可变宽度(例如Windows上的Segoe UI)渲染它们,您应该查看CSS属性:

font-variant-numeric: tabular-nums;

(这将禁用至少由OpenType字体支持proportional-numsnumeric-spacing变体的默认值,并且可能禁用特定平台的Web浏览器的文本渲染器支持的其他字体格式)

不需要javascript!这是禁用这些字体中可变宽度字形的最简洁方法,并强制它们使用表格数字(这通常使用相同字体的相同字形,但它们的前导和尾随间隙增加,因此从0到10的10位数字9将以相同的宽度呈现;但是某些字体可以避免视觉变量interdigit间距并略微隐藏一些数字,或者可以将底部衬线添加到数字1的脚.

请注意,这不会禁用使用Segoe UI观察到的变量高度(例如,某些数字将仅为x高度,如同小写字母,其他数字将具有上升或下降).这些传统的数字形式也可以使用CSS禁用

font-variant-numeric: lining-nums;

(这会禁用至少由OpenType字体支持oldstyle-numsnumeric-figure变体的默认值,以及您的特定平台的Web浏览器的文本渲染器可能支持的其他字体格式)

你可以把两者结合起来

font-variant-numeric: tabular-nums lining-nums;


下面的代码片段使用单个比例字体(非等宽字体!)来演示这一点,该字体具有数字形状变体,例如Windows上的"Segoe UI",并显示生成的不同水平和垂直对齐.

请注意,如果应用粗体或斜体等不同的样式而不是中等罗马字体,则此样式不会禁止数字更改宽度,如下所示,因为这些将使用不同的字体及其自己的不同指标(这不适用于所有等宽字体) .

html { font-family: 'Segoe UI'; /* proportional with digit variants */ }
table { margin: 0; padding: 0; border: 1px solid #AAA; border-collapse: collapse; }
th, td { vertical-align:top; text-align:right; }
.unset       { font-variant-numeric: unset; }
.traditional { font-variant-numeric: proportional-nums oldstyle-nums; }
.lining      { font-variant-numeric: proportional-nums lining-nums;   }
.tabular-old { font-variant-numeric: tabular-nums      oldstyle-nums; }
.tabular-new { font-variant-numeric: tabular-nums      lining-nums;   }
.normal      { font-variant-numeric: normal; }
Run Code Online (Sandbox Code Playgroud)
<table>
<tr><th>unset<td><table width="100%" class="unset">
  <tr><td>Rs12,34,56,789.00/Gal<td><i>Difference Rs86,41,97,532.11/Gal
  <tr><td>Rs98,76,54,321.11/Gal<td><b>Total Rs1,11,11,11,110.11/Gal
  </table>
<tr><th>traditional<td><table width="100%" class="traditional">
  <tr><td>Rs12,34,56,789.00/Gal<td><i>Difference Rs86,41,97,532.11/Gal
  <tr><td>Rs98,76,54,321.11/Gal<td><b>Total Rs1,11,11,11,110.11/Gal
  </table>
<tr><th>lining<td><table width="100%" class="lining">
  <tr><td>Rs12,34,56,789.00/Gal<td><i>Difference Rs86,41,97,532.11/Gal
  <tr><td>Rs98,76,54,321.11/Gal<td><b>Total Rs1,11,11,11,110.11/Gal
  </table>
<tr><th>tabular-old<td><table width="100%" class="tabular-old">
  <tr><td>Rs12,34,56,789.00/Gal<td><i>Difference Rs86,41,97,532.11/Gal
  <tr><td>Rs98,76,54,321.11/Gal<td><b>Total Rs1,11,11,11,110.11/Gal
  </table>
<tr><th>tabular-new<td><table width="100%" class="tabular-new">
  <tr><td>Rs12,34,56,789.00/Gal<td><i>Difference Rs86,41,97,532.11/Gal
  <tr><td>Rs98,76,54,321.11/Gal<td><b>Total Rs1,11,11,11,110.11/Gal
  </table>
<tr><th>normal<td><table width="100%" class="normal">
  <tr><td>Rs12,34,56,789.00/Gal<td><i>Difference Rs86,41,97,532.11/Gal
  <tr><td>Rs98,76,54,321.11/Gal<td><b>Total Rs1,11,11,11,110.11/Gal
  </table>
</table>
Run Code Online (Sandbox Code Playgroud)

参考:https://developer.mozilla.org/fr/docs/Web/CSS/font-variant-numeric


Ble*_*der 11

你不能用CSS做到这一点.即使你可以,结果也会很糟糕:

在此输入图像描述

如果你确实需要这样做,你可以使用JavaScript将每个字符包装在一个元素中(或者只是手工完成):

function wrap_letters($element) {
    for (var i = 0; i < $element.childNodes.length; i++) {
        var $child = $element.childNodes[i];

        if ($child.nodeType === Node.TEXT_NODE) {
            var $wrapper = document.createDocumentFragment();

            for (var i = 0; i < $child.nodeValue.length; i++) {
                var $char = document.createElement('span');
                $char.className = 'char';
                $char.textContent = $child.nodeValue.charAt(i);

                $wrapper.appendChild($char);
            }

            $element.replaceChild($wrapper, $child);
        } else if ($child.nodeType === Node.ELEMENT_NODE) {
            wrap_letters($child);
        }
    }
}

wrap_letters(document.querySelectorAll('.boxes')[0]);
wrap_letters(document.querySelectorAll('.boxes')[1]);
Run Code Online (Sandbox Code Playgroud)
.char {
    outline: 1px solid rgba(255, 0, 0, 0.5);
}

.monospace .char {
    display: inline-block;
    width: 15px;
    text-align: center;
}
Run Code Online (Sandbox Code Playgroud)
<h2 class="boxes">This is a title</h2>
<h2 class="boxes monospace">This is a title</h2>
Run Code Online (Sandbox Code Playgroud)

  • 这确实看起来很可怕. (8认同)
  • 我知道这很古老,但我觉得有必要提一下这个用途,比如计数器和图标字体. (4认同)
  • @Blender,一般来说你是对的,但是有些情况下,monospace字体实际上会为字体属性增加宽度,如粗体和斜体,如果你需要*它们排队,这可能会很糟糕.Lucida Console就是这样一种字体.如果您希望语法突出显示使用粗体,则在IDE中使用它是无用的,因为Lucida Console 12pt在粗体时大约宽1个像素.使得无法通过空格排列代码(通过行上的初始空格).我找到的一个IDE很聪明,有一个复选框可以将粗体锁定在普通宽度上. (3认同)

Dou*_*rch 10

为什么不在盒子外面和桌子内思考:

<table cellpadding="0" cellspacing="0">
<tr><td>T</td><td>h</td><td>e</td><td></td><td>r</td><td>a</td><td>i</td><td>n</td><td></td><td>i</td><td>n</td><td></td><td>S</td><td>p</td><td>a</td><td>i</td><td>n</td><td></td><td>s</td><td>t</td><td>a</td><td>y</td><td>s</td></tr>
<tr><td>m</td><td>a</td><td>i</td><td>n</td><td>l</td><td>y</td><td></td><td>i</td><td>n</td><td></td><td>t</td><td>h</td><td>e</td><td></td><td>p</td><td>l</td><td>a</td><td>i</td><td>n</td><td>s</td><td>.</td></tr>
</table>
Run Code Online (Sandbox Code Playgroud)

  • 这更像是"在盒子里面"(对不起,不得不这样做) (67认同)
  • 我想我们现在应该提出这个想法. (52认同)
  • 你们都应该被锁在一个单元格中来发表这些评论. (43认同)

Már*_*más 8

我刚刚找到了text-transform: full-width; 实验关键字,它:

[...] 强制在正方形 [...] 内写入字符 [...]

文本转换 | MDN

结合 negative letter-spacing,您可以获得不那么可怕的结果:

固定宽度的无衬线字体来模拟等宽字体

<style>
pre {
  font-family: sans-serif;
  text-transform: full-width;
  letter-spacing: -.2em;
}
</style>

<!-- Fixed-width sans-serif -->
<pre>
. i I 1  | This is gonna be awesome.
ASDFGHJK | This is gonna be awesome.
</pre>

<!-- Default font -->
. i I 1  | This is gonna be awesome.
<br>
ASDFGHJK | This is gonna be awesome.
Run Code Online (Sandbox Code Playgroud)

  • 目前仅在 Firefox 中可用,但如果它得到广泛支持,这将是最好的答案。 (3认同)
  • 可用的子集只有: 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z а b c d e f gh i j k l m n o p q rs s t u v w xi y z , .: ;! ? " ' ` ^ ~  ̄ _ & @ # % + - * = < > ( ) [ ] { } ⦅ ⦆ | ¦ / \ ¬ $ £ ¢ ₩ ¥ 所以别指望能正确渲染“café” 。对于印度文字、阿拉伯文字、希伯来文字、西里尔文字、泰语……没有解决方案。 (2认同)

Vin*_*nce 6

好吧,您并没有说使用CSS。只需要一点点 Javascript 就可以做到这一点,将每个字母包装在span. 其余的在 CSS 中...

window.onload = function() {
  const secondP = document.getElementById('fixed');
  const text = secondP.innerText;
  const newText = text.split('').map(c => {
    const span = `<span>${c}</span>`;
    return span;
  }).join('');
  secondP.innerHTML = newText;
}
Run Code Online (Sandbox Code Playgroud)
p {
  position: relative;
  border: 1px solid black;
  border-radius: 1em;
  padding: 1em;
  margin: 3em 1em;
}

p::after {
  content: attr(name);
  display: block;
  background-color: white;
  color: green;
  padding: 0 0.5em;
  position: absolute;
  top: -0.6em;
  left: 0.5em;
}

#fixed span {
  display: inline-block;
  width: 1em;
  text-align: center;
}
Run Code Online (Sandbox Code Playgroud)
<p id="variable" name="Variable Width">It might not look nice, but with a little Javascript, I can force a variable width font to act like a fixed-width font.</p>
<p id="fixed" name="Fixed Width">It might not look nice, but with a little Javascript, I can force a variable width font to act like a fixed-width font.</p>
Run Code Online (Sandbox Code Playgroud)

在带有常规文本的段落中,它看起来很糟糕,但在某些情况下这是有道理的。图标字体和 Unicode 符号都可以使用这种技术。

我在尝试为 Unicode 符号找到解决方案时发现了这个问题,这些 Unicode 符号在替换为其他 Unicode 符号时会将常规文本向右移动。


jer*_*ris -3

不,除非它是实际的等宽字体。