CSS: выделение текста без изменения размера контейнера - PullRequest
85 голосов
/ 16 апреля 2011

У меня есть горизонтальное навигационное меню, которое в основном представляет собой <ul> с элементами, расположенными рядом.Я не определяю ширину, а просто использую отступы, потому что я хотел бы, чтобы ширина определялась шириной пункта меню.Я выделил жирным шрифтом выбранный в данный момент элемент.

Проблема в том, что при выделении жирным шрифтом слово становится немного шире, что приводит к небольшому смещению остальных элементов влево или вправо.Есть ли умный способ предотвратить это?Что-то вроде того, чтобы сказать, что отступы игнорируют дополнительную ширину, вызванную жирным шрифтом?Моей первой мыслью было просто вычесть несколько пикселей из отступа «активного» элемента, но эта величина варьируется.

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

Ответы [ 11 ]

124 голосов
/ 20 февраля 2013

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

li:hover {text-shadow:0px 0px 1px black;}

Вот рабочий пример:

body {
  font-family: segoe ui;
}

ul li {
  display: inline-block;
  border-left: 1px solid silver;
  padding: 5px
}

.textshadow :hover {
  text-shadow: 0px 0px 1px black;
}

.textshadow-alt :hover {
  text-shadow: 1px 0px 0px black;
}

.bold :hover {
  font-weight: bold;
}
<ul class="textshadow">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li><code>text-shadow: 0px 0px 1px black;</code></li>
</ul>

<ul class="textshadow-alt">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li><code>text-shadow: 1px 0px 0px black;</code></li>
</ul>

<ul class="bold">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li><code>font-weight: bold;</code></li>
</ul>

Пример jsfiddle

76 голосов
/ 14 сентября 2015

Лучшее рабочее решение с использованием :: после

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добавляет невидимый псевдоэлемент с шириной полужирного текста, полученный из атрибута title.

Решение text-shadow выглядит неестественно на Mac и не использует всю прелесть, которую предлагает рендеринг текста на Mac ..:)

http://jsfiddle.net/85LbG/

Кредит: https://stackoverflow.com/a/20249560/5061744

21 голосов
/ 27 сентября 2017

Наиболее переносимым и визуально приятным решением будет использование text-shadow.Это пересматривает и показывает примеры ответа Торгейра с использованием Alexxali's и моих собственных настроек:

  li:hover { text-shadow: -0.06ex 0 black, 0.06ex 0 black; }

Это помещает крошечные "тени" в черный (используйте название цвета вашего шрифта/ код вместо black при необходимости) с обеих сторон каждой буквы, используя единицы измерения, которые будут правильно масштабироваться при рендеринге шрифта.

warning Предупреждение: pxзначения поддерживают десятичные значения, но они не будут выглядеть так здорово при изменении размера шрифта (например, пользователь масштабирует представление с помощью Ctrl + + ).Вместо этого используйте относительные значения.

В этом ответе используются доли ex единиц, поскольку они масштабируются шрифтом.
В большинстве браузеров по умолчанию *, ожидайте 1ex8px и, следовательно, 0.025ex0.1px.

Убедитесь сами:

li             { color: #000; } /* set text color just in case */
.shadow0       { text-shadow: inherit; }
.shadow2       { text-shadow: -0.02ex 0 #000, 0.02ex 0 #000; }
.shadow4       { text-shadow: -0.04ex 0 #000, 0.04ex 0 #000; }
.shadow6       { text-shadow: -0.06ex 0 #000, 0.06ex 0 #000; }
.shadow8       { text-shadow: -0.08ex 0 #000, 0.08ex 0 #000; }
.bold          { font-weight: bold; }
.bolder        { font-weight: bolder; }
.after span        { display:inline-block; font-weight: bold; } /* workaholic… */
.after:hover span  { font-weight:normal; }
.after span::after { content: attr(title); font-weight: bold; display:block; 
                     height: 0; overflow: hidden; }
.ltrsp         { letter-spacing:0; font-weight:bold; } /* @cgTag */
li.ltrsp:hover { letter-spacing:0.0125ex; }
li:hover       { font-weight: normal!important; text-shadow: none!important; }
<li class="shadow0">MmmIii123 This line tests shadow0 (plain)</li>
<li class="shadow2">MmmIii123 This line tests shadow2 (0.02ex)</li>
<li class="shadow4">MmmIii123 This line tests shadow4 (0.04ex)</li>
<li class="shadow6">MmmIii123 This line tests shadow6 (0.06ex)</li>
<li class="shadow8">MmmIii123 This line tests shadow8 (0.08ex)</li>
<li class="after"><span title="MmmIii123 This line tests [title]"
                   >MmmIii123 This line tests [title]</span> (@workaholic…)</li>
<li class="ltrsp"  >MmmIii123 This line tests ltrsp (@cgTag)</li>
<li class="bold"   >MmmIii123 This line tests bold</li>
<li class="bolder" >MmmIii123 This line tests bolder</li>
<li class="shadow2 bold">MmmIii123 This line tests shadow2 (0.02ex) + bold</li>
<li class="shadow4 bold">MmmIii123 This line tests shadow4 (0.04ex) + bold</li>
<li class="shadow6 bold">MmmIii123 This line tests shadow6 (0.06ex) + bold</li>
<li class="shadow8 bold">MmmIii123 This line tests shadow8 (0.08ex) + bold</li>

Наведите указатель мыши на отрисованные строки, чтобы увидеть, как они отличаются от стандартного текста.

Измените уровень масштабирования браузера ( Ctrl * 1051)* + + и Ctrl + - ), чтобы увидеть, как они различаются.

Я добавил два других решения для сравнения: Трюк с межбуквенным интервалом @ cgTag , который не очень хорошо работает, так как он включает в себя угадывание диапазонов ширины шрифта, и @ workaholic_gangster911's :: after trick trick , который оставляет неудобное дополнительное пространство для расширения полужирного текстане подталкивая соседние текстовые элементы (я ставлю атрибуцию после полужирного текста, чтобы вы могли видеть, как он не перемещается).


В будущем у нас будет больше переменных шрифтов способный к изменению оценки шрифта с помощью font-variation-settings. Поддержка браузера увеличивается (Chrome 63+, Firefox 62+), но для этого требуется больше, чем просто стандартные шрифты, и лишь немногие существующие шрифты поддерживают его.

Если вы встраиваете переменный шрифт, выВы сможете использовать CSS следующим образом:

/* Grade: Increase the typeface's relative weight/density */
@supports (font-variation-settings: 'GRAD' 150) {
  li:hover { font-variation-settings: 'GRAD' 150; }
}
/* Failover for older browsers: tiny shadows at right & left of the text
 * (replace both instances of "black" with the font color) */
@supports not (font-variation-settings: 'GRAD' 150) {
  li:hover { text-shadow: -0.06ex 0 black, 0.06ex 0 black; }
}

Существует живая демонстрация с ползунком для игры с различными классами в Руководстве по изменяемым шрифтам Mozilla.Google Введение в переменные шрифты в Интернете имеет анимированный GIF, демонстрирующий переключение между высокой оценкой и отсутствием оценки:

animated Amstelvar Alpha font demo with toggling grade axis

16 голосов
/ 23 мая 2014

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

a {
   letter-spacing: 1px;
}

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

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

3 голосов
/ 16 апреля 2011

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

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

1 голос
/ 01 октября 2018

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

(Пропустить этот абзацдля TL; DR ...) Я использую веб-шрифт Gotham от cloud.typography.com, и у меня есть кнопки, которые начинаются пустым (с белой рамкой / текстом и прозрачным фоном) и приобретают цвет фонапри наведенииЯ обнаружил, что некоторые цвета фона, которые я использовал, плохо контрастировали с белым текстом, поэтому я хотел поменять текст на черный для этих кнопок, но - из-за визуального трюка или распространенных методов сглаживания - темныйтекст на светлом фоне всегда выглядит легче, чем белый текст на темном фоне.Я обнаружил, что увеличение веса с 400 до 500 для темного текста поддерживает почти такой же «визуальный» вес.Тем не менее, он увеличивал ширину кнопки на крошечную величину - долю пикселя - но этого было достаточно, чтобы кнопки слегка «дрожали», от чего я хотел избавиться.

Решение:

Очевидно, что это действительно сложная задача, поэтому для нее требовалось сложное решение.В конечном итоге я использовал отрицательный letter-spacing для более смелого текста, как рекомендованный выше cgTag, но 1px был бы излишним, поэтому я просто рассчитал именно ту ширину, которая мне была бы нужна.

Изучив кнопку в Chrome devtools,Я обнаружил, что ширина моей кнопки по умолчанию составляет 165,47 пикселей, а при наведении - 165,69 пикселей, разница составляет 0,22 пикселей.У кнопки было 9 символов, так что:

0.22 / 9 = 0.024444px

Преобразовав это значение в em, я мог бы сделать настройку размера шрифта независимой.Моя кнопка использовала размер шрифта 16 пикселей, поэтому:

0.024444 / 16 = 0,001527em

Так что для моего конкретного шрифта следующий CSS сохраняет кнопки точно та же ширина при наведении:

.btn {
  font-weight: 400;
}

.btn:hover {
  font-weight: 500;
  letter-spacing: -0.001527em;
}

После небольшого тестирования и использования приведенной выше формулы вы можете найти точно правильное значение letter-spacing для вашей ситуации, и оно должно работать независимо от размера шрифта.

Единственное предостережение в том, что разные браузеры используют немного разные субпиксельные вычисления, поэтому, если вы стремитесь к этому уровню OCD с идеальной точностью до субпикселя, вам нужно будет повторить тестирование и установить другое значение длякаждый браузер. Стили CSS, ориентированные на браузер, обычно не одобряются , по понятной причине, но я думаю, что это один из вариантов использования, когда это единственный вариант, который имеет смысл.

1 голос
/ 16 апреля 2011

Используйте JavaScript, чтобы установить фиксированную ширину li на основе незакрепленного содержимого, затем выделите жирным шрифтом содержимое, применив стиль к тегу <a> (или добавьте диапазон, если у <li> нет дочерних элементов) .

0 голосов
/ 24 мая 2018

Для более актуального ответа вы можете использовать -webkit-text-stroke-width:

.element {
  font-weight: normal;
}

.element:hover {
  -webkit-text-stroke-width: 1px;
  -webkit-text-stroke-color: black;
}

Это позволяет избежать любых псевдоэлементов (что является плюсом для программ чтения с экрана) и текстовых теней (которыевыглядит грязно и все еще может создавать небольшой эффект «прыжка» или задавать любую фиксированную ширину (что может быть нецелесообразно).

Это также позволяет вам установить элемент более жирным, чем 1px (теоретически вы можете сделатьшрифт, выделенный жирным шрифтом, который вам нравится, и также может быть некачественной тренировкой для создания жирной версии шрифта, не имеющего жирного варианта, такого как пользовательские шрифты. Хотя этого следует избегать, так как некоторые шрифты, вероятно, будут выглядеть нечеткимии jagged)

Я определенно работает в самых последних выпусках Edge, Firefox, Chrome и Opera.Я предполагаю, что это работает в Safari (Opera обычно является хорошим барометром), хотя я не тестировал его в Safari.Он НЕ работает в IE11 или ниже.

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

0 голосов
/ 29 сентября 2017

ОБНОВЛЕНИЕ: пришлось использовать тег B для заголовка, потому что в IE11 псевдокласс i: after не показывался, когда у меня была видимость: скрыто.

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

Решение, представленное здесь, не работает для меня в Chrome.Вертикальное выравнивание входных данных и меток было перепутано с: after класс psuedo и -margins не исправили это.

Вот исправление, при котором у вас не возникает проблем с вертикальным выравниванием.

/* checkbox and radiobutton */
label
{
    position: relative;
    display: inline-block;
    padding-left: 30px;
    line-height: 28px;
}

/* reserve space of bold text so that the container-size remains the same when the label text is set to bold when checked. */
label > input + b + i
{
    font-weight: bold;
    font-style: normal;
    visibility: hidden;
}

label > input:checked + b + i
{
    visibility: visible;
}

/* set title attribute of label > b */
label > input + b:after
{
    display: block;
    content: attr(title);
    font-weight: normal;
    position: absolute;
    left: 30px;
    top: -2px;
    visibility: visible;
}

label > input:checked + b:after
{
    display: none;
}

label > input[type="radio"],
label > input[type="checkbox"]
{
    position: absolute;
    visibility: hidden;
    left: 0px;
    margin: 0px;
    top: 50%;
    transform: translateY(-50%);
}

    label > input[type="radio"] + b,
    label > input[type="checkbox"]  + b
    {
        display: block;
        position: absolute;
        left: 0px;
        margin: 0px;
        top: 50%;
        transform: translateY(-50%);
        width: 24px;
        height: 24px;
        background-color: #00a1a6;
        border-radius: 3px;
    }

    label > input[type="radio"] + b
    {
        border-radius: 50%;
    }

    label > input:checked + b:before
    {
        display: inline-block;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%) rotate(45deg);
        content: '';
        border-width: 0px 3px 3px 0px;
        border-style: solid;
        border-color: #fff;
        width: 4px;
        height: 8px;
        border-radius: 0px;
    }

    label > input[type="checkbox"]:checked + b:before
    {
        transform: translate(-50%, -60%) rotate(45deg);
    }

    label > input[type="radio"]:checked + b:before
    {
        border-width: 0px;
        border-radius: 50%;
        width: 8px;
        height: 8px;
    }
<label><input checked="checked" type="checkbox"/><b title="Male"></b><i>Male</i></label>
<label><input type="checkbox"/><b title="Female"></b><i>Female</i></label>
0 голосов
/ 04 апреля 2013

Вы можете реализовать это, например, при наведении на amazon.com меню «Магазин по отделам». Он использует широкий div. Вы можете создать широкий div и скрыть его правую часть

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...