web-dev-qa-db-ja.com

CSSを使用して非等幅フォントを固定幅に強制する

CSSを使用してフォントを強制的に等幅にする方法はありますか?

つまり、非等幅フォントを使用して、ブラウザに各文字を固定幅でレンダリングさせることができますか?

45
Jon Raasch

これが、いくつかのフォント(従来のタイポグラフィを使用)がデフォルトで可変幅でレンダリングするテーブル(たとえば、WindowsのSegoe UI)で数字を揃えるためのものである場合、次のCSSプロパティを調べる必要があります。

font-variant-numeric: tabular-nums;

(これにより、少なくともOpenTypeフォントでサポートされているproportional-numsバリアントのnumeric-spacingデフォルト値が無効になり、特定のプラットフォームのWebブラウザーのテキストレンダラーでサポートされている他のフォントフォーマットが無効になる場合があります)

JavaScriptは必要ありません。これは、これらのフォントの可変幅のグリフを無効にし、表形式の数字を使用するよう強制する最もクリーンな方法です(これは通常、同じフォントの同じグリフで使用されますが、先頭と末尾のギャップが大きくなるため、10桁が0から9は同じ幅でレンダリングしますが、一部のフォントは視覚的な可変桁間スペースを回避し、一部の桁を少し隠すか、または桁1の下部に下部セリフを追加する可能性があります。

これはSegoe UIで観察される変数の高さを無効にしないことに注意してください(一部の桁は小文字と同じようにx-heightになり、他の桁はアセンダーまたはディセンダーを持つ)。これらの従来の数字形式は、CSSでも無効にすることができます。

font-variant-numeric: lining-nums;

(これにより、少なくともOpenTypeフォントでサポートされているoldstyle-numsバリアントのデフォルトのnumeric-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; }
<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/fr/docs/Web/CSS/font-variant-numeric

30
verdy_p

CSSではこれを行うことはできません。できたとしても、結果は恐ろしいものになります。

enter image description here

本当にこれを行う必要がある場合は、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>
10
Blender

これについては、ボックスの外側とテーブルの内側を考えてみてください。

<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>
10
Dour High Arch

いいえ、CSSで何かを強制する方法はありません。また、非等幅フォントを等幅フォントとしてレンダリングすることを提案する方法さえありません。

4

text-transform: full-width;実験的なキーワードを見つけました。

[...]四角形の内側に文字を強制的に書き込みます[...]

テキスト変換| MDN

負のletter-spacingと組み合わせると、それほどひどくない結果が得られます。

Fixed-width sans-serif font to mock monospaced font

<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.
3
Márton Tamás

まあ、あなたはonly 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シンボルの解決策を見つけようとしたときに、この質問を見つけました。

2
Vince

私は時々カウントダウンのために非常にかわいいことをしました:

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

いいえ、それが実際の等幅フォントでなければなりません。

1
jeremyharris