230

I created a horizontal menu using a HTML lists and CSS. Everything works as it should except when you hover over the links. You see, I created a bold hover state for the links, and now the menu links shift because of the bold size difference.

I encounter the same problem as this SitePoint post. However, the post does not have proper solution. I've searched everywhere for a solution and can't find one. Surely I can't be the only one trying to do this.

Does anyone have any ideas?

P.S: I don't know the width of the text in menu items so I cannot just set the width of the li items.

.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>
350D
  • 9,451
  • 5
  • 31
  • 39
Billy
  • 14,356
  • 28
  • 67
  • 99

26 Answers26

429

Pre-set the width by using an invisible pseudo-element which has the same content and styling as the parent hover style. Use a data attribute, like title, as the source for content.

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>
MarsAndBack
  • 6,314
  • 3
  • 21
  • 45
350D
  • 9,451
  • 5
  • 31
  • 39
  • 24
  • 6
    This solution works, but its better when you add `margin-top: -1px` to `:after` to avoid creating space of 1px height. – micropro.cz Aug 17 '14 at 20:06
  • 1
    This is a great solution! Out of curiousity, is there a difference in outcome between "a:after" and "a::after"? – mattroberts33 Dec 10 '14 at 09:10
  • 5
    @mattroberts33 `:` vs `::` "Every browser that supports the double colon `::` CSS3 syntax also supports just the `:` syntax, but IE 8 only supports the single-colon, so for now, it's recommended to just use the single-colon for best browser support." http://css-tricks.com/almanac/selectors/a/after-and-before/ – gfullam Jan 28 '15 at 05:57
  • Great solution, but for me it creates a gap underneath the text. Add `background-color: #ff0000;` to `li`, and then put an element (such as an `hr` with no margins) directly underneath to see it. I get a ~5px gap on Firefox and 1px on Chrome. Get rid of the `::after` and the gap closes. Anyone else get this? I can't see what's causing it. – HughHughTeotl Mar 18 '15 at 19:11
  • 1
    @HughHughTeotl Use font-size:0 for `UL` or `a::after`, in other words — reset all padding/marging/line-heights/font-sizes etc. – 350D Mar 25 '15 at 20:10
  • 1
    Unfortunately, you always have the tooltip displayed :-( – Benedikt Apr 09 '15 at 10:49
  • 1
    @Benedikt Who says you can't use a different attribute name instead? – giraff Jun 15 '15 at 12:12
  • 1
    This doesn't work when there are
    's in the title/text. Tried swapping them with \A, the acceptable line break character for :before and :after, but still unsuccessful.
    – pinksharpii Jul 20 '15 at 18:41
  • 1
    Awesome solution! I've got a client who, on hover, wants to switch the font-family to a demi weight, and this completely rids of the shifting text issue. I'd give this answer a 1000 upvotes if could. – Jamal Ali Jul 03 '17 at 23:33
  • @350D setting `font-size: 0` on `::after` makes `::after` the same width as `a` though, thus negating this fix. – fiskhandlarn May 29 '19 at 09:28
  • @fiskhandlarn I have `font-size` for `a`, I don't get your idea – 350D Jun 02 '19 at 02:21
  • @350D Doesn't matter if you want to keep the links from shifting on hover, see here: https://jsfiddle.net/ak243myf/ – fiskhandlarn Jun 03 '19 at 07:11
  • @fiskhandlarn What I need to see there exactly? Did you checked my snippet? – 350D Jun 04 '19 at 03:04
  • not that good at all when the hover text is longer and spaced – Picard Dec 13 '19 at 10:51
  • 1
    @fiskhandlarn I was seeing the same thing as you and I couldn't work out why. But, switching `a::after` to `a::before` fixed the problem for me. With `a::after` it was as if the element was still reserving vertical space, even though the height was 0 (verified in inspector). So, my link was being pushed up vertically and the extra space was causing things to spill out of the parent. I could get `a::after` to work if I set `max-height` on the parent, but that seemed like the wrong solution. – nirvdrum Jan 10 '20 at 20:23
  • @nirvdrum No difference for me if I use `a::before` instead. Do you have a working example? (Also, "vertically"? X)) – fiskhandlarn Jan 16 '20 at 12:18
  • I was unable to induce the problem in this answer, so I can only relay that I was seeping the same issue you reported with my own app and that using `a::before` fixed the problem for me. I suspect there is a conflicting Ant rule in there somewhere. Where did I lose you on vertically? Without the fix, the text is pushed to the top of the element by virtue of the hidden element taking up space. With the fix, the text centers vertically ("middle"). – nirvdrum Jan 17 '20 at 21:28
  • `::before` instead of `::after` also worked much better in my case, all things being equal. – John Mar 09 '20 at 01:31
  • 1
    @John I've updated my answer and snippet, thank you – 350D Mar 09 '20 at 09:48
  • this is not working if I change text-transform: uppercase; for lower case how should this apply? – Franco Apr 29 '21 at 13:45
  • @Franco Make sure you have the same text style for both a and ::before pseudo element. ITs works 100%, its too simple to not work. – 350D Apr 30 '21 at 18:00
