有没有办法使用CSS来强制字体成为等宽字体?
我的意思是,在使用非等宽字体的情况下,你能否强制浏览器以固定的宽度呈现每个字符?
有没有办法使用CSS来强制字体成为等宽字体?
我的意思是,在使用非等宽字体的情况下,你能否强制浏览器以固定的宽度呈现每个字符?
如果这是用于对齐表格中的数字,其中一些字体(具有传统排版)在默认情况下以可变宽度呈现它们(例如Windows上的Segoe UI),您应该研究以下CSS属性:
font-variant-numeric: tabular-nums;
(这将禁用 numeric-spacing
变体的 proportional-nums
默认值,该变体至少由 OpenType 字体支持,并且可能由您特定平台上的 Web 浏览器的文本渲染器支持的其他字体格式支持)
无需 JavaScript!这是禁用这些字体中可变宽度字形并强制使用表格数字的最清晰的方式(通常使用相同字体中的相同字形,但其前导和尾随间隙增加,以便 0 到 9 的 10 个数字将以相同宽度呈现;然而,某些字体可能会避免视觉上可变的数字间距,并略微扩大某些数字,或者在数字 1 的底部添加底横线)。
请注意,这不会禁用 Segoe UI 观察到的可变高度(例如,某些数字只有 x 高度,如小写字母,而其他数字具有上伸部分或下降部分)。这些传统数字形式也可以使用 CSS 禁用。
font-variant-numeric: lining-nums;
(这将禁用默认的oldstyle-nums
值,该值至少由OpenType字体支持,并且可能由您特定平台的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
请注意,对于'Segoe UI'字体来说,'normal'样式与'tabular-new'样式相同(即'tabular-nums lining-nums')。并非所有定义数字变体的字体都是如此,并且并非所有数字系统都是如此(如果不显示拉丁数字,例如某些原生婆罗门数字,特别是如果它们来自不支持所有这些样式的回退字体)。此外,这对于非数字字符没有影响,它们保留其可变宽度,但可以通过其他CSS属性或使用编码变体控制来定义特定的变体。
如果您使用罗马数字系统中的数字,这些数字可能仍然以可变宽度呈现(例如,1968年的"MCMLXVIII"),除非HTML包含一些CSS样式,允许将它们的语义更改为数字而不是字母,或者这些数字以不同的方式编码,例如在CJK字体中具有"fullwidth"变体,或者在数学字体中定义了具有特定代码点的特定样式变体,而不是使用样式和标记。
font-feature-settings: 'tnum' 1;
或font-feature-settings:'tnum' on;
进行设置,参见https://developer.mozilla.org/en-US/docs/Web/CSS/font-feature-settings ,但请注意MDN的说明:
“如果有可能,Web作者应该改用[...]font-variant-numeric
”。 - mrienstra为什么不打破常规,使用表格来解决这个问题:
<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>
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>
我刚发现了 text-transform: full-width;
这个实验性的关键字,它可以:
[...] 强制字符写在方块内 [...]
与负的 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.
好的,你没有说只使用CSS。通过使用一点Javascript将每个字母包装在标签中,这样做是可行的。剩下的就用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符号时将常规文本向右移动的问题时发现了这个问题。
有时候我为倒计时做了一件非常漂亮的事情:
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;}
}
.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>
font-variant-numeric: tabular-nums
(这一点我知道),而其他解决方案也不适合我,所以我想出了这个方法——在我的情况下,我只需要扩大字母间距,然后压缩(巨大的)零,使其看起来可接受:
CSS:
.squashzeros { letter-spacing:.2em; }
.squashzeros span { display:inline-block; margin:0 -.09em; }
JS:
document.querySelectorAll('.squashzeros').forEach((o)=>{
o.innerHTML = o.innerText.replaceAll(/0/g,'<span>0</span>');
});
很遗憾,我没有找到纯CSS的解决方案。
结合了Márton Tamás和nïkö的回答:
document.querySelectorAll('pre').forEach( o => {
o.innerHTML = o.innerText.replace(/(.)/g, '<i>$1</i>');
});
pre i {
font-style: normal;
font-family: serif;
display: inline-block;
width: 0.65em;
text-align: center;
}
<!-- Fixed-width serif -->
<pre>
. i I 1 | This is gonna be awesome. 12:10
ASDFGHJK | This is gonna be awesome. 08:51
</pre>
<!-- Default font -->
. i I 1 | This is gonna be awesome. 12:10
<br>
ASDFGHJK | This is gonna be awesome. 08:51
 
。由于它有些奇特,在MS Word中缺乏,通常根本没有空格。但是当您使一个align=justify
文本时,像 "№1234" 这样的术语内部的间隙宽度在不同的行中变得不同!看起来很糟糕。并且要注意:Google更改了 № 符号的宽度以使文本变丑。 - Arioch 'The