web-dev-qa-db-fra.com

Les éléments en ligne se déplacent lorsqu'ils sont audacieux au survol

J'ai créé un menu horizontal utilisant des listes HTML et CSS. Tout fonctionne comme il se doit sauf lorsque vous survolez les liens. Vous voyez, j'ai créé un état de survol en gras pour les liens, et maintenant les liens de menu changent en raison de la différence de taille en gras.

Je rencontre le même problème que cet article de SitePoint . Cependant, le poste n'a pas de solution appropriée. J'ai cherché partout une solution et je ne peux pas en trouver une ... Je ne peux certainement pas être le seul à essayer de le faire.

Quelqu'un a-t-il une idée?

P.S: Je ne connais pas la largeur du texte dans les éléments de menu, je ne peux donc pas simplement définir la largeur des éléments li.

Ceci est mon code:

HTML:

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

CSS:

.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: #ffffff; 
    margin-left: 8px; 
    margin-right: 5px; 
}
.nav li a:hover{ 
    text-decoration: none; 
    font-weight: bold; 
}
.nav li.first { border: none; }
156
Billy

li, a {
    display:inline-block;
    text-align:center;
    font: normal 14px Open Sans;
    text-transform: uppercase;
}
a:hover {
    font-weight:bold;
}
a::after {
    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>

Consultez l'exemple de travail sur JSfiddle . L'idée est de réserver de l'espace pour le contenu en gras (ou n'importe quel style d'état :hover) dans le pseudo-élément :after et d'utiliser la balise title comme source du contenu.

327
350D

Une solution compromise consiste à simuler en gras avec text-shadow, par exemple:

texte-ombre: 0 0 0,01px noir;

Pour une meilleure comparaison, j'ai créé ces exemples: 

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>

Passer à text-shadow une valeur très basse pour blur-radius rendra l'effet de flou moins évident.

En général, plus vous répétez text-shadow, plus votre texte sera en caractères gras, mais en même temps, vous perdrez la forme originale des lettres.

Je devrais vous avertir que définir le blur-radius en fractions ne produira pas le même rendu dans tous les navigateurs! Safari, par exemple, a besoin de valeurs plus grandes pour le rendre de la même manière que Chrome.

29
Stefan J

Si vous ne pouvez pas définir la largeur, cela signifie que la largeur changera à mesure que le texte devient gras. Il n'y a aucun moyen d'éviter cela, sauf par des compromis tels que la modification du remplissage/des marges pour chaque état.

27
Andrew Vit

Une autre idée utilise letter-spacing 

a {
  letter-spacing: 0.05px
}

a:hover, a:focus {
  font-weight: bold;
  letter-spacing: 0
}
19
John Magnolia

Un ligne dans jQuery:

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

edit: Bien que cela puisse apporter la solution, il convient de mentionner que cela ne fonctionne pas en conjonction avec le code de la publication originale. "display: inline" doit être remplacé par des paramètres flottants pour qu'un réglage de largeur soit effectif et que ce menu horizontal fonctionne comme prévu.

17
Alex

Vous pourriez utiliser quelque chose comme 

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

puis, dans votre css, définissez simplement le contenu de la plage en gras et masquez-le avec une visibilité: masqué, afin qu'il conserve ses dimensions. Vous pouvez ensuite ajuster les marges des éléments suivants pour l’ajuster correctement.

Je ne suis pas sûr si cette approche est SEO friendly si.

5
monk

Je viens de résoudre le problème avec la solution "shadow" ... Cela semble le plus simple et efficace.

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

Pas besoin de répéter l'ombre trois fois (le résultat était le même pour moi).

5
Daniele B

J'ai eu un problème similaire au vôtre. Je voulais que mes liens apparaissent en gras lorsque vous les survolez, mais pas seulement dans le menu, mais également dans le texte. Comme vous pouvez le supposer, ce serait une véritable corvée de déterminer toutes les largeurs. La solution est assez simple:

Créez une zone contenant le texte du lien en gras, mais coloré comme votre arrière-plan et votre lien réel au-dessus. Voici un exemple de ma page:

CSS:

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

Bien sûr, vous devez remplacer # FFFFE0 par la couleur d'arrière-plan de votre page. Les z-indices ne semblent pas être nécessaires, mais je les mets quand même (car l'élément "hypo" apparaîtra après l'élément "hyper" dans le code HTML). Maintenant, pour mettre un lien sur votre page, incluez ce qui suit:

HTML:

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

Le second "ici" sera invisible et caché sous votre lien. Comme il s'agit d'une boîte statique avec Votre texte de lien en gras, le reste de votre texte ne sera plus déplacé puisqu'il a déjà été déplacé avant le survol du lien.

J'espère que j'ai pu aider :).

