CSS:粗体化一些文本而不改变其容器的大小

时间:2011-04-15 22:18:41

标签: css fonts menu

我有一个水平导航菜单,它基本上只是一个<ul>,并排设置了元素。我没有定义宽度,只是使用填充,因为我希望宽度由菜单项的宽度定义。我加粗了当前所选的项目。

麻烦的是,在粗体中,单词变得稍宽,这导致其余元素稍微向左或向右移动。有没有一种聪明的方法可以防止这种情况发生?告诉padding忽略由粗体引起的额外宽度的问题?我的第一个想法是简单地从“活动”元素的填充中减去几个像素,但这个数量会有所不同。

如果可能的话,我想避免在每个条目上设置静态宽度然后居中而不是我目前的填充解决方案,以便将来对条目的更改变得简单。

12 个答案:

答案 0 :(得分:119)

我遇到了同样的问题,但是稍微妥协得到了类似的效果,我使用了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 example

答案 1 :(得分:75)

使用:: 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

答案 2 :(得分:21)

最便携且视觉上最令人愉悦的解决方案是使用text-shadow。 这将修改并显示Thorgeir's answer使用Alexxali's和我自己的调整的示例:

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

这会带来微小的阴影&#34;黑色(使用您的字体的颜色名称/代码代替black,如果需要)使用可以使用字体渲染正确缩放的单位在每个字母的两侧。

  

warning 警告: px值确实支持十进制值,但是当字体大小发生变化时,它们看起来不会很好(例如,用户缩放视图使用 Ctrl + + )。改为使用相对值。

     

此答案使用ex单位的分数,因为它们会按字体缩放。
在〜大多数浏览器默认值*中,期望1ex8px因此0.025ex0.1px

亲眼看看:

&#13;
&#13;
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; }
&#13;
<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>
&#13;
&#13;
&#13;

将鼠标悬停在渲染的线条上,以查看它们与标准文字的区别。

更改浏览器的缩放级别( Ctrl + + Ctrl + - )看看它们是如何变化的。

我在此处添加了另外两个解决方案进行比较:@cgTag's letter spacing trick,由于涉及猜测字体宽度范围而无法正常工作,而@workaholic_gangster911's ::after drawing trick会留下尴尬的额外空间,因此大胆文本可以扩展而不会轻推相邻的文本项(我将粗体文本后面的属性放在一起,这样你就可以看到它不会移动了。)

