CSS:在不改变容器大小的情况下加粗一些文本

Posted

技术标签:

【中文标题】CSS:在不改变容器大小的情况下加粗一些文本【英文标题】:CSS: bolding some text without changing its container's size 【发布时间】:2011-08-06 22:04:46 【问题描述】:

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

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

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

【问题讨论】:

为什么尺寸变化有问题?它是否以某种方式弄乱了布局? 我认为最好在 Stack Overflow 上提出 Web 编程问题。也许一个模组会把它迁移到那里。 Chaulky:因为在布局方面,没有什么比你应该尝试点击跳转按钮更让我讨厌的东西了 doejo.com/blog/… 是我发现的一种解决方案,它完全符合 John 和 Blowski 所说的 jscript。 Inline elements shifting when made bold on hover的可能重复 【参考方案1】:

有趣的问题。我想你使用的是浮点数,对吧?

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

我知道避免这种变化的唯一解决方案是您说您不想要的解决方案:将固定大小设置为 li's。

【讨论】:

【参考方案2】:

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

我唯一能想到的是使用一些 javascript 来计算选项卡在加粗之前的宽度,然后在需要加粗的同时应用宽度(悬停或单击时)。

【讨论】:

hm,我将对此进行试验,尽管我希望它至少对于非 JS 用户来说看起来合理(即加粗)。也许我可以将它加粗发送,使用 JS 将其取消加粗,计算宽度,然后再次加粗?或者这只是愚蠢的? 是的,这听起来像是适应非 JavaScript 用户的最佳方式。【参考方案3】:

使用 JavaScript 根据未加粗的内容设置 li 的固定宽度,然后通过将样式应用于 <a> 标记(如果 <li> 没有任何子标记,则添加跨度) .

【讨论】:

糟糕 - 抱歉重复:$ 还是谢谢你的回答:) @Mala 您找到解决方案了吗?有趣的是,我也有类似的问题。【参考方案4】:

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

【讨论】:

我喜欢这个解决方案,尽管我建议将其翻转为 1px 0px 0px。看起来更大胆一些。 我需要一个纯 CSS 的解决方案,这就是答案。 仅添加 li:hover text-shadow: 1px 0 0 black; 会导致文本的字母间距过小。为了再次改进,我们还设置了li letter-spacing: 1px; 我使用了-0.5px 0 #fff, 0.5px 0 #fff,因为我们可以看到文本本身和阴影之间的小间隙。而且当文本加粗时,它会增加两边的重量。 我认为这不是一个好的解决方案,粗体字体不仅仅是更宽的字体,大多数字体都有特殊的粗体字母形式。【参考方案5】:

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

【讨论】:

【参考方案6】:

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

a 
   letter-spacing: 1px;


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

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

【讨论】:

这是最好的也是最被低估的解决方案,虽然我改变了它,使它从 0 开始并在粗体时变为负字母间距。您还必须针对每种字体和字体大小对其进行微调。我还更新了@Thorgeir 的小提琴以包括这个(作为第二个解决方案)jsfiddle.net/dJcPn/50/ 现代浏览器现在支持亚像素精度。因此,您可以使用 0.98px 或更小的分数来微调间距。 这看起来有点奇怪,因为间距算法并不完全相同(一些字母会跳动一点),更重要的是,当字体缩放时,这不起作用,即使你转换1px0.025ex0.0125ex 等相对值。请参阅my answer 进行现场演示。 @AdamKatz 我怀疑自发布此答案以来字体渲染已发生变化,这在很大程度上取决于您使用的字体。【参考方案7】:

使用 ::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://***.com/a/20249560/5061744

【讨论】:

这是最可靠和干净的解决方案,它只是为元素中的粗体文本保留空间。在我的例子中,额外的伪元素导致了高度的变化。将负数 margin-top 添加到 ::after 块解决了这个问题。 这个解决方案很棒!我使用 JS 添加了一个包含元素文本的“data-content”属性,这样我就可以避免更改 html 太棒了。这应该是最好的答案。请注意,如果与 li 不同的元素,您可能必须使用 display:block;在 :after 父元素上。 很好的解决方案!也可以与 ::before 一起使用,在我的情况下,这可以防止底部有额外的边距。 感谢您提供此解决方案。我最初使用 text-shadow 但这在 Safari 中不起作用,因为它会四舍五入十进制值。由于我使用的是 0.1px,因此将其四舍五入为 0。您的解决方案完美无缺。我只用名称替换了标题属性,因为我不想显示工具提示【参考方案8】:

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

  li:hover  text-shadow: -0.06ex 0 currentColor, 0.06ex 0 currentColor; 

这会在每个字母的两侧使用可随字体渲染正确缩放的单位,在字体的当前颜色中添加微小的“阴影”(如有必要,使用字体的颜色名称/代码代替 currentColor)。

警告: px 值确实支持十进制值,但是当字体大小改变时它们看起来不会那么好(例如,用户使用 Ctrl++)。请改用相对值。

此答案使用ex 单位的分数,因为它们随字体缩放。 在〜大多数浏览器默认设置* 中,预计1ex8px 并因此0.025ex0.1px

自己看看:

li:hover       font-weight: normal!important; text-shadow: none!important; 
.shadow0       text-shadow: inherit; 
.shadow2       text-shadow: -0.02ex 0 currentColor, 0.02ex 0 currentColor; 
.shadow4       text-shadow: -0.04ex 0 currentColor, 0.04ex 0 currentColor; 
.shadow6       text-shadow: -0.06ex 0 currentColor, 0.06ex 0 currentColor; 
.shadow8       text-shadow: -0.08ex 0 currentColor, 0.08ex 0 currentColor; 
.bold          font-weight: bold; 
.bolder        font-weight: bolder; 
.after span    display:inline-block; font-weight: bold;  /* @SlavaEremenko */
.after:hover span   font-weight:normal; 
.after span::after  content: attr(title); font-weight: bold;
                     display: block; height: 0; overflow: hidden; 
