243

我使用 HTML 列表和 CSS 创建了一个水平菜单。除非您将鼠标悬停在链接上,否则一切正常。你看,我为链接创建了一个粗体悬停状态,现在菜单链接由于粗体大小的不同而发生了变化。

我遇到了与此 SitePoint 帖子相同的问题。但是,该帖子没有适当的解决方案。我到处寻找解决方案,但找不到。当然,我不可能是唯一一个尝试这样做的人。

有没有人有任何想法?

PS:我不知道菜单项中文本的宽度,所以我不能只设置 li 项的宽度。

.nav { margin: 0; padding: 0; }
.nav li { 
    list-style: none; 
    display: inline; 
    border-left: #ffffff 1px solid; 
}
.nav li a:link, .nav li a:visited { 
    text-decoration: none; 
    color: #000; 
    margin-left: 8px; 
    margin-right: 5px; 
}
.nav li a:hover{ 
    text-decoration: none; 
    font-weight: bold; 
}
.nav li.first { border: none; }
<ul class="nav">
    <li class="first"><a href="#">item 0</a></li>
    <li><a href="#">item 1</a></li>
    <li><a href="#">item 2</a></li>
    <li><a href="#">item 3</a></li>
    <li><a href="#">item 4</a></li>
</ul>

4

29 回答 29

466

通过使用与父悬停样式具有相同内容和样式的不可见伪元素来预设宽度。使用数据属性,如title,作为内容的来源。

li {
    display: inline-block;
    font-size: 0;
}

li a {
    display:inline-block;
    text-align:center;
    font: normal 16px Arial;
    text-transform: uppercase;
}

a:hover {
    font-weight:bold;
}

/* SOLUTION */
/* The pseudo element has the same content and hover style, so it pre-sets the width of the element and visibility: hidden hides the pseudo element from actual view. */
a::before {
    display: block;
    content: attr(title);
    font-weight: bold;
    height: 0;
    overflow: hidden;
    visibility: hidden;
}
<ul>
    <li><a href="#" title="height">height</a></li>
    <li><a href="#" title="icon">icon</a></li>
    <li><a href="#" title="left">left</a></li>
    <li><a href="#" title="letter-spacing">letter-spacing</a></li>
    <li><a href="#" title="line-height">line-height</a></li>
</ul>

于 2013-11-27T17:49:33.940 回答
52

一个妥协的解决方案是用文本阴影伪造粗体,例如:

文字阴影:0 0 0.01px 黑色;

为了更好地比较,我创建了这些示例:

a, li {
  color: black;
  text-decoration: none;
  font: 18px sans-serif;
  letter-spacing: 0.03em;
}
li {
  display: inline-block;
  margin-right: 20px;
  color: gray;
  font-size: 0.7em;
}
.bold-x1 a.hover:hover,
.bold-x1 a:not(.hover) {
  text-shadow: 0 0 .01px black;
}
.bold-x2 a.hover:hover,
.bold-x2 a:not(.hover){
  text-shadow: 0 0 .01px black, 0 0 .01px black;
}
.bold-x3 a.hover:hover,
.bold-x3 a:not(.hover){
  text-shadow: 0 0 .01px black, 0 0 .01px black, 0 0 .01px black;
}
.bold-native a.hover:hover,
.bold-native a:not(.hover){
  font-weight: bold;
}

.bold-native li:nth-child(4),
.bold-native li:nth-child(5){
 margin-left: -6px;
 letter-spacing: 0.01em;
}
<ul class="bold-x1">
  <li><a class="hover" href="#">Home</a></li>
  <li><a class="hover" href="#">Products</a></li>
  <li><a href="#">Contact</a></li>
  <li><a href="#">About</a></li>
  <li>Bold (text-shadow x1)</li>
</ul>
<ul class="bold-x2">
  <li><a class="hover" href="#">Home</a></li>
  <li><a class="hover" href="#">Products</a></li>
  <li><a href="#">Contact</a></li>
  <li><a href="#">About</a></li>
  <li>Extra Bold (text-shadow x2)</li>
</ul>
<ul class="bold-native">
  <li><a class="hover" href="#">Home</a></li>
  <li><a class="hover" href="#">Products</a></li>
  <li><a href="#">Contact</a></li>
  <li><a href="#">About</a></li>
  <li>Bold (native)</li>
