web-dev-qa-db-ja.com

CSS:コンテナのサイズを変更せずにテキストを太字にする

水平ナビゲーションメニューがあり、基本的には<ul>要素を並べて設定します。私は幅を定義しませんが、幅をメニュー項目の幅で定義したいので、単にパディングを使用します。現在選択されているアイテムを太字にします。

問題は、太字の場合、Wordが少し広くなり、残りの要素が左または右にわずかに移動することです。これを防ぐ賢い方法はありますか?太字による余分な幅を無視するようにパディングに指示する線に沿って何か?私の最初の考えは、「アクティブな」要素のパディングから数ピクセルを単純に差し引くことでしたが、この量はさまざまです。

可能であれば、各エントリに静的な幅を設定してから、現在のパディングソリューションとは対照的に中央に配置することを避けて、エントリの将来の変更を簡単にします。

88
Mala

私は同じ問題を抱えていましたが、少し妥協して同様の効果を得ました。代わりにtext-shadowを使用しました。

li:hover {text-shadow:0px 0px 1px black;}

これが実際の例です:

body {
  font-family: segoe ui;
}

ul li {
  display: inline-block;
  border-left: 1px solid silver;
  padding: 5px
}

.textshadow :hover {
  text-shadow: 0px 0px 1px black;
}

.textshadow-alt :hover {
  text-shadow: 1px 0px 0px black;
}

.bold :hover {
  font-weight: bold;
}
<ul class="textshadow">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li><code>text-shadow: 0px 0px 1px black;</code></li>
</ul>

<ul class="textshadow-alt">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li><code>text-shadow: 1px 0px 0px black;</code></li>
</ul>

<ul class="bold">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li><code>font-weight: bold;</code></li>
</ul>

jsfiddleの例

126
Thorgeir

:: afterを使用した最適なソリューション

