Skip to content
This repository has been archived by the owner on Nov 9, 2022. It is now read-only.

Image Replacement #60

Closed
loganfranken opened this issue Aug 16, 2012 · 11 comments
Closed

Image Replacement #60

loganfranken opened this issue Aug 16, 2012 · 11 comments
Assignees
Milestone

Comments

@loganfranken
Copy link
Contributor

Image replacement is a technique for replacing a text element within a page with an image. It's very common, so Web Blocks should provide support for it.

Consider the following example: you have an image banner containing the title of your website. Your first thought would be to create the following markup:

<h1><img src="banner.jpg" alt="Website Title" /></h1>

However, this is not very semantic: the intent of the markup is to present the title of the website, not an image of the title of the website. The fact that your title is represented within an image is merely a technical detail specific to the current implementation of the website. Furthermore, imagine if you were restyling the same markup (to fit a smaller viewport size, for example); you're now stuck with an image element in the markup.

Instead, you would ideally want the following markup:

<h1>Website Title</h1>

You would then want to replace the text with an image. This is where image replacement comes into play.

This is one of my personal favorite CSS topics as it has been undergoing research since the early days of CSS Zen Garden and there are still new techniques cropping up. There are a number of techniques (http://css-tricks.com/css-image-replacement/), but I will summarize some of the bigger players:

Fahrer Method

The granddaddy method (http://en.wikipedia.org/wiki/Fahrner_Image_Replacement). This technique works by adding an inner span and then hiding it using display: none. The text is hidden from screen readers, however, so this technique has fallen out of favor.

Phark Method

This is the most common method (http://www.domedia.org/oveklykken/css-image-replacement.php). Very easy, very semantic: you just shove the text offscreen with text-indent: -9999px. The key problem here is that this does not work in a CSS on/images off scenario.

Levin-Alexander Method

This is an adaptation of the Fahrer method (http://levinalex.net/files/20030809/alternatefir.html) with some improvements. The unnecessary span returns but many of the other issues are solved. A couple new issues, including text showing through transparent images, are introduced (see: http://css-tricks.com/css-image-replacement/).

Newer Techniques

Like I said, there are still new techniques being developed for this age-old issue. HTML5 Boilerplate includes a new technique: http://nicolasgallagher.com/another-css-image-replacement-technique/ (which I haven't fully researched)

Next Steps

More research is needed to determine the best option given the requirements of Web Blocks (specifically ease of use and cross-browser supportability).

@ghost ghost assigned loganfranken Aug 16, 2012
@ebollens
Copy link
Contributor

@loganfranken whatever technique we settle on, we want it to require only markup from the end user perspective.

Ideally, I'd think something of this form:

<outer class="image-replacement">
    <img src="..." alt="">
    <inner>Text Alternate</inner.>
</outer>

Where outer is pretty much any element and inner is just about whatever you might find useful here - maybe a text control like span or h1 but also a more complex control like a div. I don't think that things like header and footer make sense for inner, but they certainly fit for outer.

@loganfranken
Copy link
Contributor Author

Cool, I'll continue research. Just to give an end goal: we won't want that img at all, actually, (it's specified in the CSS) so worst case scenario (IMO):

<outer class="image-replacement">
    <inner>Text That Will Be Replaced</inner>
</outer>

And best case scenario:

<outer class="image-replacement>Text That Will Be Replaced</outer>

@ebollens
Copy link
Contributor

I'm not sure we want to avoid the img tag because, if we do that, then an end user has to define their own CSS anyways to make it work. My thought is that we're giving them a way to say "show this image or else fall back to this other thing".

@ebollens
Copy link
Contributor

Thinking about this for a moment, I think we can actually get at least the case of an explicitly defined image or not. Consider these two markup cases:

<outer class="image-replacement">
    <img></img>
    <inner>Text That Will Be Replaced</inner>
</outer>
<outer class="image-replacement">
    <inner>Text That Will Be Replaced</inner>
</outer>

If we have to distinguish between the two cases, we could probably get away with some trickery using the general sibling selector ~ such as :not(img) ~ img for the case where img has another sibling. Unfortunately, I don't think the same is true for this case:

<outer class="image-replacement>Text That Will Be Replaced</outer>

My logic here is that I don't think you can't determine if a class has a child of a given class.

@loganfranken
Copy link
Contributor Author

I'm just a little confused as to why we are also handling a case where an img is provided? The main goal of image replacement is to remove the image from your markup.

@ebollens
Copy link
Contributor

Maybe I'm misunderstanding the purpose of this some. What exactly are we trying to do here? I thought this was about showing text if images are disabled or else showing an image?

@loganfranken
Copy link
Contributor Author

Oh, sorry, no, I probably explained it poorly above. The basic idea is you're trying to replace something like this:

<h1>Website Title</h1>

Or this:

<a href="http://www.twitter.com/">Twitter</a>

With an image using CSS since the alternatives would be less semantic:

<h1><img src="header.jpg" alt="Website Title" /></h1>

(The title of the website is not semantically an image, in this case, it's "Website Title." The fact that it's an image is just an implementation detail of this specific design.)

Or:

<a href="http://www.twitter.com/"><img src="twitter-icon.png" alt="Twitter" /></a>

(Similarly, the link text is not semantically an image, in this case, it's "Twitter")

@ebollens
Copy link
Contributor

Ohhhh, I see what you're saying. Maybe you can just forget everything I said above :P

So basically this is a CSS helper where you need to define an additional class as well to actually place the image?

@loganfranken
Copy link
Contributor Author

Yup, exactly :)

I'm glad we had this discussion, though, as I think it's informative and also got me to thinking about which types of elements should be expected to work with image replacement.

@loganfranken
Copy link
Contributor Author

The most straightforward option to choose would be the Phark method:

.ir
{
    background-color: transparent;      /* https://github.com/h5bp/html5-boilerplate/pull/609 */
    background-repeat: no-repeat;
    border: 0;
    direction: ltr;                     /* Ensure ir is happening from expected direction */
    display: block;
    text-align: left;                   /* Ensure ir is happening from expected direction */
    text-indent: -999em;                /* Used instead of -9999px to hide zoomed text */
    overflow: hidden;
    *line-height: 0;                    /* https://github.com/h5bp/html5-boilerplate/pull/811 */
}

/* https://github.com/h5bp/html5-boilerplate/commit/bb94ded9f34bd098e4fec28e4e0fc6ebb61a11f9 */
.ir br
{
    display: none;              
}

There was some concern that this has performance problems on iPad 1 (http://www.zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement/), but the actual significance of those issues are questionable (h5bp/html5-boilerplate#1005).

Nicholas Gallagher proposed a font-squishing technique (http://nicolasgallagher.com/another-css-image-replacement-technique/), which is also featured as an option in Compass (https://github.com/chriseppstein/compass/blob/stable/frameworks/compass/stylesheets/compass/typography/text/_replacement.scss). The only real advantage of this method is the ability to style inline-block elements.

Issues with the font-squishing technique caused Gallagher to propose a new method (which is currently used in Boilerplate): h5bp/html5-boilerplate#1149 This method uses a pseudo element to push out the content and then falls back to the Phark method for IE6/7 (using the * hack):

.ir
{
    overflow: hidden;
    *text-indent: -999em;
}

.ir:before
{
    content: "";
    display: block;
    width: 0;
    height: 100%;
}

My major concern with this method is that it creates an inconsistency between IE7 and other browsers with inline-block elements. If you use Phark, image replacement with inline-block elements is not supported in any browser. If you use the new H5BP method, image replacement with inline-block is supported in every browser but IE7 (and IE6, but we are not supporting IE6 with Web Blocks).

@loganfranken
Copy link
Contributor Author

I implemented this using the Phark method (with enhancements from HTML5 Boilerplate).

I played around with the alternative method proposed by Gallagher above. As far as I could tell, you had to provide either a display: block or a display: inline-block in the CSS declaration for each element using image replacement. With the Phark method, display: block is part of the main declaration, so you don't have to provide this.

Then, just for kicks, I tried the Phark method but then added the display: inline-block declaration to override display: block from the main declaration. Worked like a charm in all of the browsers I checked (IE9, Firefox, Opera, Chrome, and Safari), so it seems the Phark method works fine with display: inline-block.

I'll continue researching, but Phark just seemed like the most straightforward approach.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants