内联元素在悬停时变粗时会发生变化


204

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

Answers:


389

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

检查JSfiddle上的工作示例。这个想法是为伪元素中的加粗(或任何:hover状态样式)内容保留空间,:before并使用title标签作为内容源。


20
完善!即使在不使用ul的情况下,它也适用于<a>,我将使用另一个属性,例如数据文本,而不是标题。
brittongr 2014年

6
该解决方案的作品,但它的更好,当你添加margin-top: -1px:after以避免造成1px的高度的空间。
micropro.cz

4
@ mattroberts33 :::“每个支持双冒号::CSS3语法的浏览器也都支持该:语法,但是IE 8仅支持单冒号,因此,现在建议仅使用单冒号以获得最佳的浏览器支持。” css-tricks.com/almanac/selectors/a/after-and-before
gfullam 2015年

1
@HughHughTeotl将font-size:0用作ULa::after,换句话说,重置所有padding / marging / line-heights / font-sizes等。–
350D

1
不幸的是,您始终会显示工具提示:-(
Benedikt

42

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

文字阴影: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一样进行渲染。


6
这甚至比丑陋的浏览器等大胆的计算解决方案,并应避免
扎克索西耶

28

如果您无法设置宽度,则表示宽度将随着文本变粗体而改变。除了通过诸如修改每个状态的填充/边距之类的折衷办法外,没有其他方法可以避免这种情况。


2
如安德鲁所说,+ 1,粗体字更宽。生活的事实。甚至固定菜单项的宽度可以避免这种情况发生或避免这种情况发生(重新计算填充不精确且容易出错)。
cletus

是的,出于这个原因,我倾向于避免使用大胆的鼠标悬停效果。
史蒂夫·沃瑟姆

“没有办法避免这种情况”。请参阅下面的350D答案。
gfullam

另请注意,在添加350D解决方案之前的4年,安德鲁的答案已发布。那时绝对不可能用attr()作为内容值的伪元素:)哦,时间过得真快,堆栈溢出了。但是,社区克服了它,并获得了公认的答案和最多的支持,所以我很高兴!
Justus Romijn

25

另一个想法是使用 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>


那是否适用于所有浏览器,尤其是IE10 +和Safari?
Umair Hafeez

我最喜欢的一个:)
Inc33

1
@UmairHafeez是,所有现代浏览器都希望使用Opera mini caniuse.com/#feat=css-letter-spacing
John Magnolia

1
您怎么知道0.235px是完美的数量?是否有任何公式可以计算所需的间距?
Cold_Class

不,我认为这只是快速尝试和错误
约翰·

17

一个在jQuery的行:

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

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


您可以为页面中的所有链接执行此操作吗?也就是说,ul.nav li aa作品代替吗?
gnzlbg 2014年

2
这个问题没有用JS标记,更不用说jQuery了。请不要发布不必要的解决方案。
Zach Saucier

2
@Zach Saucier在某些情况下,某些开发人员可能更喜欢JS解决方案,因为它们通常较短。您可以在问题中添加JS标签,然后让每个人决定他们觉得更有用的解决方案,而不是用JS张贴文章的所有人。
lurkit

1
@Zach Saucier CSS解决方案在某些情况下可能不切实际。有时您可能需要具有不同的title属性,或者已经用尽:: after伪元素,或者您可能个人认为在给定情况下将JS中的一个衬里用于几行CSS。我确实认为CSS答案在大多数情况下是优越的,但是将JS答案作为附加选项很有用。
lurkit

这是我能找到的唯一解决该问题的方法,同时保持元素之间的间距均匀。
Jaiden Mispy

11

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为自己的笔划设置a ,就可以使用。


这太神奇了
艾伦·菲茨帕特里克

大提示。不幸的是,四年后它仍然不是标准。
大卫Veszelovszki

5

您可以使用类似

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

然后在CSS中将跨度内容设置为粗体,并以可见性将其隐藏:hidden,以便保持其尺寸。然后,您可以调整以下元素的边距以使其正确适合。

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


1
这也不是对开发人员/维护人员友好的
Zach Saucier

5

我只是用“阴影”解决方案解决了这个问题。看来最简单有效。

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

无需重复阴影3次(对我来说结果是相同的)。


这比其他浏览器计算的大胆解决方案还要难看,应该避免
Zach Saucier

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>

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

希望我能帮助:)。

太长


2

您可以使用“ margin”属性:

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

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

只要确保左右边缘足够大,以便多余的空间可以包含粗体文本即可。长话大说,您可以选择不同的边距。这只是另一个解决方法,但可以为我完成工作。


我使用了类似的解决方案,但对我来说-仅将'margin:0 -2px'添加到悬停样式中(而不向常规样式添加任何其他内容)-效果很好。
Yuval A.

8
如果您的字符串长度完全不可变,则此方法将不起作用
kat 2014年

2

我更喜欢使用文本阴影。特别是因为您可以使用过渡为文本阴影设置动画。

您真正需要的是:

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


使用过渡效果很好。伟大的替代解决方案。
Yazmin

1

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

在正常和斜体之间切换时,也会发生这种变化。我会尝试更改颜色,如果文本下方有空格,请切换下划线。(下划线应从底部边框保持清晰)

如果我在Form Design类中使用切换字体,我会被嘘:-)

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


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>


1

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

text-shadow: 0 0 0.01px;

区别在于我没有指定阴影颜色,因此该解决方案适用于所有字体颜色。


1

一种替代方法是通过文本阴影“模拟”粗体文本。这具有奖金(/ malus,取决于您的情况),也可以在字体图标上使用。

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

Kinda hacky,尽管它使您免于复制文本(如果很多,这很有用,例如我的情况)。


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>


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>

1
这有很多额外的标记和CSS可以解决此问题……它不是开发人员,SEO或对未来不友好的
Zach Saucier

0

不是很好的解决方案,但是“可行”:

a
{
    color: #fff;
}

a:hover
{
    text-shadow: -1px 0 #fff, 0 1px #fff, 1px 0 #fff, 0 -1px #fff;
}

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>


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/


您能否提供理由说明为什么a::before会比以下更好a::after?这似乎是您解决问题的关键,但是在这种情况下,为什么一个比另一个更可取却并不明显。
nirvdrum

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);

-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' });
}

没有在问题中标记Javascript,更不用说jQuery。请使用问题中标记的语言继续回答
Zach Saucier

-1

当有一个简单的解决方案时,当有人告诉您不要以这种方式做某事时,我实在无法忍受。我不确定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;
}

1
就像不是指定的OP一样,这使用的是固定宽度。因此,此答案不能回答所提出的问题
Zach Saucier

-1

试试这个:

.nav {
  font-family: monospace;
}

那会如何改变?
leonheess

@ MiXT4PE对于等宽字符,常规字符或粗体字符的大小相同。大小不会改变
Yukulélé

因此,更改字体系列不是解决方案
funkysoul

更改字体家族以解决UI错误不是解决方案,因为字体家族通常是所有品牌排版的根源。
Umair Hafeez

排版是UI设计的重要组成部分,为品牌设计的字体应考虑其在UI中的使用。PT Sans和Clear Sans是两种字体,其字形间距在权重上相似。不幸的是,确实有很少(非等宽)字体具有此属性,实现该问题的其他答案之一可能比为字体开发付费要便宜。但是,随着可变字体可用性的提高,这种情况将会改变。有关可变宽度和粗细的字体,请参见v-fonts.com
Peter W

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

希望我能帮上忙!


1
请不要以已标记语言以外的其他语言发布答案。这不能回答所提出的问题
Zach Saucier
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.