.ltrsp         letter-spacing:0px; font-weight:bold;  /* @Reactgular */
.ltrsp:hover   letter-spacing:1px; 
<li class="shadow0">MmmIii123 This tests shadow0 (plain)</li>
<li class="shadow2">MmmIii123 This tests shadow2 (0.02ex)</li>
<li class="shadow4">MmmIii123 This tests shadow4 (0.04ex)</li>
<li class="shadow6">MmmIii123 This tests shadow6 (0.06ex)</li>
<li class="shadow8">MmmIii123 This tests shadow8 (0.08ex)</li>
<li class="after"><span title="MmmIii123 This tests [title]"
                   >MmmIii123 This tests [title]</span> (@SlavaEremenko)</li>
<li class="ltrsp"  >MmmIii123 This tests ltrsp (@Reactgular)</li>
<li class="bold"   >MmmIii123 This tests bold</li>
<li class="bolder" >MmmIii123 This tests bolder</li>
<li class="shadow2 bold">MmmIii123 This tests shadow2 (0.02ex) + bold</li>
<li class="shadow4 bold">MmmIii123 This tests shadow4 (0.04ex) + bold</li>
<li class="shadow6 bold">MmmIii123 This tests shadow6 (0.06ex) + bold</li>
<li class="shadow8 bold">MmmIii123 This tests shadow8 (0.08ex) + bold</li>

将鼠标悬停在渲染的线条上,看看它们与标准文本有何不同。

更改浏览器的缩放级别(Ctrl++Ctrl+-)以查看它们的变化.

我在此处添加了另外两个解决方案以进行比较:@Reactgular's letter spacing trick,因为它涉及猜测字体宽度范围,所以效果不佳,以及@SlavaEremenko'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 带有一个滑块,可以玩各种等级。 Google 的 Introduction to variable fonts on the web 有一个动画 GIF,展示了高分和无分之间的切换:

【讨论】:

如此简单,如此美丽。 这在 Firefox 82(我键入时)和 Safari 上存在问题。似乎使用0.5px 是一个更好的选择。 您可以使用currentColor 代替black 或任何特定颜色(尽管我没有在许多浏览器上测试过) @DavidGilbertson – 不错的电话。 currentColor 是supported universally,所以我把它加到代码里了。【参考方案9】:

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

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

此处提供的解决方案在 Chrome 中对我不起作用。 输入和标签的垂直对齐被 :after 伪类弄乱了,-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>

【讨论】:

【参考方案10】:

如需更多最新答案,您可以使用-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编辑:@Lars Blumberg 感谢您确认)。它不适用于 IE11 或更低版本。

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

【讨论】:

也适用于 Safari 13.0.5。迄今为止对我来说最干净的解决方案。 这在 Firefox 中有效,但要注意它看起来真的很难看,有点模糊。 不是一个好的解决方案,字体变得“更圆”,正如@MightyPork 提到的......模糊。【参考方案11】:

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

(为 TL 跳过此段;DR...) 我使用来自 cloud.typography.com 的 Gotham 网络字体,并且我的按钮开始是空心的(带有白色边框/文本和透明背景)并在悬停时获取背景颜色。我发现我使用的一些背景颜色与白色文本没有很好的对比,所以我想将这些按钮的文本更改为黑色,但是——无论是因为视觉技巧还是常见的抗锯齿方法——黑暗浅色背景上的文本总是看起来比深色背景上的白色文本更轻。我发现将深色文本的权重从 400 增加到 500 可以保持几乎完全相同的“视觉”权重。然而,它只是将按钮的宽度增加了很小的一部分——一个像素的一小部分——但这足以让按钮看起来有点“抖动”,我想摆脱它。

解决方案:

显然,这是一个非常挑剔的问题,因此需要一个挑剔的解决方案。最终我在上面推荐的 cgTag 的粗体文本上使用了否定的letter-spacing,但是 1px 会有点过分,所以我只是计算了我需要的宽度。

通过在 Chrome devtools 中检查按钮,我发现我的按钮的默认宽度是 165.47px,悬停时是 165.69px,相差 0.22px。该按钮有 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 样式通常不受欢迎,这是有充分理由的,但我认为这是一个用例,它是唯一有意义的选择。

【讨论】:

【参考方案12】:

我强烈建议为此用例尝试 uniwidth 字体。

它们仍然是比例字体(与等宽字体相反),但它们在不同的字体粗细中占据相同的大小无需 CSS、JS 或花哨的 hack 即可保持大小不变​​。它已融入字体。

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

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

Recursive PT Root UI Golos UI Grandstander

通过上述文章也链接了许多非免费选项。

【讨论】:

以上是关于CSS:在不改变容器大小的情况下加粗一些文本的主要内容,如果未能解决你的问题,请参考以下文章

在不改变字体大小的情况下控制字体粗细

如何在不改变绘图宽度的情况下使用 ggplot2 在 R 中添加可变大小的 y 轴标签?

如何在不使用 transform: scale 的情况下更改 CSS 切换开关的大小?

CXF 在不改变 http.maxConnections 的情况下增加连接池大小

CSS如何在不改变图像样式的情况下垂直居中图像和文本

在不自动调整大小的情况下确定 UIView 容器大小