45

A compromised solution is to fake bold with text-shadow, e.g:

text-shadow: 0 0 0.01px black;

For better comparison I created these examples:

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>

Passing to text-shadow really low value for blur-radius will make the blurring effect not so apparent.

In general the more your repeat text-shadow the bolder your text will get but in the same time loosing original shape of the letters.

I should warn you that setting the blur-radius to fractions is not going to render the same in all browsers! Safari for example need bigger values to render it the same way Chrome will do.

Stefan J
  • 859
  • 8
  • 9
33

Another idea is using 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>
John Magnolia
  • 15,835
  • 30
  • 147
  • 254
28

If you cannot set the width, then that means the width will change as the text gets bold. There is no way to avoid this, except by compromises such as modifying the padding/margins for each state.

Andrew Vit
  • 18,433
  • 6
  • 73
  • 83
  • 2
    +1 as Andrew says, the bold text is wider. Fact of life. Even fix the width of the menu items to avoid this or live with it (recalculating padding is imprecise and error prone). – cletus Feb 17 '09 at 11:04
  • Yep, I tend to avoid the bold mouseover effect for this reason. – Steve Wortham Jun 10 '09 at 17:48
  • "There is no way to avoid this". See answer by 350D below. – gfullam Jan 28 '15 at 05:52
  • Also note that the answer of Andrew was posted 4 years before the solution of 350D was added. Pseudo elements with attr() function as content value was absolutely not possible back then :) oh time flies at Stack Overflow. However community gets over it and has it is the accepted answer and most upvotes, so I'm happy! – Justus Romijn May 12 '20 at 14:24
17

One line in jquery:

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

edit: While this can bring about the solution, one should mention that it does not work in conjunction with the code in the original post. "display:inline" has to be replaced with floating-parameters for a width-setting to be effective and that horizontal menu to work as intended.

edwardh
  • 40
  • 6
Alex
  • 210
  • 3
  • 7
  • Can you do this for all links in the page? That is, does replacing `ul.nav li a` with `a` works? – gnzlbg Apr 18 '14 at 15:42
  • 2
    This question was not tagged with JS, let alone jQuery. Please don't post unnecessary solutions. – Zach Saucier Mar 04 '16 at 17:48
  • 2
    @Zach Saucier Under some situations some devs might prefer a JS solution, as they are usually shorter. Instead of downvoting everyone who posted something with JS, you could add the JS tag to the question and let each person decide which solution they find more useful. – lurkit Mar 04 '16 at 19:56
  • 1
    @Zach Saucier The CSS solution might not be practical in some situations. Sometimes you might need to have a different title attribute, or already used up the ::after pseudo element, or you might personally consider more practical on a given situation to use a one liner in JS to several lines of CSS. I do consider the CSS answer to be superior in most cases, but it is useful to have the JS answers as additional options. – lurkit Mar 07 '16 at 17:57
  • This is the only solution I could find that solves the problem while retaining even spacing between elements. – Mispy Jun 08 '16 at 06:56
12

CSS3 Solution - Experimental

(Fake boldness)

Thought to share a different solution which no one suggested here. There's a property called text-stroke which will be handy for this.

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

Here, I am targeting the text inside of the span tag and we stroke it by a pixel with black which will simulate bold style for that particular text.

Note that this property is not widely supported, as of now (while writing this answer), only Chrome and Firefox seems to support this. For more information on browser support for text-stroke, you can refer to CanIUse.


Just for sharing some extra stuff, you can use -webkit-text-stroke-width: 1px; if you are not looking to set a color for your stroke.