Si longtemps

4
kay

Solution CSS3 - Expérimentale

(Fausse audace)

Pensé pour partager une solution différente que personne n'a suggéré ici. Il existe une propriété appelée text-stroke qui sera utile pour cela.

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

Ici, je cible le texte à l'intérieur de la balise span et nous le traitons d'un pixel avec black qui simule le style bold pour ce texte particulier.

Notez que cette propriété n'est pas encore largement prise en charge (en écrivant cette réponse), seuls Chrome et Firefox semblent le supporter. Pour plus d'informations sur la prise en charge de text-stroke par le navigateur, vous pouvez vous référer à CanIUse .


Juste pour partager des informations supplémentaires, vous pouvez utiliser -webkit-text-stroke-width: 1px; si vous ne souhaitez pas définir une color pour votre trait.

3
Mr. Alien

Je vous conseillerais de ne pas changer de police (°) en vol stationnaire. Dans ce cas, il ne s'agit que des éléments de menu qui bougent un peu, mais j'ai déjà vu des cas où le paragraphe complet est reformaté parce que l'élargissement entraîne un retour à la ligne supplémentaire. Vous ne voulez pas que cela se produise lorsque la seule chose à faire est de déplacer le curseur; si vous ne faites rien, la mise en page ne devrait pas changer.

Le décalage peut également se produire lors du basculement entre normal et italique. J'essaierais de changer les couleurs ou de faire basculer le soulignement si vous avez de la place sous le texte. (le soulignement doit rester dégagé du bord inférieur)

Je serais boo'd si j'utilisais des polices de changement de classe pour ma classe de conception de formulaire :-)

(°) La police Word est souvent mal utilisée. "Verdana" est une police , "Verdana normal" et "Verdana bold" sont différentes polices de la même police.

2
stevenvh

Vous pouvez travailler avec la propriété "margin":

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

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

Assurez-vous simplement que les marges gauche et droite sont suffisamment grandes pour que l'espace supplémentaire puisse contenir du texte en gras. Pour les mots longs, vous pouvez choisir différentes marges… .. C'est juste une autre solution de contournement mais faire le travail pour moi.

2
Martin Horvath

J'aime utiliser text-shadow à la place. Surtout parce que vous pouvez utiliser des transitions pour animer une ombre de texte.

Tout ce dont vous avez vraiment besoin est:

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

Pour une navigation complète consultez ce jsfiddle: https://jsfiddle.net/831r3yrb/

Support du navigateur et plus d’informations sur l’ombre au texte: http://www.w3schools.com/cssref/css3_pr_text-shadow.asp

1
Lightningsoul

C'est la solution que je préfère. Cela nécessite un peu de JS mais vous n'avez pas besoin que votre propriété title soit exactement la même et votre CSS peut rester très 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>

0
lurkit

J'ai combiné un tas des techniques ci-dessus pour fournir quelque chose qui ne soit pas totalement nul avec js éteint et qui est encore meilleur avec un peu de jQuery. Maintenant que le support des navigateurs pour l'espacement des lettres sous-pixel s'améliore, il est vraiment agréable de l'utiliser.

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
squarecandy

Une approche alternative consisterait à "émuler" un texte en gras via text-shadow. Cela a le bonus (/ malus, selon votre cas) de fonctionner également sur les icônes de polices.

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

Kinda hacky, bien que cela vous évite de dupliquer du texte (ce qui est utile si c.

0
EdoardoSchnell

Il vaut mieux utiliser a :: before à la place a :: after comme ceci:

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

Pour plus de détails: https://jsfiddle.net/r25foavy/

0
clisima

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>

0
Qwertiy

Solution pas très élégante, mais "fonctionne":

a
{
    color: #fff;
}

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

Et ça? Une solution javascript - sans 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>
0
user10099

J'utilise la solution d'ombre de texte comme certains autres mentionnés ici:

text-shadow: 0 0 0.01px;

la différence est que je ne spécifie pas la couleur des ombres. Cette solution est donc universelle pour toutes les couleurs de police.

0
jabko87