Встроенные элементы смещаются при выделении жирным шрифтом при наведении курсора мыши

StackOverflow https://stackoverflow.com/questions/556153

  •  05-09-2019
  •  | 
  •  

Вопрос

Я создал горизонтальное меню, используя HTML-списки и CSS.Все работает так, как должно, за исключением того, что вы наводите курсор на ссылки.Видите ли, я выделил ссылки жирным шрифтом при наведении курсора, и теперь ссылки меню смещаются из-за разницы в размере жирного шрифта.

Я сталкиваюсь с той же проблемой, что и этот пост с сайта SitePoint.Однако в сообщении нет надлежащего решения.Я везде искал решение и не могу его найти.Конечно, я не могу быть единственным, кто пытается это сделать.

У кого-нибудь есть какие-нибудь идеи?

P.S:Я не знаю ширину текста в пунктах меню, поэтому я не могу просто установить ширину элементов 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>

Это было полезно?

Решение

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

Проверьте рабочий пример на JSfiddle ( Ошибка ).Идея состоит в том, чтобы зарезервировать место для выделенных жирным шрифтом (или любых :hover стили состояния) контент в :after псевдоэлемент и использование тега title в качестве источника контента.

Другие советы

Скомпрометированное решение - подделать жирный шрифт с помощью текстовой тени, например:

текст-тень:0 0 0.01пикселей черный;

Для лучшего сравнения я создал эти примеры:

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 to fractions не будет отображаться одинаково во всех браузерах!Safari, например, нужны большие значения, чтобы отображать его так же, как это будет делать Chrome.

Если вы не можете установить ширину, то это означает, что ширина будет меняться по мере того, как текст будет выделяться жирным шрифтом.Нет никакого способа избежать этого, кроме как путем компромиссов, таких как изменение отступов / полей для каждого состояния.

Другая идея заключается в использовании letter-spacing

a {
  letter-spacing: 0.05px
}

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

Один строка в jquery:

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

Редактировать: Хотя это может привести к решению, следует упомянуть, что оно не работает в сочетании с кодом в исходном сообщении."display: встроенный" должен быть заменен на плавающие параметры, чтобы настройка ширины была эффективной, а горизонтальное меню работало так, как задумано.

Вы могли бы использовать что-то вроде

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

а затем в вашем css просто выделите span content жирным шрифтом и скройте его видимостью:скрытый, так что он сохраняет свои размеры.Затем вы можете отрегулировать поля следующих элементов, чтобы они соответствовали размеру должным образом.

Однако я не уверен, что такой подход подходит для SEO.

Я только что решил проблему с помощью "теневого" решения.Это кажется самым простым и эффективным.

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

Не нужно повторять нанесение тени три раза (результат у меня был тот же).

Решение 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, вы можете обратиться к КанИУзе.


Просто для того, чтобы поделиться некоторыми дополнительными материалами, вы можете использовать -webkit-text-stroke-width: 1px; если вы не хотите устанавливать color для твоего инсульта.

У меня была проблема, похожая на вашу.Я хотел, чтобы мои ссылки выделялись жирным шрифтом при наведении на них курсора мыши, но не только в меню, но и в тексте.Как вы можете догадаться, было бы настоящей рутиной вычислить все размеры разной ширины.Решение довольно простое:

Создайте поле, содержащее текст ссылки, выделенный жирным шрифтом, но окрашенный в цвет вашего фона, и вашу реальную ссылку над ним.Вот пример с моей страницы:

CSS - файл:

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

Конечно, вам нужно заменить #FFFFE0 на цвет фона вашей страницы.Z-индексы, кажется, не нужны, но я все равно их добавляю (поскольку элемент "hypo" будет располагаться после элемента "hyper" в HTML-коде).Теперь, чтобы разместить ссылку на своей странице, укажите следующее:

HTML:

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

