CSS
March 2012 3

Новый метод замены текста картинкой, или избавляемся от -9999px

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



Немного об истории решения этого вопроса.


Самой первой популярной техникой была так называемая FIR (она же — Fahrner Image Replacement), которая появилась в 2003-м году. Она проста как пень, и многие начинающие верстальщики ее до сих пор используют:

<style>
h1.text-hide span { display: none; }
h1.text-hide {
    height: 35px; /* height of the replacement image */
    background-image: url("hello-world.gif");
    background-repeat: no-repeat;
}
</style>
<h1 class="text-hide"><span>Hello world!</span><h1></code>

Знакомая штука? По сути, внутрь тега, в фоне которого лежит наша картинка, мы добавляем инлайновый тег, который дублирует текст на картинке, а потом его скрываем с помощью display:none;
Многие сразу же признали кривизну этой техники, как с точки зрения семантики, так и с точки зрения утяжеления html лишними тегами. Ко всему прочему, ее полюбили серые оптимизаторы, в результате чего некоторые поисковые системы применяли санкции к страницам, перегруженным такими объектами.

В том же году появилась еще одна техника замены. Работала она примерно так:


#ID_OF_ELEMENT {
    padding: HEIGHT_OF_IMAGEpx 0 0 0;
    overflow: hidden;
    background-image: url("hello_world.gif");
    background-repeat: no-repeat; 
    height: 0px !important;
    height /**/:HEIGHT_OF_IMAGEpx;
}

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

-9999px


После всего этого появилась на свет техника Phark’s Accessible Image Replacement, которая является самой популярной на текущий момент и состоящая всего из одной строки:
.text-hide {
   text-indent: -9999px (или -999em);
}

Техника не идеальна, однако если не забывать о некоторых нюансах ее работы, то она сойдет для большинства случаев. В частности, проверять, чтобы text-align был направлен в ту же сторону, что и text-indent (в большинстве случаев — text-align:left). А также, не забывать, что применив ее на элемент со свойством display: inline-block;, этот элемент улетит в IE7 вслед за скрываемым текстом.

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

Новое решение


И вот, несколько дней назад товарищ Zeldman предложил такой вариант:
.text-hide {
   text-indent: 100%;
   white-space: nowrap;
   overflow: hidden;
}

Такой способ решает сразу несколько проблем:
  • Во-первых, можно быть уверенными, что даже самый длинный текст, который скрывается, никогда не достигнет видимого контейнера, даже если длина этого текста будет превышать 9999px
  • Во-вторых, сначала обнаружилась, а потом этим же способом решилась проблема, которая состояла в следующем: каждый раз при задании -9999px в dom-дереве добавлялся невидимый блок такой ширины. И если на обычных браузерах это сказывалось мало, то на iPAD обнаружились серьезные проблемы с производительностью анимации (демо для проверки)

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

Вариант Зелдмана немного оживил ведущих фронт-енд разработчиков, которые ведут оживленные дискуссии в комментах и блогах.
Также, он был замечен командой разработчиков html5boilerplate, которые сейчас активно дискутируют на github на тему включения нового способа скрытия текста в набор вспомогательных классов своего бойлерплейта.

В той же ветке был предложен еще один способ, который имеет право на жизнь:


.text-hide {
    font: 0/0 serif;
    text-shadow: none;
    color: transparent;
}

Этот способ тоже кроссбраузерен — проверено в IE7-10, Opera 11.61, Chrome 17.0, Firefox 10.0, и Safari 5.1.2. Правда, для старых браузеров такой вариант не прокатит — многие из них не понимают нулевое значение шрифта. Например, какой-то из старых Safari вместо нуля может принять значение 6 или 8.

Большую часть информации об истории и новом способе почерпнул из этого поста

UPD: Еще один интеренсный метод от Николаса Галлахера с псевдоэлементом, спасибо за подсказку SelenIT2

UPD2: В комментах к html5-boilerplate на гитхабе появились результаты теста трех способов IR (отрицательный text-indent, положительный text-indent и font: 0/0 a) в нескольких скринридерах. Вариант с font: 0/0 a не фурычит в Window-Eyes (как я понял, вымирающем, его сравнивают с IE5.5), остальное работает везде (хотя при положительном text-indent текст становится видимым во время его озвучки в старых версиях JAWS).
Спасибо SelenIT2, ссылка на комментарий

UPD3:Chris Coyier проделал огромную работу и собрал целый музей, посвященный техникам Image Replacement: CSS Image Replacement Museum
+92
32.2k 583
Comments 87
Top of the day