</ul>
<ul class="bold-x3">
  <li><a class="hover" href="#">Home</a></li>
  <li><a class="hover" href="#">Products</a></li>
  <li><a href="#">Contact</a></li>
  <li><a href="#">About</a></li>
  <li>Black (text-shadow x3)</li>
</ul>

传递给text-shadow非常低的值blur-radius将使模糊效果不那么明显。

一般来说,你重复text-shadow的次数越多,你的文字就会越粗,但同时会失去字母的原始形状。

我应该警告您,将blur-radius分数设置为不会在所有浏览器中呈现相同的内容!例如,Safari 需要更大的值来渲染它,就像 Chrome 一样。

于 2013-04-03T10:51:22.190 回答
39

另一个想法是使用letter-spacing

li, a { display: inline-block; }
a {
  font-size: 14px;
  padding-left: 10px;
  padding-right: 10px;
  letter-spacing: 0.235px
}

a:hover, a:focus {
  font-weight: bold;
  letter-spacing: 0
}
<ul>
  <li><a href="#">item 1</a></li>
  <li><a href="#">item 2</a></li>
  <li><a href="#">item 3</a></li>
</ul>

于 2014-10-20T22:37:49.417 回答
28

如果你不能设置宽度,那么这意味着宽度会随着文本变粗而改变。没有办法避免这种情况,除非通过修改每个状态的填充/边距等妥协。

于 2009-02-17T10:09:28.663 回答
17

jquery中的一行

$('ul.nav li a').each(function(){
    $(this).parent().width($(this).width() + 4);
});

编辑: 虽然这可以带来解决方案,但应该提到它不能与原始帖子中的代码一起使用。"display:inline" 必须替换为浮动参数才能使宽度设置生效并且水平菜单按预期工作。

于 2010-10-29T09:08:38.560 回答
13

CSS3 解决方案 - 实验性

(假大胆)

想分享一种不同的解决方案,这里没有人建议。有一个名为的属性text-stroke将对此很方便。

p span:hover {
  -webkit-text-stroke: 1px black;
}
<p>Some stuff, <span>hover this,</span> it's cool</p>

在这里,我定位span标签内的文本,我们用一个像素来描边它,该像素black将模拟bold该特定文本的样式。

请注意,此属性并未得到广泛支持,截至目前(在编写此答案时),似乎只有 Chrome 和 Firefox 支持此属性。有关浏览器支持的更多信息text-stroke,可以参考CanIUse


只是为了分享一些额外的东西,如果你不想为你的中风-webkit-text-stroke-width: 1px;设置一个,你可以使用。color

于 2016-06-02T10:53:16.927 回答
5

你可以使用类似的东西

<ul>
   <li><a href="#">Some text<span><br />Some text</span></a></li>
</ul>

然后在你的css中将span内容设置为粗体并用可见性隐藏它:隐藏,这样它就可以保持它的尺寸。然后您可以调整以下元素的边距以使其适合。

我不确定这种方法是否对 SEO 友好。

于 2012-12-04T11:17:44.200 回答
5

我刚刚用“影子”解决方案解决了这个问题。这似乎是最简单有效的。

nav.mainMenu ul li > a:hover, nav.mainMenu ul li.active > a {
    text-shadow:0 0 1px white;
}

不需要重复阴影三次(结果对我来说是一样的)。

于 2013-09-04T13:20:44.833 回答
4

我遇到了和你类似的问题。当您将鼠标悬停在它们上时,我希望我的链接变得粗体,但不仅在菜单中,而且在文本中。正如您猜测的那样,弄清楚所有不同的宽度将是一件真正的苦差事。解决方案非常简单:

创建一个框,其中包含粗体的链接文本,但颜色与您的背景相似,但在其上方是您的真实链接。这是我页面中的一个示例:

CSS:

.hypo { font-weight: bold; color: #FFFFE0; position: static; z-index: 0; }
.hyper { position: absolute; z-index: 1; }

当然,您需要将#FFFFE0 替换为页面的背景颜色。z 索引似乎不是必需的,但我还是把它们放在了(因为“hypo”元素将出现在 HTML 代码中的“hyper”元素之后)。现在,要在您的页面上放置一个链接,请包括以下内容:

HTML:

You can find foo <a href="http://bar.com" class="hyper">here</a><span class="hypo">here</span>

第二个“此处”将不可见并隐藏在您的链接下方。由于这是一个带有粗体链接文本的静态框,因此您的其余文本将不再移动,因为在您将鼠标悬停在链接上之前它已经移动了。

希望我能提供帮助:)。

这么久