Второе "здесь" будет невидимым и скрытым под вашей ссылкой.Поскольку это статическое поле с текст вашей ссылки выделен жирным шрифтом, остальной текст больше не будет смещаться, поскольку он уже был смещен до того, как вы навели курсор на ссылку.

Надеюсь, я смог помочь :).

Так долго

Я бы посоветовал не переключать шрифты (°) при наведении курсора мыши.В данном случае это просто небольшое перемещение пунктов меню, но я видел случаи, когда весь абзац переформатировался, потому что расширение привело к дополнительному переносу слов.Вы же не хотите, чтобы это происходило, когда единственное, что вы делаете, это перемещаете курсор;если вы ничего не предпримете, макет страницы не должен измениться.

Сдвиг также может произойти при переключении между обычным шрифтом и курсивом.Я бы попробовал изменить цвета или переключить подчеркивание, если у вас есть место под текстом.(подчеркивание должно оставаться четким от нижней границы)

Меня бы освистали, если бы я использовал переключение шрифтов для своего класса дизайна формы :-)

(°) Слово "шрифт" часто используется неправильно."Вердана" - это шрифт, "Verdana normal" и "Verdana bold" отличаются друг от друга шрифты того же шрифта.

Вы можете работать со свойством "margin":

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

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

Просто убедитесь, что левое и правое поля достаточно большие, чтобы в дополнительном пространстве мог быть выделен жирный текст.Для длинных слов вы можете выбрать другие поля.Это просто еще один обходной путь, но он выполняет эту работу за меня.

Вместо этого мне нравится использовать text-shadow .Особенно потому, что вы можете использовать переходы для анимации текста-тени.

Все, что вам действительно нужно, это:

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

Для получения полной навигации ознакомьтесь с этим jsfiddle:https://jsfiddle.net/831r3yrb/

Поддержка браузера и дополнительная информация о text-shadow:http://www.w3schools.com/cssref/css3_pr_text-shadow.asp

Это решение, которое я предпочитаю.Для этого требуется немного 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>

А как насчет этого?Бесплатное решение на 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>

Не очень элегантное решение, но "работает":

a
{
    color: #fff;
}

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

Я объединил кучу методов, описанных выше, чтобы обеспечить что-то, что не совсем отстойно с отключенным 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>

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>

Я использую решение text-shadow, как и некоторые другие, упомянутые здесь:

text-shadow: 0 0 0.01px;

разница в том, что я не указываю цвет тени, поэтому это решение универсально для всех цветов шрифта.

Альтернативным подходом было бы "эмулировать" жирный текст с помощью text-shadow.Это дает бонус (/ malus, в зависимости от вашего случая) для работы также с иконками шрифтов.

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

Довольно халтурно, хотя это избавляет вас от дублирования текста (что полезно, если его много, как это было в моем случае).

Это лучше использовать a::перед вместо этого a::после вот так:

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

Если вы не прочь использовать Javascript, вы можете установить нужную ширину после отображения страницы.Вот как я это сделал (используя 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' });
}

Я действительно терпеть не могу, когда кто-то говорит тебе не делать что-то таким образом, когда есть простое решение проблемы.Я не уверен насчет li elements, но я только что исправил ту же проблему.У меня есть меню, состоящее из тегов div.

Просто установите для тега div значение "отображать:встроенный блок".Встроенные, чтобы они располагались рядом друг с другом и перекрывали друг друга, для чего вы можете задать ширину.Просто установите ширину, достаточную для размещения выделенного жирным шрифтом текста, и выровняйте текст по центру.

(Примечание:Кажется, что это удаляет мой html [ниже], но вокруг каждого пункта меню был обернут тег div с соответствующим идентификатором и именем класса SearchBar_Cateogory .ie: <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;
}

попробуй это:

.nav {
  font-family: monospace;
}

Вы также можете попробовать использовать отрицательные поля, если жирный текст шире обычного.(не всегда) Итак, идея состоит в том, чтобы использовать классы вместо этого для стилизации состояния :hover .

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

Я надеюсь, что смог бы помочь!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top