将来,我们会有更多variable fonts能够通过font-variation-settings更改字体等级等内容。 Browser support正在逐渐增加(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可变字体指南中有一个live demo滑块可以播放各种等级。谷歌的Introduction to variable fonts on the web有一个动画GIF,展示高等级和无等级之间的切换:

animated Amstelvar Alpha font demo with toggling grade axis

答案 3 :(得分:15)

我发现当你将字母间距调整为1px时,大多数字体都是相同的。

a {
   letter-spacing: 1px;
}

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

虽然这确实改变了常规字体,但每个字母都有一个额外的像素间距。对于菜单,标题很短,不会出现问题。

答案 4 :(得分:3)

不幸的是,当文本为粗体时,避免宽度更改的唯一方法是定义列表项的宽度,但是正如您所说,手动执行此操作非常耗时且无法扩展。

我唯一能想到的是使用一些javascript来计算标签宽度,然后再加粗,然后在需要加粗的同时应用宽度(当你悬停或点击时)。

答案 5 :(得分:1)

使用JavaScript根据非压缩内容设置li的固定宽度,然后通过将样式应用于<a>标记来加粗内容(如果<li>不添加,则添加范围有孩子)。

答案 6 :(得分:0)

有趣的问题。我想你正在使用浮动,对吧?

好吧,我不知道你可以使用任何技术来摆脱这种字体放大,因此它们会尝试适应所需的最小宽度 - 而不同的字体厚度会改变这个值。

我知道避免这种变化的独特解决方案是你说你不想要的:将固定尺寸设置为li。

答案 7 :(得分:0)

您可以像amazon.com“按部门购物”悬停菜单一样实现此功能。它使用宽div。您可以创建宽div并隐藏其右侧部分

答案 8 :(得分:0)

更新:必须使用B标签作为标题,因为在IE11中伪类i:之后没有显示我有可见性:隐藏。

在我的情况下,我想将(自定义设计的)输入复选框/收音机与标签文本对齐,当选中输入时文本变为粗体。

此处提供的解决方案在Chrome中对我无效。 输入和标签的垂直对齐方式搞砸了:在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>

答案 9 :(得分:0)

这是一个非常老的问题,但是我正在重新研究它,因为我在正在开发的应用程序中遇到了这个问题,并发现这里想要所有答案。

(跳过本段的TL; DR ...)。我使用的是cloud.typography.com上的Gotham网络字体,并且按钮的开头是空心的(带有白色边框/文字和透明背景),并在悬停时获取背景色。我发现我使用的某些背景颜色与白色文本无法很好地形成对比,因此我想将这些按钮的文本更改为黑色,但是-由于视觉技巧或常用的抗锯齿方法-深色浅色背景上的文字总是比深色背景上的白色文字轻。我发现,将深色文本的权重从400增加到500,可以保持几乎完全相同的“视觉”权重。但是,它只是将按钮的宽度增加了一小部分(像素的几分之一),但这足以使按钮看起来略微“抖动”,这是我想要消除的。

解决方案:

显然,这是一个非常棘手的问题,因此需要一个棘手的解决方案。最终,我对上面建议的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在悬停时将按钮完全保持相同的宽度:

.btn {
  font-weight: 400;
}

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

稍作测试并使用上述公式,您可以找到适合自己情况的正确letter-spacing值,并且无论字体大小如何,该值都可以工作。

一个警告是,不同的浏览器使用的子像素计算略有不同,因此,如果要达到OCD级别的亚像素完美精度,则需要重复测试并为每个浏览器。 以浏览器为目标的CSS样式通常会被反对,这是有充分理由的,但是我认为这是一个用例,它是唯一有意义的选择。

答案 10 :(得分:0)

我强烈建议在此用例中尝试使用 uniwidth 字体。

它们仍然是成比例的字体(与等宽字体相反),但它们在不同的字体粗细中占据相同的大小不需要 CSS、JS 或花哨的技巧来保持大小不变​​。它直接融入字体中。

这是来自 this excellent article 的示例,将比例字体 IBM Plex Sans 与 uniwidth Recursive 进行比较。

comparing proportional to uniwidth font

您可以尝试的免费单宽字体有:

上述文章中还链接了许多非免费选项。

答案 11 :(得分:-1)

要获得更新的答案,您可以使用-webkit-text-stroke-width

.element {
  font-weight: normal;
}

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

这可以避免任何伪元素(对于屏幕阅读器来说是一个加分)和文本阴影(看起来很混乱,仍然可以创建轻微的“跳跃”效果)或设置任何固定宽度(可以是不切实际的。)

它还允许您将元素设置为比1px更大胆(理论上,您可以根据需要制作粗体字体,也可以是一种伪劣的锻炼方式,用于创建粗体版本的字体,而不是#39 ; t有一个大胆的变体,比如自定义字体。虽然这应该避免,因为它可能会使一些字体显得沙哑和锯齿状)

我绝对可以在Edge,Firefox,Chrome和Opera的最新版本中使用。我认为它适用于Safari(Opera通常是一个很好的晴雨表)虽然我还没有在Safari上测试它。它在IE11或更低版本中不起作用。

另请注意,它使用的是-webkit前缀,因此这不是标准配置,未来可能会放弃支持,所以不要依赖这个粗体是非常重要的 - 它是最好避免使用这种技术,除非它只是美学。