于 2009-09-29T13:23:24.783 回答
3

我使用 text-shadow 解决方案,就像这里提到的其他人一样:

text-shadow: 0 0 0.01px;

不同的是我没有指定阴影颜色,所以这个解决方案对所有字体颜色都是通用的。

于 2019-02-26T15:02:18.573 回答
3

如果您不想预设列表项的宽度,一个非常好的选择是尝试在列表项中使用等宽字体。

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

我认为这是解决这个常见问题的一个非常优雅的解决方案。

这是这篇优秀文章中的一个示例,将比例字体 IBM Plex Sans 与 uniwidth Recursive 进行了比较。

与单宽字体成比例比较

注意在比例字体 (IBM Plex Sans) 中,列表项如何随着粗体字体大小的变化而变化。使用 uniwidth 字体 Recursive,项目在悬停时变为粗体,但不改变 size

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

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

于 2021-05-12T18:02:42.400 回答
2

您可以使用“margin”属性:

li a {
  margin: 0px 5px 0px 5px;
}

li a:hover {
  margin: 0;
  font-weight: bold;
}

只需确保左右边距足够大,以便额外的空间可以包含粗体文本。对于长词,您可以选择不同的边距。这只是另一种解决方法,但为我完成了这项工作。

于 2012-04-07T10:51:24.020 回答
2

我喜欢使用 text-shadow 代替。特别是因为您可以使用过渡来为文本阴影设置动画。

您真正需要的是:

a {
  transition: text-shadow 1s;
}
a:hover {
  text-shadow: 1px 0 black;
}

如需完整导航,请查看此 jsfiddle: https ://jsfiddle.net/831r3yrb/

浏览器支持和更多关于文本阴影的信息:http: //www.w3schools.com/cssref/css3_pr_text-shadow.asp

于 2016-11-30T09:30:30.490 回答
2

另一种方法是通过文本阴影“模拟”粗体文本。这有一个好处(/malus,取决于你的情况)也可以在字体图标上工作。

   nav li a:hover {
      text-decoration: none;
      text-shadow: 0 0 1px; /* "bold" */
   }

Kinda hacky,虽然它可以让你免于复制文本(如果它很多,这很有用,就像我的情况一样)。

于 2019-05-15T10:59:49.430 回答
1

我建议不要在悬停时切换字体(°)。在这种情况下,它只是菜单项移动了一点,但我已经看到了整个段落被重新格式化的情况,因为加宽会导致额外的自动换行。当您唯一要做的就是移动光标时,您不希望看到这种情况发生;如果您不执行任何操作,则页面布局不应更改。

在正常和斜体之间切换时也会发生这种转变。如果文本下方有空间,我会尝试更改颜色或切换下划线。(下划线应远离底部边框)

如果我为我的表单设计课使用切换字体,我会被嘘的:-)

(°) 字体一词经常被误用。“Verdana”是一种字体,“Verdana normal”和“Verdana bold”是同一种字体的不同字体。

于 2009-02-17T11:26:33.143 回答
1

ul {
  list-style-marker: none;
  padding: 0;
}

li {
  display: inline-block;
}

li + li {
  margin-left: 1em;
}

a {
  display: block;
  position: relative;
  text-align: center;
}

a:before, a:after {
  content: attr(aria-label);
  text-decoration: inherit;
}

a:before {
  font-weight: bold;
  visibility: hidden;
}

