[html] Inline elements shifting when made bold on hover

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.

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

This question is related to html css hover text-size

The answer is


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.


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.

_x000D_
_x000D_
jQuery(document).ready(function($) {_x000D_
  $('.nav a').each(function(){_x000D_
      $(this).clone().addClass('hoverclone').fadeTo(0,0).insertAfter($(this));_x000D_
    var regular = $(this);_x000D_
    var hoverclone = $(this).next('.hoverclone');_x000D_
    regular.parent().not('.current_page_item').hover(function(){_x000D_
      regular.filter(':not(:animated)').fadeTo(200,0);_x000D_
      hoverclone.fadeTo(150,1);_x000D_
    }, function(){_x000D_
      regular.fadeTo(150,1);_x000D_
      hoverclone.filter(':not(:animated)').fadeTo(250,0);_x000D_
    });_x000D_
  });_x000D_
});
_x000D_
ul {_x000D_
  font:normal 20px Arial;_x000D_
  text-align: center;_x000D_
}_x000D_
li, a {_x000D_
  display:inline-block;_x000D_
  text-align:center;_x000D_
}_x000D_
a {_x000D_
  padding:4px 8px;_x000D_
  text-decoration:none;_x000D_
  color: #555;_x000D_
}_x000D_
_x000D_
.nav a {_x000D_
  letter-spacing: 0.53px; /* adjust this value per font */_x000D_
}_x000D_
.nav .current_page_item a,_x000D_
.nav a:hover {_x000D_
  font-weight: bold;_x000D_
  letter-spacing: 0px;_x000D_
}_x000D_
.nav li {_x000D_
  position: relative;_x000D_
}_x000D_
.nav a.hoverclone {_x000D_
  position: absolute;_x000D_
  top:0;_x000D_
  left: 0;_x000D_
  white-space: nowrap;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>_x000D_
<ul class="nav">_x000D_
  <li><a href="#">Item 1</a></li>_x000D_
  <li><a href="#">Item 2</a></li>_x000D_
  <li class="current_page_item"><a  href="#">Item 3</a></li>_x000D_
  <li><a href="#">Item 4</a></li>_x000D_
  <li><a href="#">Item 5</a></li>_x000D_
</ul>
_x000D_
_x000D_
_x000D_


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


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

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

_x000D_
_x000D_
.breadcrumb {_x000D_
  margin: 0;_x000D_
  padding: 0;_x000D_
  list-style: none;_x000D_
  overflow: hidden;_x000D_
}_x000D_
_x000D_
.breadcrumb li, _x000D_
.breadcrumb li a {_x000D_
  display: inline-block;_x000D_
}_x000D_
_x000D_
.breadcrumb li:not(:last-child)::after {_x000D_
  content: '>'; /* or anything else */_x000D_
  display: inline-block;_x000D_
}_x000D_
_x000D_
.breadcrumb a:hover {_x000D_
  font-weight: bold;_x000D_
}_x000D_
_x000D_
.breadcrumb a::before {_x000D_
  display: block;_x000D_
  content: attr(data-label);_x000D_
  font-weight: bold;_x000D_
  height: 0;_x000D_
  overflow: hidden;_x000D_
  visibility: hidden;_x000D_
}
_x000D_
<ul class="breadcrumb">_x000D_
  <li><a data-label="one" href="https://www.google.fr/" target="_blank">one</a></li>_x000D_
  <li><a data-label="two" href="https://duckduckgo.com/" target="_blank">two</a></li>_x000D_
  <li><a data-label="three" href="#">three</a></li>_x000D_
</ul>
_x000D_
_x000D_
_x000D_

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


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.


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


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!


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.


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

_x000D_
_x000D_
ul {_x000D_
  list-style-marker: none;_x000D_
  padding: 0;_x000D_
}_x000D_
_x000D_
li {_x000D_
  display: inline-block;_x000D_
}_x000D_
_x000D_
li + li {_x000D_
  margin-left: 1em;_x000D_
}_x000D_
_x000D_
a {_x000D_
  display: block;_x000D_
  position: relative;_x000D_
  text-align: center;_x000D_
}_x000D_
_x000D_
a:before, a:after {_x000D_
  content: attr(aria-label);_x000D_
  text-decoration: inherit;_x000D_
}_x000D_
_x000D_
a:before {_x000D_
  font-weight: bold;_x000D_
  visibility: hidden;_x000D_
}_x000D_
_x000D_
a:after {_x000D_
  position: absolute;_x000D_
  left: 0;_x000D_
  top: 0;_x000D_
  right: 0;_x000D_
  bottom: 0;_x000D_
}_x000D_
_x000D_
a:hover:before {_x000D_
  visibility: visible;_x000D_
}_x000D_
_x000D_
a:hover:after {_x000D_
  display: none;_x000D_
}
_x000D_
<ul>_x000D_
  <li>_x000D_
    <a href="" aria-label="Long-long-long"></a>_x000D_
  </li><li>_x000D_
    <a href="" aria-label="or"></a>_x000D_
  </li><li>_x000D_
    <a href="" aria-label="Short"></a>_x000D_
  </li><li>_x000D_
    <a href="" aria-label="Links"></a>_x000D_
  </li><li>_x000D_
    <a href="" aria-label="Here"></a>_x000D_
  </li>_x000D_
</ul>
_x000D_
_x000D_
_x000D_


Another idea is using letter-spacing

_x000D_
_x000D_
li, a { display: inline-block; }_x000D_
a {_x000D_
  font-size: 14px;_x000D_
  padding-left: 10px;_x000D_
  padding-right: 10px;_x000D_
  letter-spacing: 0.235px_x000D_
}_x000D_
_x000D_
a:hover, a:focus {_x000D_
  font-weight: bold;_x000D_
  letter-spacing: 0_x000D_
}
_x000D_
<ul>_x000D_
  <li><a href="#">item 1</a></li>_x000D_
  <li><a href="#">item 2</a></li>_x000D_
  <li><a href="#">item 3</a></li>_x000D_
</ul>
_x000D_
_x000D_
_x000D_


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.


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.

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

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.


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

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


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

try this:

.nav {
  font-family: monospace;
}

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.

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


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


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.


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>

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.


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:

_x000D_
_x000D_
a, li {_x000D_
  color: black;_x000D_
  text-decoration: none;_x000D_
  font: 18px sans-serif;_x000D_
  letter-spacing: 0.03em;_x000D_
}_x000D_
li {_x000D_
  display: inline-block;_x000D_
  margin-right: 20px;_x000D_
  color: gray;_x000D_
  font-size: 0.7em;_x000D_
}_x000D_
.bold-x1 a.hover:hover,_x000D_
.bold-x1 a:not(.hover) {_x000D_
  text-shadow: 0 0 .01px black;_x000D_
}_x000D_
.bold-x2 a.hover:hover,_x000D_
.bold-x2 a:not(.hover){_x000D_
  text-shadow: 0 0 .01px black, 0 0 .01px black;_x000D_
}_x000D_
.bold-x3 a.hover:hover,_x000D_
.bold-x3 a:not(.hover){_x000D_
  text-shadow: 0 0 .01px black, 0 0 .01px black, 0 0 .01px black;_x000D_
}_x000D_
.bold-native a.hover:hover,_x000D_
.bold-native a:not(.hover){_x000D_
  font-weight: bold;_x000D_
}_x000D_
_x000D_
.bold-native li:nth-child(4),_x000D_
.bold-native li:nth-child(5){_x000D_
 margin-left: -6px;_x000D_
 letter-spacing: 0.01em;_x000D_
}
_x000D_
<ul class="bold-x1">_x000D_
  <li><a class="hover" href="#">Home</a></li>_x000D_
  <li><a class="hover" href="#">Products</a></li>_x000D_
  <li><a href="#">Contact</a></li>_x000D_
  <li><a href="#">About</a></li>_x000D_
  <li>Bold (text-shadow x1)</li>_x000D_
</ul>_x000D_
<ul class="bold-x2">_x000D_
  <li><a class="hover" href="#">Home</a></li>_x000D_
  <li><a class="hover" href="#">Products</a></li>_x000D_
  <li><a href="#">Contact</a></li>_x000D_
  <li><a href="#">About</a></li>_x000D_
  <li>Extra Bold (text-shadow x2)</li>_x000D_
</ul>_x000D_
<ul class="bold-native">_x000D_
  <li><a class="hover" href="#">Home</a></li>_x000D_
  <li><a class="hover" href="#">Products</a></li>_x000D_
  <li><a href="#">Contact</a></li>_x000D_
  <li><a href="#">About</a></li>_x000D_
  <li>Bold (native)</li>_x000D_
</ul>_x000D_
<ul class="bold-x3">_x000D_
  <li><a class="hover" href="#">Home</a></li>_x000D_
  <li><a class="hover" href="#">Products</a></li>_x000D_
  <li><a href="#">Contact</a></li>_x000D_
  <li><a href="#">About</a></li>_x000D_
  <li>Black (text-shadow x3)</li>_x000D_
</ul>
_x000D_
_x000D_
_x000D_

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.


Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to css

need to add a class to an element Using Lato fonts in my css (@font-face) Please help me convert this script to a simple image slider Why there is this "clear" class before footer? How to set width of mat-table column in angular? Center content vertically on Vuetify bootstrap 4 file input doesn't show the file name Bootstrap 4: responsive sidebar menu to top navbar Stylesheet not loaded because of MIME-type Force flex item to span full row width

Examples related to hover

Angular 2 Hover event How can I access a hover state in reactjs? CSS disable hover effect How to remove/ignore :hover css style on touch devices Spin or rotate an image on hover How to make in CSS an overlay over an image? How to display and hide a div with CSS? simple Jquery hover enlarge Changing image on hover with CSS/HTML CSS On hover show another element

Examples related to text-size

Text size of android design TabLayout tabs Different font size of strings in the same TextView Text size and different android screen sizes What is the default text size on Android? How to assign text size in sp value using java code Inline elements shifting when made bold on hover