[〜#〜] html [〜#〜]

<li title="EXAMPLE TEXT">
  EXAMPLE TEXT
</li>

[〜#〜] css [〜#〜]

li::after {
  display: block;
  content: attr(title);
  font-weight: bold;
  height: 1px;
  color: transparent;
  overflow: hidden;
  visibility: hidden;
}

title属性をソースとする太字テキストの幅を持つ不可視の擬似要素を追加します。

text-shadowソリューションはMacでは不自然に見え、Macでのテキストレンダリングが提供するすべての美しさを利用しません。:)

http://jsfiddle.net/85LbG/

クレジット: https://stackoverflow.com/a/20249560/5061744

最も移植性が高く視覚的に満足のいくソリューションは、 _text-shadow_ を使用することです。これは Alexxaliの と私自身の微調整を使用して Thorgeirの答え の例を修正して示しています。

_  li:hover { text-shadow: -0.06ex 0 black, 0.06ex 0 black; }
_

これにより、フォントのレンダリングで適切にスケーリングされる単位を使用して、各文字の両側に小さな「影」が黒で表示されます(必要に応じてblackの代わりにフォントの色名/コードを使用します)。

warning 警告:px値は10進数値をサポートしますが、フォントサイズが変更された場合はそれほど大きく見えません(たとえば、ユーザーがビューを Ctrl++)。代わりに相対値を使用してください。

この回答では、フォントに合わせてスケーリングされるため、 ex 単位の端数を使用します。
〜ほとんどのブラウザのデフォルト * 、_1ex_≈_8px_、したがって_0.025ex_≈_0.1px_が必要です。

自分で見て:

_li             { color: #000; } /* set text color just in case */
.shadow0       { text-shadow: inherit; }
.shadow2       { text-shadow: -0.02ex 0 #000, 0.02ex 0 #000; }
.shadow4       { text-shadow: -0.04ex 0 #000, 0.04ex 0 #000; }
.shadow6       { text-shadow: -0.06ex 0 #000, 0.06ex 0 #000; }
.shadow8       { text-shadow: -0.08ex 0 #000, 0.08ex 0 #000; }
.bold          { font-weight: bold; }
.bolder        { font-weight: bolder; }
.after span        { display:inline-block; font-weight: bold; } /* workaholic… */
.after:hover span  { font-weight:normal; }
.after span::after { content: attr(title); font-weight: bold; display:block; 
                     height: 0; overflow: hidden; }
.ltrsp         { letter-spacing:0; font-weight:bold; } /* @cgTag */
li.ltrsp:hover { letter-spacing:0.0125ex; }
li:hover       { font-weight: normal!important; text-shadow: none!important; }_
_<li class="shadow0">MmmIii123 This line tests shadow0 (plain)</li>
<li class="shadow2">MmmIii123 This line tests shadow2 (0.02ex)</li>
<li class="shadow4">MmmIii123 This line tests shadow4 (0.04ex)</li>
<li class="shadow6">MmmIii123 This line tests shadow6 (0.06ex)</li>
<li class="shadow8">MmmIii123 This line tests shadow8 (0.08ex)</li>
<li class="after"><span title="MmmIii123 This line tests [title]"
                   >MmmIii123 This line tests [title]</span> (@workaholic…)</li>
<li class="ltrsp"  >MmmIii123 This line tests ltrsp (@cgTag)</li>
<li class="bold"   >MmmIii123 This line tests bold</li>
<li class="bolder" >MmmIii123 This line tests bolder</li>
<li class="shadow2 bold">MmmIii123 This line tests shadow2 (0.02ex) + bold</li>
<li class="shadow4 bold">MmmIii123 This line tests shadow4 (0.04ex) + bold</li>
<li class="shadow6 bold">MmmIii123 This line tests shadow6 (0.06ex) + bold</li>
<li class="shadow8 bold">MmmIii123 This line tests shadow8 (0.08ex) + bold</li>_

レンダリングされた行にカーソルを合わせて、標準のテキストとの違いを確認します。

ブラウザのズームレベルを変更します(Ctrl++ そして Ctrl+-)それらがどのように変化するかを確認します。

比較のために他の2つのソリューションをここに追加しました: @ cgTagの文字間隔トリック (フォント幅の範囲を推測する必要があるためうまく機能しません)、および @ workaholic_gangster911の::トリック を描画すると、厄介な余分なスペースが残るため、太字テキストは隣接するテキスト項目をナッジすることなく拡大できます(太字テキストの後に属性を配置して、移動しない方法を確認します)。


将来的に、font-variation-settings_を介して font grade を変更するなどの機能を備えた 可変フォント が追加される予定です。 ブラウザのサポート は強化されています(Chrome 63 +、Firefox 62+)が、これにはまだ標準フォント以上のものが必要であり、いくつかの既存のフォントがサポートしています。

可変フォントを埋め込むと、次のようなCSSを使用できます。

_/* Grade: Increase the typeface's relative weight/density */
@supports (font-variation-settings: 'GRAD' 150) {
  li:hover { font-variation-settings: 'GRAD' 150; }
}
/* Failover for older browsers: tiny shadows at right & left of the text
 * (replace both instances of "black" with the font color) */
@supports not (font-variation-settings: 'GRAD' 150) {
  li:hover { text-shadow: -0.06ex 0 black, 0.06ex 0 black; }
}
_

Mozilla Variable Fonts Guideには、さまざまなグレードで遊ぶためのスライダー付きの live demo があります。 Googleの ウェブ上の可変フォントの紹介 には、高グレードと無グレードの切り替えを示すアニメーションGIFがあります。

animated Amstelvar Alpha font demo with toggling grade axis

22
Adam Katz

文字間隔を1px調整すると、ほとんどのフォントが同じサイズであることがわかりました。

a {
   letter-spacing: 1px;
}

a:hover {
   font-weight: bold;
   letter-spacing: 0px;
}

これは通常のフォントを変更するので、各文字には余分なピクセル間隔があります。メニューの場合、タイトルは非常に短いため、問題にはなりません。

16
Reactgular

残念ながら、テキストが太字のときに幅が変化しないようにする唯一の方法はリスト項目の幅を定義することですが、これを手動で行うと時間がかかり、スケーラブルではありません。

私が考えることができる唯一のことは、太字になる前にタブの幅を計算し、太字が必要なときに(ホバーまたはクリックしたときに)タブの幅を適用するJavaScriptを使用することです。

4
ajcw

JavaScriptを使用して、太字でないコンテンツに基づいてliの固定幅を設定し、<a>タグにスタイルを適用してコンテンツを太字にします(または<li>に子がない場合はスパンを追加します) )。

2
Dan Blows

最新の回答については、-webkit-text-stroke-width

.element {
  font-weight: normal;
}

.element:hover {
  -webkit-text-stroke-width: 1px;
  -webkit-text-stroke-color: black;
}

これにより、擬似要素(スクリーンリーダーにとってプラス)やテキストシャドウ(乱雑に見え、わずかな「ジャンプ」効果が得られる)や固定幅の設定(非実用的)が回避されます。

また、要素を1pxより太字に設定することもできます(理論的には、フォントを好きなように太字にすることができます。カスタムフォントのような変種。一部のフォントがひっかき傷やギザギザになる可能性があるため、これは避けるべきです

これは、Edge、Firefox、ChromeおよびOperaの最新リリースで確実に動作します。Safari(Operaは通常、その優れたバロメーターです)で動作すると想定していますが、 Safari:IE11以前では動作しません。

また、-webkitプレフィックスなので、これは標準ではなく、サポートは将来廃止される可能性があります。したがって、これは太字であることに依存しないことが本当に重要です-単に美的でない限り、この手法を避けるのが最善です。

1
Oliver

これは非常に古い質問ですが、開発中のアプリにこの問題があり、ここですべての答えが欲しいと思ったので、再訪しています。

(TLのこの段落をスキップ; DR ...) cloud.typography.comのGotham webfontを使用していますが、中空のボタン(白い境界線/テキストと透明な背景)とホバーで背景色を取得します。使用している背景色の一部が白いテキストとうまくコントラストをとらないことがわかったため、これらのボタンのテキストを黒に変更したかったのですが、視覚的なトリックや一般的なアンチエイリアシング方法のために、暗い明るい背景のテキストは常に、暗い背景の白いテキストよりも軽いように見えます。暗いテキストの重量を400から500に増やすと、ほぼ同じ「視覚的な」重量が維持されることがわかりました。ただし、ボタンの幅をほんの少し(ピクセルの何分の1か)だけ増加させていましたが、ボタンをわずかに「ジッター」させるように表示するには十分でした。

解決策:

明らかに、これは本当に細かい問題なので、細かい解決策が必要でした。最終的には、上記の推奨されるcgTagとして太字のテキストに負のletter-spacingを使用しましたが、1pxが多すぎるので、必要な幅を正確に計算しました。

Chrome devtoolsでボタンを調べると、ボタンのデフォルトの幅は165.47ピクセルで、ホバーでは165.69ピクセルで、0.22ピクセルの差があります。ボタンは9文字でした。

0.22/9 = 0.024444px

それをem単位に変換することにより、フォントサイズを調整しないで調整できます。私のボタンは16pxのフォントサイズを使用していました。

0.024444/16 = 0.001527em

私の特定のフォントについては、次のCSSがホバーでボタンexactlyと同じ幅を維持します。

.btn {
  font-weight: 400;
}

.btn:hover {
  font-weight: 500;
  letter-spacing: -0.001527em;
}

上記の式を少しテストして使用すると、状況に合ったletter-spacing値を正確に見つけることができ、フォントサイズに関係なく機能します。

1つの注意点は、ブラウザーごとにわずかに異なるサブピクセル計算を使用することです。したがって、このOCDレベルのサブピクセル完全精度を目指している場合は、テストを繰り返し、ブラウザーごとに異なる値を設定する必要があります。 ブラウザをターゲットにしたCSSスタイルは一般的に眉をひそめています、これには正当な理由がありますが、これは意味のある唯一のオプションであるユースケースだと思います。

1
dannymcgee

Amazon.comの「部門別ショップ」ホバーメニューのように実装できます。広いdivを使用します。幅広のdivを作成して、その右側の部分を非表示にすることができます

0
Andrus

更新:IE11では、visibility:hiddenのときに擬似クラスi:afterが表示されなかったため、タイトルにBタグを使用する必要がありました。

私の場合、入力がチェックされるとテキストが太字になるラベルテキストに(カスタムデザインの)入力チェックボックス/ラジオを揃えたいと思います。

ここで提供されているソリューションは、Chromeでは機能しませんでした。入力とラベルの垂直方向の配置が:after psuedoクラスで台無しになり、-marginsはこれを修正しませんでした。

これは、垂直方向の配置で問題が発生しない修正です。

/* checkbox and radiobutton */
label
{
    position: relative;
    display: inline-block;
    padding-left: 30px;
    line-height: 28px;
}

/* reserve space of bold text so that the container-size remains the same when the label text is set to bold when checked. */
label > input + b + i
{
    font-weight: bold;
    font-style: normal;
    visibility: hidden;
}

label > input:checked + b + i
{
    visibility: visible;
}

/* set title attribute of label > b */
label > input + b:after
{
    display: block;
    content: attr(title);
    font-weight: normal;
    position: absolute;
    left: 30px;
    top: -2px;
    visibility: visible;
}

label > input:checked + b:after
{
    display: none;
}

label > input[type="radio"],
label > input[type="checkbox"]
{
    position: absolute;
    visibility: hidden;
    left: 0px;
    margin: 0px;
    top: 50%;
    transform: translateY(-50%);
}

    label > input[type="radio"] + b,
    label > input[type="checkbox"]  + b
    {
        display: block;
        position: absolute;
        left: 0px;
        margin: 0px;
        top: 50%;
        transform: translateY(-50%);
        width: 24px;
        height: 24px;
        background-color: #00a1a6;
        border-radius: 3px;
    }

    label > input[type="radio"] + b
    {
        border-radius: 50%;
    }

    label > input:checked + b:before
    {
        display: inline-block;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%) rotate(45deg);
        content: '';
        border-width: 0px 3px 3px 0px;
        border-style: solid;
        border-color: #fff;
        width: 4px;
        height: 8px;
        border-radius: 0px;
    }

    label > input[type="checkbox"]:checked + b:before
    {
        transform: translate(-50%, -60%) rotate(45deg);
    }

    label > input[type="radio"]:checked + b:before
    {
        border-width: 0px;
        border-radius: 50%;
        width: 8px;
        height: 8px;
    }
<label><input checked="checked" type="checkbox"/><b title="Male"></b><i>Male</i></label>
<label><input type="checkbox"/><b title="Female"></b><i>Female</i></label>
0
Erik

興味深い質問。フロートを使用していると思いますか?

まあ、このフォントの拡大を取り除くために使用できるテクニックはわかりません。したがって、必要な最小幅に収まるようにしようとします-フォントの太さを変えるとこの値が変わります。

この変更を回避するために私が知っているユニークな解決策は、あなたが望まないと言ったものです:固定サイズをliに設定します。

0
Dave