Mr. Alien
  • 140,764
  • 31
  • 277
  • 265
5

You could use somehting like

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

and then in your css just set the span content bold and hide it with visibility: hidden, so that it keeps its dimensions. Then you can adjust margins of the following elements to make it fit properly.

I am not sure if this approach is SEO friendly though.

monk
  • 51
  • 1
  • 3
5

I just solved the problem with the "shadow" solution. It seems the most simple and effective.

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

No need to repeat the shadow three times (result was the same for me).

Daniele B
  • 213
  • 3
  • 8
4

I had a problem similar to yours. I wanted my links to get bold when you hover over them but not only in the menu but also in the text. As you cen guess it would be a real chore figuring out all the different widths. The solution is pretty simple:

Create a box that contains the link text in bold but coloured like your background and but your real link above it. Here's an example from my page:

CSS:

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

Of course you need to replace #FFFFE0 by the background colour of your page. The z-indices don't seem to be necessary but I put them anyway (as the "hypo" element will occur after the "hyper" element in the HTML-Code). Now, to put a link on your page, include the following:

HTML:

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

The second "here" will be invisible and hidden below your link. As this is a static box with your link text in bold, the rest of your text won't shift any longer as it is already shifted before you hover over the link.

Hope I was able to help :).

So long

2

You can work with the "margin" property:

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

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

Just make sure that the left and right margin are big enough so the extra space can contain the bold text. For long words, you might choose different margins. It's just another workaround but doing the job for me.

Zach Saucier
  • 21,903
  • 12
  • 75
  • 126
Martin Horvath
  • 456
  • 1
  • 6
  • 16
  • I used a similar solution, but for me - just adding 'margin:0 -2px' to the hover style (and not adding anything else to the normal style) - worked great. – Yuval A. Oct 26 '13 at 22:43
  • 8
    This doesn't work if there is any variability at all in your string length – kat Dec 17 '14 at 19:23
2

I like to use text-shadow instead. Especially because you can use transitions to animate text-shadow.

All you really need is:

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

For a complete navigation check out this jsfiddle: https://jsfiddle.net/831r3yrb/

Browser support and more info on text-shadow: http://www.w3schools.com/cssref/css3_pr_text-shadow.asp

Lightningsoul
  • 532
  • 5
  • 15
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>
Qwertiy
  • 14,618
  • 9
  • 41
  • 96
1

I use text-shadow solution as some others mentioned here:

text-shadow: 0 0 0.01px;

the difference is that I do not specify shadow color, so this solution is universal for all font colors.

michal.jakubeczy
  • 4,457
  • 1
  • 30
  • 43
1

I would advice against switching fonts(°) on hover. In this case it's just the menu items moving a bit, but I've seen cases where the complete paragraph gets reformatted because the widening causes an extra word wrap. You don't want to see this happen when the only thing you do is move the cursor; if you don't do anything the page layout should not change.

The shift can also happen when switching between normal and italic. I would try changing colors, or toggle underline if you have room below the text. (underlining should stay clear from the bottom border)

I would be boo'd if I used switching fonts for my Form Design class :-)

(°) The word font is often misused. "Verdana" is a typeface, "Verdana normal" and "Verdana bold" are different fonts of the same typeface.

stevenvh
  • 2,822
  • 9
  • 36
  • 48
1

An alternative approach would be to "emulate" bold text via text-shadow. This has the bonus (/malus, depending on your case) to work also on font icons.

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

Kinda hacky, although it saves you from duplicating text (which is useful if it is a lot, as it was in my case).

0

This is the solution I prefer. It requires a bit of JS but you don't need your title property to be the exact same and your CSS can remain very simple.