a:after {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

a:hover:before {
  visibility: visible;
}

a:hover:after {
  display: none;
}
<ul>
  <li>
    <a href="" aria-label="Long-long-long"></a>
  </li><li>
    <a href="" aria-label="or"></a>
  </li><li>
    <a href="" aria-label="Short"></a>
  </li><li>
    <a href="" aria-label="Links"></a>
  </li><li>
    <a href="" aria-label="Here"></a>
  </li>
</ul>

于 2017-05-16T22:32:54.313 回答
1

letter-spacing与 一起使用text-shadow

a {
  letter-spacing: .1em;
}

a:hover {
  text-shadow: 0 0 .9px #color, 0 0 .9px #color, 0 0 .9px #color;
}
于 2021-07-28T09:03:30.013 回答
1

我用几行javascript解决了这个问题。

$('a.menu_item').each(function() {
    let width = $(this).width();
    $(this).css('width',width + 'px');
});
于 2021-09-21T10:47:28.807 回答
1

在这里看到很多很棒但非常复杂的答案。真的不需要重置宽度,添加隐藏元素,为不同的布局声明重新设计元素等。最简单的解决方案是通过将悬停声明中的字体大小调整为稍微增加粗体文本来解决大小的增加较小的尺寸。例如 font-size: .985em 来自正常的 1em 声明,它允许文本在悬停时变为粗体,但也保持原始大小外观。

于 2021-11-10T16:37:53.860 回答
0

这是我喜欢的解决方案。它需要一点 JS,但你不需要你的 title 属性完全相同,你的 CSS 可以保持非常简单。

$('ul a').each(function() {
  $(this).css({
    'padding-left': 0,
    'padding-right': 0,
    'width': $(this).outerWidth()
  });
});
li, a { display: inline-block; }
a {
  padding-left: 10px;
  padding-right: 10px;
  text-align: center; /* optional, smoother */
}
a:hover { font-weight: bold; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
  <li><a href="#">item 1</a></li>
  <li><a href="#">item 2</a></li>
  <li><a href="#">item 3</a></li>
</ul>

于 2015-03-23T20:20:50.027 回答
0

那这个呢?一个 javascript - CSS3 免费解决方案。

http://jsfiddle.net/u1aks77x/1/

ul{}
li{float:left; list-style-type:none; }
a{position:relative; padding-right: 10px; text-decoration:none;}
a > .l1{}
a:hover > .l1{visibility:hidden;}
a:hover > .l2{display:inline;}
a > .l2{position: absolute; left:0; font-weight:bold; display:none;}

<ul>
  <li><a href="/" title="Home"><span class="l1">Home</span><span class="l2">Home</span></a></li>
  <li><a href="/" title="Contact"><span class="l1">Contact</span><span class="l2">Contact</span></a></li>
  <li><a href="/" title="Sitemap"><span class="l1">Sitemap</span><span class="l2">Sitemap</span></a></li>
</ul>
于 2015-12-04T01:02:09.287 回答
0

不是很优雅的解决方案,但“有效”:

a
{
    color: #fff;
}

a:hover
{
    text-shadow: -1px 0 #fff, 0 1px #fff, 1px 0 #fff, 0 -1px #fff;
}
于 2017-01-10T15:45:40.210 回答
0

我结合了上面的一些技术来提供一些在关闭 js 时不会完全糟糕的东西,并且在使用一点 jQuery 时会更好。现在浏览器对亚像素字母间距的支持正在改进,使用它真的很棒。

jQuery(document).ready(function($) {
  $('.nav a').each(function(){
      $(this).clone().addClass('hoverclone').fadeTo(0,0).insertAfter($(this));
    var regular = $(this);
    var hoverclone = $(this).next('.hoverclone');
    regular.parent().not('.current_page_item').hover(function(){
      regular.filter(':not(:animated)').fadeTo(200,0);
      hoverclone.fadeTo(150,1);
    }, function(){
      regular.fadeTo(150,1);
      hoverclone.filter(':not(:animated)').fadeTo(250,0);
    });
  });
});
ul {
  font:normal 20px Arial;
  text-align: center;
}
li, a {
  display:inline-block;
  text-align:center;
}
a {
  padding:4px 8px;
  text-decoration:none;
  color: #555;
}

.nav a {
  letter-spacing: 0.53px; /* adjust this value per font */
}
.nav .current_page_item a,
.nav a:hover {
  font-weight: bold;
  letter-spacing: 0px;
}
.nav li {
  position: relative;
}
.nav a.hoverclone {
  position: absolute;
  top:0;
  left: 0;
  white-space: nowrap;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="nav">
  <li><a href="#">Item 1</a></li>
  <li><a href="#">Item 2</a></li>
  <li class="current_page_item"><a  href="#">Item 3</a></li>
  <li><a href="#">Item 4</a></li>
  <li><a href="#">Item 5</a></li>
</ul>

于 2017-04-27T15:57:58.417 回答
0

最好使用a::before而不是a::after像这样:

.breadcrumb {
  margin: 0;
  padding: 0;
  list-style: none;
  overflow: hidden;
}

.breadcrumb li, 
.breadcrumb li a {
  display: inline-block;
}

.breadcrumb li:not(:last-child)::after {
  content: '>'; /* or anything else */
  display: inline-block;
}

.breadcrumb a:hover {
  font-weight: bold;
}

.breadcrumb a::before {
  display: block;
  content: attr(data-label);
  font-weight: bold;
  height: 0;
  overflow: hidden;
  visibility: hidden;
}
<ul class="breadcrumb">
  <li><a data-label="one" href="https://www.google.fr/" target="_blank">one</a></li>
  <li><a data-label="two" href="https://duckduckgo.com/" target="_blank">two</a></li>
  <li><a data-label="three" href="#">three</a></li>
</ul>

更多详情:https ://jsfiddle.net/r25foavy/

于 2019-05-15T13:04:44.407 回答
0

当悬停大胆成功时,我修复了菜单。它支持响应式,这是我的代码:

(function ($) {
'use strict';

$(document).ready(function () {
    customWidthMenu();
});
$(window).resize(function () {
    customWidthMenu();
});
function customWidthMenu() {
    $('ul.nav li a').each(function() {
        $(this).removeAttr('style');
        var this = $(this);
        var width = this.innerWidth();
        this.css({'width': width + 12});
    });
}})(jQuery);
于 2019-09-24T10:44:10.923 回答
-1

如果您不反对使用 Javascript,则可以在页面显示后设置适当的宽度。这是我的做法(使用原型):

$$('ul.nav li').each(this.setProperWidth);

setProperWidth: function(li)
{
  // Prototype's getWidth() includes padding, so we 
  // have to subtract that when we set the width.
  var paddingLeft = li.getStyle('padding-left'),
      paddingRight = li.getStyle('padding-right');

  // Cut out the 'px' at the end of each padding
  paddingLeft = paddingLeft.substring(0,paddingLeft.length-2);
  paddingRight = paddingRight.substring(0,paddingRight.length-2);

  // Make the li bold, set the width, then unbold it
  li.setStyle({ fontWeight: 'bold' });
  li.setStyle({ width: (li.getWidth() - paddingLeft - paddingRight) + 'px'});
  li.setStyle({ fontWeight: 'normal', textAlign: 'center' });
}
于 2009-12-03T19:25:52.240 回答
-1

试试这个:

.nav {
  font-family: monospace;
}
于 2018-10-07T02:23:09.143 回答
-2

当有一个简单的问题解决方案时,有人告诉你不要那样做,我真的无法忍受。我不确定 li 元素,但我刚刚解决了同样的问题。我有一个由 div 标签组成的菜单。

只需将 div 标签设置为“display: inline-block”。内联,因此它们彼此相邻并阻挡您可以设置宽度。只需将宽度设置为足以容纳粗体文本并对齐文本中心即可。

(注意:它似乎正在剥离我的 html [下面],但每个菜单项都有一个 div 标记,并带有相应的 ID 和类名 SearchBar_Cateogory。即:<div id="ROS_SearchSermons" class="SearchBar_Category">

HTML(我在每个菜单项周围都有锚标记,但我无法将它们作为新用户提交)

<div id="ROS_SearchSermons" class="SearchBar_Cateogry bold">Sermons</div>|
<div id="ROS_SearchIllustrations" class="SearchBar_Cateogry">Illustrations</div>|
<div id="ROS_SearchVideos" class="SearchBar_Cateogry">Videos</div>|
<div id="ROS_SearchPowerPoints" class="SearchBar_Cateogry">PowerPoints</div>|
<div id="ROS_SearchScripture" class="SearchBar_Cateogry">Scripture</div>|

CSS:

#ROS_SearchSermons { width: 75px; }
#ROS_SearchIllustrations { width: 90px; }
#ROS_SearchVideos { width: 55px; }
#ROS_SearchPowerPoints { width: 90px; }
#ROS_SearchScripture { width: 70px; }

.SearchBar_Cateogry
{
    display: inline-block;
    text-align:center;
}
于 2009-06-10T17:38:48.717 回答
-3

如果粗体文本比常规文本更宽,您也可以尝试负边距。(并非总是如此)所以想法是使用类来设置 :hover 状态的样式。

jQuery:

 $(".nav-main .navbar-collapse > ul > li > a").hover(function() {
    var originalWidth = $(this).outerWidth();

    $(this).parent().addClass("hover");
    $(this).css({
       "margin-left": -(($(this).outerWidth() - originalWidth) / 2),
       "margin-right": -(($(this).outerWidth() - originalWidth) / 2)
    });
 },
 function() {
    $(this).removeAttr("style");
    $(this).parent().removeClass("hover");
 });

CSS:

ul > li > a {
    font-style: normal;
}

ul > li > a.hover {
    font-style: bold;
}

我希望我能帮上忙!

于 2014-08-07T17:39:15.973 回答