Замена изображения <img> элемента с помощью CSS.

Перевод статьи:  Replace the Image in an <img> with CSS.
Автор: Marcel Shields.

Эта статья была размещена в качестве гостевого поста на одном из популярных среди веб-разработчиков ресурсе — CSS Tricks. В ней автор делится своим опытом и рассказывает о том, как он вышел из положения, когда должен был заменить находящееся на странице изображение, не имея доступа к исходному HTML коду. Довольно редкий случай, но я уверен, что каждый из нас когда-нибудь оказывался в подобной необычной ситуации. Марсель рассказывает, как ему удалось заменить изображение, не меняя при этом исходного кода страницы и не используя JavaScript. Более того, оказалось, что этот прием является вполне подходящим способом замены контента практически любого элемента изображением.

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

Как-то на работе мне поручили одно задание, заключающееся в замене размещенного на нашем сайте изображения <img> изображением, находящимся на другом хостинге. Довольно простая задача, не правда ли? Однако, проблема заключалась в том, что у меня не было возможности вносить изменения в разметку, поскольку она была уже отправлена в производство, но используемая CMS все еще позволяла мне добавить необходимый CSS или JavaScript код. Какой бы путь я не выбрал в данном случае, изображение вставлялось на все страницы сайта, но мне необходимо было сделать это только на одной конкретной странице, с учетом того, что родительские элементы-контейнеры не предусматривали никаких атрибутов, позволяющих привязаться к требуемой странице.

<head>
<title>Really Cool Page</title>
</head>
<body>
<!–– .header будет использоваться на других страницах сайта с различными
дочерними элементами, поэтому к нему фоновое изображение не применяется. ––>
<div class="header">
<img class="banner" src="http://notrealdomain1.com/banner.png">
</div>
</body>

Это очень просто реализовать средствами JavaScript, но мне все же хотелось узнать существует ли другой, возможно более простой способ. Сделав несколько попыток с помощью Chrome Dev Tools, я пришел к мысли об использовании свойства box-sizing для жесткой фиксации размеров. Далее вставил новое изображение в качестве фона элемента и сдвинул исходное встроенное изображение за рамки видимой области с помощью левого внутреннего отступа и вот что в результате получилось:

/* Все в одном селекторе */
.banner {
display: block;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: url(http://notrealdomain2.com/newbanner.png) no-repeat;
width: 180px; /* ширина нового изображения */
height: 236px; /* высота нового изображения */
padding-left: 180px; /* размер отступа равен ширине нового изображения */
}

Этот метод прекрасно работает и вот его основные преимущества (*о недостатках ниже):

  • Применим к любым элементам, даже к пустым, типа <img> или <hr>.
  • Отличная поддержка браузерами (Chrome, Firefox, Opera, Safari, IE8+), подробности на Can I Use.
  • Позволяет избежать использования SEO-конфликтных свойств типа display: none и ему подобных.

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

Обзор комментариев

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

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

.banner {
display: block;
background: url(http://notrealdomain2.com/newbanner.png) no-repeat;
width: 0px; /* обнуляем значение ширины */
height: 236px; /* высота нового изображения */
padding-left: 180px; /* размер отступа равен ширине нового изображения */
}

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

Некоторые предлагают для достижения той же цели использовать псевдоэлементы :before и :after, не объясняя при этом как именно это делается. Автор статьи категорически заявил, что этот способ не работает. Я тоже сделал пару экспериментов с псевдоэлементами и не добился желаемого результата.

Другой метод хотя самый простой и вполне рабочий, но обладает очень слабой поддержкой в браузерах. Он заключается в использовании свойства content:

.banner {
content: url(http://notrealdomain2.com/newbanner.png);
}

Что касается вытеснения и замены исключительно текста, то здесь тоже имеется несколько вариантов. Вот первый:

.hide-text {
text-indent: 1000%;
white-space: nowrap;
overflow: hidden;
}

Нет, это не опечатка, разработчик, предлагающий этот способ, утверждает, что такое процентное значение необходимо для предотвращения отображения части скрываемого таким способом текста в Firefox.

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

.text-replacement {
display: block;
height: 250px;
width: 250px;
text-indent: -100%;
overflow: hidden;
background: #333 url('url-string') no-repeat;
}

Оба примера используют свойство text-indent, что в случае с текстом является самым оптимальным решением, не требующим манипуляций с шириной, внутренними отступами и свойством box-sizing.

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

  • Если таким образом вы замещаете фрагмент текста, то он все еще остается контентом страницы, хотя и не видимым пользователю. Этот текст по-прежнему может быть выделен. То есть в данном случае вы должны быть абсолютно уверены, что текст, который вы прячете от пользователя, действительно должен быть просто скрыт, а не удален полностью. Ведь ситуации бывают разные, возможно, хотя и маловероятно, что в одном из браузеров стили будут отключены вообще.
  • Это негативно сказывается на производительности ресурса, поскольку, после такой замены мы все же вынуждаем браузер загружать оба изображения.
  • Да, еще одна интересная деталь. При вызове пользователем контекстного меню изображения, доступные действия и отображаемые при этом свойства, будут относиться не к видимому фоновому изображению, а к скрытому встроенному изображению, что может ввести в заблуждение, поскольку элемент все еще ссылается на файл исходного изображения.

Один из читателей в обход проблемы одновременной загрузки двух изображений, предложил изначально использовать однопиксельное прозрачное GIF изображение, с помощью которого, как вам известно, можно заполнить фон любого размера, а затем подгружать необходимую картинку и вставлять ее одним из представленных выше способов. Эта идея тоже не получила должной поддержки, поскольку хотя однопиксельное изображение само по себе очень мало́, оно все-таки требует выполнения дополнительного HTTP запроса для своей загрузки, что также негативно отражается на производительности. С точки зрения SEO это тоже не эффективно, поскольку однопиксельное изображение, ассоциируемое с контентом, который оно должно дополнять, вряд ли будет положительно воспринято поисковыми машинами, даже если оно сопровождается описательными атрибутами alt и title.

В продолжение темы SEO, хочется отметить, что между автором статьи и одним из ее читателей возник нешуточный спор касательно высказывания о том, что применение display: none негативно воспринимается поисковиками. Ведь не секрет, что множество элементов пользовательского веб-интерфейса использует это значение свойства display. К ним можно отнести различные виджеты, закладки, слайд шоу и т.д. В принципе, такой метод скрытия элементов не связан с какими-либо негативными последствиями. Вот приведенная автором цитата Google, позаимствованная с форума StackExchange:

Просто использование свойства display: none само по себе еще не означает автоматическое применение санкций. Ключевым моментом в этом случае является цель его применения. В том случае, если оно необходимо для реализации определенного механизма, как автоматического, так и запускаемого пользователем, который делает контент видимым, то это допустимо.

Но применительно к обсуждаемой здесь теме — замены изображения либо текста, скрытие контента таким образом не является частью какого-либо механизма, поэтому скорее всего поисковики не будут приветствовать такое оформление. Как бы там ни было, я считаю, что скрытие определенных фрагментов страницы с помощью display: none в большей степени является практическим вопросом, нежели теоретическим и любой разработчик может использовать его при необходимости. Отношение к этому приему поисковых систем в данном случае имеет второстепенное значение.

* Примечание переводчика.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *