71

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

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

4

9 回答 9

57

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

font-variant-numeric: tabular-nums;

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

无需 JavaScript!这是禁用这些字体中的可变宽度字形并强制它们使用表格数字的最干净的方法(这通常在相同字体的相同字形中使用,但它们的前导和尾随间隙增加了,因此 10 个数字从 0 到9 将以相同的宽度呈现;但是某些字体可能会避免视觉可变的数字间间距,并且会稍微加宽一些数字,或者可能会在数字 1 的脚下添加底部衬线。

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

font-variant-numeric: lining-nums;

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

您可以将两者结合起来:

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; }
<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>

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

于 2017-11-18T04:01:29.203 回答
16

为什么不跳出框框思考一下:

<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>
于 2012-04-13T23:23:33.270 回答
12

你不能用 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]);
.char {
    outline: 1px solid rgba(255, 0, 0, 0.5);
}

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

于 2012-04-13T23:04:28.193 回答
10

我刚刚找到了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.
于 2018-12-30T18:54:46.057 回答
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;
}
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;
}
<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>

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

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

于 2017-01-27T12:44:53.233 回答
2

我有时为倒计时做了一件非常漂亮的事情:

HTML:

<div class="counter">
    <span class="counter-digit counter-digit-0">2</span>
    <span class="counter-digit counter-digit-1">4</span>
    <span class="counter-digit counter-digit-divider">/</span>
    <span class="counter-digit counter-digit-2">5</span>
    <span class="counter-digit counter-digit-3">7</span>
</div>

SCSS:

$digit-width: 18px;
.counter {

    text-align: center;
    font-size: $digit-width;

    position: relative;

    width : $digit-width * 4.5;
    margin: 0 auto;
    height: 48px;
}
.counter-digit {

    position: absolute;
    top: 0;
    width: $digit-width;
    height: 48px;
    line-height: 48px;
    padding: 0 1px;

    &:nth-child(1) { left: 0; text-align: right; }
    &:nth-child(2) { left: $digit-width * 1; text-align: left;}
    &:nth-child(3) { left: $digit-width * 2; text-align: center; width: $digit-width / 2} // the divider (/)
    &:nth-child(4) { left: $digit-width * 2.5; text-align: right;}
    &:nth-child(5) { left: $digit-width * 3.5; text-align: left;}
}
于 2014-12-04T15:55:45.250 回答
1

您可以将秒位数字包装在一个跨度中,并将其设置为... .time-seconds {display: inline-block;width: .52em;text-align: center;} 请参阅代码段。

function padlength(what) {
  var output = (what.toString().length == 1) ? "0" + what : what;
  return output;
}

function displaytime() {
  var serverdate = new Date();
  var dd = "am";
  var hh = serverdate.getHours();
  var h = hh;
  if (h >= 12) {
    h = hh - 12;
    dd = "pm";
  }
  if (h == 0) {
    h = 12;
  }
  h = parseInt(h);
  var sec = String(padlength(serverdate.getSeconds()));
  var timeFixed = h + ':' + padlength(serverdate.getMinutes()) + ':<span class="time-seconds">' + sec.charAt(0) + '</span><span class="time-seconds">' + sec.charAt(1) + '</span> ' + dd;
  timeVariable = h + ':' + padlength(serverdate.getMinutes()) + ':' + sec + ' ' + dd;
  document.getElementById("servertime-fixed").innerHTML = timeFixed;
  document.getElementById("servertime-variable").innerHTML = timeVariable;
}

window.onload = function() {
  displaytime();
  setInterval("displaytime()", 1000);
};
center {
  font-size: 3em;
  font-family: Cursive;
}

.time-seconds {
  display: inline-block;
  width: .52em;
  text-align: center;
}
<html>

<body>
  <center id="servertime-fixed">H:MM:SS mm</center>
  <center id="servertime-variable">H:MM:<span class="time-seconds">S</span><span class="time-seconds">S</span> mm</center>
</body>

</html>

于 2021-12-04T21:35:48.430 回答
0

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

于 2012-04-13T22:58:42.470 回答
0

不,没有办法在 CSS 中强制执行任何操作。甚至没有办法建议将非等宽字体呈现为等宽字体。

于 2012-04-13T23:00:01.257 回答