I have a horizontal navigation menu, which is basically just a
with the elements set side-by-side. I do not define width, but simply use padding, bec
Use JavaScript to set a fixed width of the li based on the unbolded content, then bold the content by applying a style to the <a>
tag (or add a span if the <li>
doesn't have any children).
The best working solution using ::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;
}
It adds an invisible pseudo-element with width of bold text, sourced by title
attribute.
The text-shadow
solution looks unnatural on Mac and doesn't utilize all the beauty that text rendering on Mac offers.. :)
http://jsfiddle.net/85LbG/
Credit: https://stackoverflow.com/a/20249560/5061744
For a more up-to-date answer, you can use -webkit-text-stroke-width
:
.element {
font-weight: normal;
}
.element:hover {
-webkit-text-stroke-width: 1px;
-webkit-text-stroke-color: black;
}
This avoids any pseudo-elements (which is a plus for screen readers) and text-shadows (which looks messy and can still create a slight 'jump' effect) or setting any fixed widths (which can be impractical).
It also allows you to set an element to be bolder than 1px (theoretically, you can make a font as bold as you like and could also be a shoddy-ish workout for creating a bold version of a font that doesn't have a bold variant, like custom fonts (edit: variable fonts depreciate this suggestion). Though this should be avoided as it will probably make some fonts appear scratchy and jagged)
I this definitely works in Edge, Firefox, Chrome and Opera (at time of posting) and in Safari (edit: @Lars Blumberg thanks for confirming that). It does NOT work in IE11 or below.
Also note, it uses the -webkit
prefix, so this is not standard and support may be dropped in the future, so don't rely on this is bold is really important - it's best to avoid this technique unless it's merely aesthetic.
This is a very old question, but I'm revisiting it because I had this problem in an app I'm developing and found all of the answers here wanting.
(Skip this paragraph for the TL;DR...) I'm using the Gotham webfont from cloud.typography.com, and I have buttons which start hollow (with a white border/text and a transparent background) and acquire a background color on hover. I found that some of the background colors I was using didn't contrast well with the white text, so I wanted to change the text to black for those buttons, but — whether because of a visual trick or common anti-aliasing methods — dark text on a light background always appears to be lighter weight than white text on a dark background. I found that increasing the weight from 400 to 500 for the dark text maintained almost exactly the same "visual" weight. However, it was increasing the button width by a tiny amount — a fraction of a pixel — but it was enough to make the buttons appear to "jitter" slightly, which I wanted to get rid of.
Solution:
Obviously, this is a really finicky problem so it required a finicky solution. Ultimately I used a negative letter-spacing
on the bolder text as cgTag recommended above, but 1px would have been way overkill, so I just calculated exactly the width I would need.
By inspecting the button in Chrome devtools, I found that the default width of my button was 165.47px, and 165.69px on hover, a difference of 0.22px. The button had 9 characters, so:
0.22 / 9 = 0.024444px
By converting that to em units I could make the adjustment font-size agnostic. My button was using a font size of 16px, so:
0.024444 / 16 = 0.001527em
So for my particular font, the following CSS keeps the buttons exactly the same width on hover:
.btn {
font-weight: 400;
}
.btn:hover {
font-weight: 500;
letter-spacing: -0.001527em;
}
With a little testing and using the formula above, you can find exactly the right letter-spacing
value for your situation, and it should work regardless of font size.
The one caveat is that different browsers use slightly different sub-pixel calculations, so if you're aiming for this OCD level of sub-pixel-perfect precision, you'll need to repeat the testing and set a different value for each browser. Browser-targeted CSS styles are generally frowned upon, for good reason, but I think this is one use case where it's the only option that makes sense.
You can implement this like amazon.com "Shop by department" hover menu. It uses wide div. You can create wide div and hide its right part
Unfortunately the only way to avoid the width changing when the text is bold is to define the width of the list item, however as you stated doing this manually is time consuming and not scalable.
The only thing I can think of is using some javascript that calculates the width of the tab before it is bold, and then applies the width at the same time the bold is required (either when you hover or click).