• Равномерный фон под текстом

    Одно из модных направлений веб-дизайна последних лет — оформление заголовков контрастным фоном. Например, вот так:

    example

    Простая, на первый взгляд, задача решается не так уж и просто: первая же мысль «добавить padding» натыкается на то, что отступ добавляется исключительно в начале и в конце текста, игнорируя переносы:

    padding

    Ближе всех к решению задачи когда-то подошёл akella, добавив border у родительского элемента. Но проблема не решена на 100%: в конце первой строки (место, где переносятся слова) всё равно нет отступа. Решения остальных ребят, которые присылались мне в твиттер, грешили одной и той же проблемой: нужно точно указать место разрыва строк.

    В простейшем случае, когда нужно добавить небольшой отступ, решение оказалось до боли простым. Есть одно «паразитное» CSS-свойство, от которого кодеры обычно избавляются — это свойство outline. Его особенность заключается в том, что во всех браузерах (по крайней мере в тех, в которых я проверял: Safari 4, Firefox 3.5, Opera 10, IE8) контур outline точно повторяет границы текстового элемента. Соответственно, эта строчка кода полностью решает нашу проблему:

    span.uniform-bg {
    	outline: red solid 0.3em;
    }
    

    Не обошлось без ложки дёгтя: в данном случае «плохим мальчиком» оказался Firefox. Во-первых, он иногда рисует контур с небольшим отступом от границ текста, а во-вторых — прочерчивает его между строками, перекрывая текст:

    firefox

    Первая проблема решается довольно просто: достаточно немного «втянуть» контур с помощью CSS-свойства outline-offset (либо -moz-outline-offset, эксклюзивно для Firefox), вторая — добавлением ещё одной обёртки с position:relative, чтобы поднять текст над контуром.

    Итоговое решение выглядит так:

    <style type="text/css">
    	.uniform-bg {
    		background:red;
    		position:relative;
    		outline: red solid 0.3em;
    		-moz-outline-offset:-0.04em;
    	}
    
    	.uniform-bg span {
    		position:relative;
    	}
    </style>
    <h2><span class="uniform-bg"><span>Hello everyone</span></span></h2>
    

    Оно не работает в IE6—7, в них не поддерживается свойство outline. Но, так как это исключительно декоративная задача, можно объединить её с решением от akella и получить почти идеальное решение.

    UPD: читатель Roman указал на баг в отрисовке фона в месте переноса строк в IE6—7. Немножко доработать напильником — и получится вполне приличное решение (обновил пример).

    Лично меня такой способ полностью не устраивает, так как есть ограничения на высоту строки (при больших значениях появляются проблемы между строками) и толщину контура (слишком толстый контур выглядит очень некрасиво). Предлагаю читателям подумать вместе со мной над более гибким решением, а также — совсем крутота — как такое же провернуть с фоном-картинкой.

    Второй способ (upd)

    Тот же читатель Roman предложил ещё один способ решения задачи. Он основан на смещении трех слоёв относительно друг друга: например, если отступ равен x, то второй слой смещается на 2x вправо, а третий на –x, влево:

    method2

    Его можно немного упростить, убрав один слой и добавив левый border у контейнера. Способ более гибкий, чем с outline (который, как выяснилось, не очень дружит с Opera). На основе него я хотел сделать решение с фоновой картинкой, но столкнулся проблемой: вместе с переносом строк переносится и фон, то есть во второй строке фон начинается там же, где заканчивается в первой:

    bg-problem

    Метки: , , ,
  • 37 комментариев

    1. 19 января 2010

      Надо взять на заметку

    2. 19 января 2010

      в словосочетании ничего нельзя вставлять? 🙂

    3. 19 января 2010

      и да в ФФ3.6рц2 бока есть
      http://deer.org.ua/filez/ff36rc2.png

    4. Сергей Чикуенок
      19 января 2010

      В смысле? Можно задать любой текст и любую ширину контейнера, всё будет как надо. А бока можно ещё больше подтянуть.

    5. 19 января 2010

      та я имел ввиду доп-спаны (другие тэги) внутри текста, но понял что не нужно 😉

    6. 19 января 2010

      А чем не устраивает блочный элемент + float?

    7. Костя
      19 января 2010

      >>А чем не устраивает блочный элемент + float?

      Тем, что это не работает )

    8. Андрей
      19 января 2010

      Первое что пришло в голову — добавить неразывный пробел после hello и перед everyone.
      Но это очень кривой костыль.

    9. egorinsk
      19 января 2010

      Чем мне не нравится outline — в той же Опере он тормозит прокрутку страниц.

    10. Андрей
      19 января 2010

      egorinsk, мне из-за этого именно опера не нравится 🙂

    11. egorinsk
      19 января 2010

      Андрей, ну вообще да, у нее есть еще веселые баги с не-обновлением картинки на экране при изменениях в DOM, например когда от выезжающего меню куски нестертые остаются. Сколько сил убито на его лечение, ужас. Естественно, при этом разные версии еще и ведут себя (=глючат) по разному.

      Но с точки зрения пользователя, а не верстальщика — она мне очень даже нравится 🙂

    12. 19 января 2010

      Есть довольно тяжеловесное универсальное решение, но оно слишком тяяяяжелое!
      Там 1 и тот же текст повторяется 3 раза, в 2х случаях он спрятан и спозиционирован под основным блоком с отступами слева и справа. Но там можно подкладывать любой фон, менять расстояния между строками и работает везде.
      Но опять таки слишком много элементов и повторение текста плохо сказывается на seo.

      Если кто подскажет универсальное решение, с 1 блоком то ему огромное спасибо за это 🙂

    13. 20 января 2010

      Ещё outline покалечили в Opera 9.5, сделав его инструментом веб-разработчика: обводку теперь нельзя перекрыть ничем (даже IFRAME 🙂
      http://rusrestaurant.com/tests/opera-bugs/opera95-css-bug-outline.html

    14. radioheaded
      20 января 2010

      Вместо -moz-outline-offset:-0.04em можно поставить .uniform-bg span { background:red; }.

    15. Roman
      20 января 2010

      А как вам такое решение (пока кроме IE 5-7)?
      http://korb.ru/temp/
      Высота строки компенсируется паддингом.

    16. Сергей Чикуенок
      20 января 2010

      Roman, очень хорошо. Обновил статью.

    17. 20 января 2010

      Фон кратным line-height не лечится? (в общем, не панацея, конечно)

    18. 20 января 2010

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

    19. Николай
      20 января 2010

      Фон кстати можно вылечить простым background-attachment:fixed;
      Вот только опять же про IE промолчим…

    20. Сергей Чикуенок
      20 января 2010

      Прокрутка текста с background-attachment: fixed; определённо доставляет 🙂

    21. 21 января 2010

      Наркотики не твоя тема ;)))
      зы: мой єксперимент http://deer.org.ua/2010/01/21/1/

    22. 21 января 2010

      Для многих, лучшим решением будет ручное разбиение фразы на строки при помощи span-ов c padding-ом. Самый психически здоровый способ, при условии, что текст не часто меняется и т.д.

    23. Сергей Чикуенок
      21 января 2010

      uggallery, а чем способ от Романа тяжелее «психически здорового» выделения каждого слова span’ом?

    24. 22 января 2010

      поместив в текст ссылку мы увидим, что в хроме пропадают подчеркивания текста. а если переместить ссылку под span, ie делает блок текста ровно прямоугольным.

      сижу, борюсь с хромом 🙂

    25. 22 января 2010

      По мне дак лучше заголовки вообще с прозрачным фоном делать. Так приятнее и удобнее.

    26. Bryan Watson
      16 февраля 2010

      Sorry, I don’t speak Russian, but here is my rough translation:

      Жаль, я не говорю на русском языке, но вот — мой грубый перевод:

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

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

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

      Кроме того, высота заголовка включена, так типографский поток последователен.

      Вы можете рассмотреть мой демонстрационный пример здесь:
      http: // http://www.bryanwatson.ca/Misc/Block-Heading.html

    27. Сергей Чикуенок
      16 февраля 2010

      Bryan, there are two problems with your solution:

      1. it requires you to know where exactly to put a line break (e.g. preformat header before posting);
      2. it’s not a “bulletproof” solution: if user decides to shrink down window size or increase font size, he receives very weird looking header with some words missing:

    28. Bryan Watson
      16 февраля 2010

      Very true, my solution was mainly to demonstrate that it can look uniform across all browsers.

      Currently, without using some one-off javascript, there is no perfect solution to this issue.

      When used in a practical application, you have to consider what’s more important for your specific project: Presentation or Accessibility

      If accessibility is more important then presentation, then using any of the techniques listed probably wouldn’t be a wise choice in the first place.

      When considering using semantic, clean code for purely presentation purposes, then my solution fits that need.

    29. vlad43
      17 февраля 2010

      Насчет последнего метода — «его можно немного упростить, убрав один слой и добавив левый border у контейнера». Так вот, это дело начинает бажить в IE8, хотя в остальны все отлично 🙁

    30. vlad43
      17 февраля 2010

      как выяснилось, если для основного контейнера не указать left,отличный от 0, то начинаются баги в IE8. Почему — черт его знает. Для IE 6-7 оптимально выдавать вариант с border слева. Проверил в IE6-7-8, Opera 9-10, FF 2-3, Safari 3-4 — работает.

      пример тут: http://vlad.flango.ru/fon-span/

    31. 16 июля 2010

      Начиная с FF 3.6 (Gecko 1.9.2) свойство moz-outline-offset больше не поддерживается, поэтому заменяем:
      .uniform-bg {
      background:red;
      position:relative;
      outline: red solid 0.3em;
      -moz-outline-offset:-0.04em;
      }
      на
      .uniform-bg {
      background:red;
      position:relative;
      outline: red solid 0.3em;
      }
      @-moz-document url-prefix() {.uniform-bg {outline-offset:-0.04em;}}

    32. 3 августа 2010

      Второе решение тоже не идеальное:
      http://igorfrolov.info/s/i/temp/heading_outline.png

      Перехлёст выносных элементов — такое точно не устроит ни одного дизайнера.

    33. 5 сентября 2010

      Так или иначе варианты выглядят вполне не плохо. Сейчас бьюсь с проблемой :hover в варианте с графической подложкой.

    34. 15 октября 2010

      > как выяснилось, если для основного контейнера не указать left,отличный от 0, то начинаются баги в IE8. Почему — черт его знает. Для > IE 6-7 оптимально выдавать вариант с border слева. Проверил в IE6-7-8, Opera 9-10, FF 2-3, Safari 3-4 — работает.

      > пример тут: http://vlad.flango.ru/fon-span/

      по-моему хорошее решение, спасибо vlad43 🙂

    35. Елена
      12 марта 2011

      А как быть, если фон полупрозрачный?Если в примере поменять красный на скажем rgba(1,0,0,0.5), то появляются уродливые горизонтальные полосы из-за наложения полупрозрачности.

    36. 13 декабря 2011

      Если размер шрифта, то нижняя строка наезжает на верхнюю. Как можно побороть ?

    37. 13 декабря 2011

      меньше 1.2