$('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>
lurkit
  • 368
  • 4
  • 16
0

What about this? A javascript - CSS3 free solution.

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>
user10099
  • 1,128
  • 2
  • 15
  • 21
0

Not very elegant solution, but "works":

a
{
    color: #fff;
}

a:hover
{
    text-shadow: -1px 0 #fff, 0 1px #fff, 1px 0 #fff, 0 -1px #fff;
}
Świeżu
  • 140
  • 2
  • 5
0

I've combined a bunch of the techniques above to provide something that doesn't totally suck with js turned off and is even better with a bit of jQuery. Now that browsers support for subpixel letter-spacing is improving, it's really nice to use it.

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>
squarecandy
  • 4,079
  • 1
  • 27
  • 40
0

It's better to use a::before instead a::after like this:

.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>

For more details: https://jsfiddle.net/r25foavy/

clisima
  • 11
  • 1
  • Can you please provide a justification for why `a::before` would be better than `a::after`? That seems like a key piece of your answer, but it's not obvious why one is preferable to the other in this case. – nirvdrum Jan 10 '20 at 19:31
0

I fixed menu when hover bold success. It support responsive, this is my code:

(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);
Ty Phan
  • 19
  • 1
0

If you don't want to preset the width of the list items, a really good alternative would be to try using a uniwidth font in your list items.

Unlike a monospace font, they're still proportional typefaces -- but they occupy the same size across different font weights. No CSS, JS, or fancy hacks are required to keep the size constant. It's baked right into the typeface.

I think it's a really elegant solution to this common problem.

Here's an example from this excellent article comparing the proportional font IBM Plex Sans to the uniwidth Recursive.

comparing proportional to uniwidth font

Notice how in the proportional font (IBM Plex Sans), the list items shift as they change size in the bold typeface. With the uniwidth font Recursive, the items become bold on hover but don't change size.

Free uniwidth fonts you can try are:

There are also many non-free options linked to via the aforementioned article.

aardvarkk
  • 13,147
  • 6
  • 58
  • 89
  • @Jean-François Fabre I feel that a uniwidth font approach to solve this problem is elegant and not represented in the answers. My solution has been edited to be more tailored to the question. – aardvarkk May 12 '21 at 18:04
-1

If you're not averse to using Javascript, you can set the proper width once the page is shown. Here's how I did it (using Prototype):

$$('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' });
}
Alex Grin
  • 7,761
  • 6
  • 28
  • 53
  • Javascript was not tagged in the question, let alone jQuery. Please keep answer using the languages tagged in the question – Zach Saucier Mar 04 '16 at 17:53
-1

try this:

.nav {
  font-family: monospace;
}
Yukulélé
  • 11,464
  • 8
  • 52
  • 76
  • How would that change anything? – leonheess Feb 06 '19 at 16:24
  • @MiXT4PE With monospace, characters have the same size in regular or bold. size will not change – Yukulélé Feb 10 '19 at 03:33
  • changing a font family because of that is not a solution – funkysoul Jun 06 '19 at 11:08
  • Changing font-family to fix a UI bug is not a solution, as font-family is the root of all brand typography most of the time. – Umair Hafeez Dec 17 '19 at 16:37
  • Typography is a large part of UI design and the typefaces designed for a brand should take into account their use in UIs. PT Sans and Clear Sans are two typefaces whose glyph spacing is similar across weights. Unfortunately, it's true that very few (non-monospaced) typefaces have this property, and it's likely cheaper to implement one of the other answers to the question than to pay for typeface development. However, that will change as Variable font availability improves. See https://v-fonts.com for fonts with variable width + weights. – Peter W Apr 20 '20 at 22:34
-2

I really can't stand it when someone tells you not to do something that way when there's a simple solution to the problem. I'm not sure about li elements, but I just fixed the same issue. I have a menu consisting of div tags.

Just set the div tag to be "display: inline-block". Inline so they sit next to each other and block to that you can set a width. Just set the width wide enough to accomodate for the bolded text and have the text center aligned.

(Note: It seems to be stripping out my html [below], but each menu item had a div tag wrapped around it with the corrasponding ID and the class name SearchBar_Cateogory. ie: <div id="ROS_SearchSermons" class="SearchBar_Category">

HTML (I had anchor tags wrapped around each menu item, but i wasn't able to submit them as a new user)

<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;
}
Jørn Schou-Rode
  • 35,883
  • 13
  • 81
  • 120
  • 1
    This is using a fixed width just like the OP specified is *NOT* the case. As such, this answer does not answer the question being asked – Zach Saucier Mar 04 '16 at 17:55
-3

You can try the negative margins too if the bold text is wider than the regular. (not always) So the idea is to use classes instead to style the :hover state.

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

I hope I could help!

Robert Bokori
  • 261
  • 1
  • 3
  • 8
  • 1
    Please do not post answers in languages other than the tagged ones. This does not answer the question being asked – Zach Saucier Mar 04 '16 at 17:56