Skip to content
This repository

Look into updating .ir to use a "new and improved" method #1005

Closed
davidmurdoch opened this Issue March 01, 2012 · 52 comments
David Murdoch

This article claims that -9999px (or -999em in our case) has noticeable performance issues when running animations on the iPad 1.

Performance is dramatically improved because a 9999px box is not drawn. Noticeably so in animations on the iPad 1.

The new CSS would be something like:

.ir {
    text-indent: 100%;
    white-space: nowrap;
    overflow: hidden;
}

Also, H5BP has some non-obvious tweaks in the existing .ir class that would need to be evaluated if this new method were to be implemented.

Mathias Bynens
Owner

Demo that’s supposed to show the performance difference: http://lab.pgdn.us/hidden-text-performance/

Scott Kellum

Happy to see the FIR method being updated.

@necolas also pointed out the NIR method here: http://nicolasgallagher.com/css-image-replacement-with-pseudo-elements/
Lack of support for IE7 and below might be a deal breaker though, it is for me in most situations anyway.

Nicolas Gallagher
Owner

Other than first gen iPads, what other browser/OS combos experience noticeable perf benefits from this?

David Murdoch

@scottkellum, the method I posted should be IE5.5+ compatible, I believe. According to MDN IE has supported white-space: nowrap since version 5.5, overflow: hidden since version 4.0, and text-indent since 3.0.

Disregard if you were just referring to @necolas' version.

Scott Kellum

You can identify the performance hit with a CSS profiler. It will not be visible in the frame rate as the demo is running on a single page.

Here are the numbers: http://yfrog.com/kgqzwp

Small but it adds up with each redraw, new element, and animation.

David Murdoch

@necolas I just tested on Android 2.2 running in a Huawei M835/Comet (One of the worst Android-based phones of 2010) and the demo Mathias posted doesn't stutter at all.

Nicolas Gallagher
Owner

Whatever that profiler data is showing, the difference is 0.007ms - extremely small even if you scale that up hundreds of times. Actual framerate/scrolling/rendering/etc degradation would be a concern.

Paul Lewis

@necolas I've just tested it on iPad 2 and iPhone 4S, neither of which stuttered. So far the only claimed benefit seems to be the iPad 1 as far as I can tell.

Paul Irish
Owner

So I just switched the order of the two testcases in this file and rerun the CSS selector profiler and it's indicating the inverse results:

test page: http://dl.dropbox.com/u/39519/temp/hiddentextperf.html


So your evidence of an improvement isn't too trustworthy, but I'm not 100% concerned because the CSS Selector profiler merely matches at selector matching, not style recalculations and reflow.

Measuring that is different, but let me see if i can wire up a more appropriate test page for it.

Scott Kellum

Thanks @paulirish. This is just a little something I wiped up trying to speed up animations on complex pages. I have noticed performance increases in animations but an having trouble applying quantitative data to them.

What steered me away from FIR: http://techblog.netflix.com/2012/01/webkit-in-your-living-room.html

Honestly, the FIR method is tried and true. I am not saying my method is perfect but it works well for me. Other people seem to like it and I am flattered.

Nicolas Gallagher
Owner

What steered me away from FIR...

What does the video say that convinced you?

Paul Irish
Owner

Certainly, but if this is the new best technique then it should, in fact, be the best. I'd be happy to see that it is, but 1) i don't want to see people regress the perf of their sites but wrongly implementing this change and 2) i want to see people prioritize performance issues well.

scott, come by #html5 on freenode -- we're banging this out now.

Paul Irish
Owner

Also Seeley's presentation is awesome. +++ it

Paul Irish
Owner

So I think the most optimal way to measure this cost is a test page with some large number (like 1000) of elements with .ir applied to them. Then in Chrome/Safari open the Dev Tools and Timeline panel. Record, refresh, and look at the Style Recalc, Layout and Paint actions. Those are where we'd see a change.

And hypothetically there is a significant difference ( >20ms diff for layout/paint would be "large", even though these numbers are small)

We don't have this sort of instrumentation on iPad so you'd have to use some +new Date() measurements from <head> to window.onload and hope to see a difference (or benchmark.js), but you're capturing a lot more browser lifecycle so it may be too messy to get hard data.

Scott Kellum

@necolas Finally, found where he talks about text-indent: http://youtu.be/xuMWhto62Eo?t=35m15s

Jonathan Neal
Collaborator

What about this? https://gist.github.com/1954805

.ir
{
    direction: ltr;
    font: 0/0 serif;
    overflow: hidden;
    text-indent: 100%;
    white-space: nowrap;
}

.ir *
{
    clip: rect(0 0 0 0);
    position: absolute;
}

I've set the direction (because h5bp does), but that might not be necessary; it depends on how right-to-left text impacts text-indent: 100%. The font is compressed to decrease the size of the "invisible box"; one of the main suspects of performance. The overflow, text-indent, and white-space (as mentioned by others) hide the text. The descendants of .ir get the usual hidden-but-screen-readable treatment.

Also, would it be useful to use the bookmarklet at http://andy.edinborough.org/CSS-Stress-Testing-and-Performance-Profiling to test and quantify the performance of these different methods ( like the ones seen at http://lab.pgdn.us/hidden-text-performance/ )?

Here's a potential test page at http://jsfiddle.net/CpewT/3/show/

Nicolas Gallagher
Owner

If the text is going to be crushed out of existence, like we did when working on that IE-expression-powered clearfix, then you don't need white-space: nowrap...might not even need the text-indent either (haven't tested in all browsers).

.ir {
    font: 0/0 serif;
    overflow: hidden;
    text-shadow: none;
}

However, there might be a reason why crushing the text in IR methods isn't used already - such as it being hidden on screenreaders. Worth checking that it doesn't cause any additional accessibility problems.

Scott Kellum

Might not even need overflow:hidden as the text is already gone.

.ir {
    font: 0/0 serif;
    text-shadow: none;
}

Also, direction: ltr is not as important as text-align: left. It doesn’t really matter what direction the text is flowing as long as it is left aligned. Again, not needed as the text is gone :)

Jonathan Neal
Collaborator

Older Safari browsers could not crush text out of existence. Font size 0 would render as font size 6 or 8. However, in a Safari 4+ or Safari 5+ world, I'm not sure if that is still the case.

I was shrinking the font size to reduce the size of the invisible box that was reportedly being drawn off screen on the iPad and adding a substantial and noticeable performance hit.

If font size does the trick all by itself in 2012, well, awesome.

Chris Eppstein

@jonathantneal In older safaris, will color: transparent be respected?

Chris Eppstein

I would also point out that we can use @media screen to avoid issues with readers.

Nicolas Gallagher
Owner

I just tested in Safari 4 - the text is very small but not crushed down into an invisible pixel. You still get a line of tiny text. Setting color: transparent did hide it though.

Safari 5, like modern browsers, only needs the font and text-shadow styles.

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

I would also point out that we can use @media screen to avoid issues with readers.

Really? Given the amount of time spent debating the use of display:none and its effects on accessibility, I would find it really surprising if this claim were correct.

Chris Eppstein

@necolas tested - that works on IE6-9 and all the way back to FF3 and Opera 10

Chris Eppstein

Re: @media screen My claim is a theoretical one, but would not expect display:none to have any correspondance to a media query in terms of behavior. display none means "remove from the document" -- it's not a visual property.

Nicolas Gallagher
Owner

What I meant was that if styles in @media screen were hidden from screenreaders, that fact would have been exploited by now to shield screenreaders from styles that might negatively impact the experience for users of that tech.

As an aside: display affects the formatting structure; so "remove from the document" doesn't seem like an accurate characterisation, especially since that makes it sound like the DOM is affected. It's just that screenreaders take some CSS into account when deciding how to present the document.

Scott Kellum

Screen readers can be used/are included in most modern browsers. Just because something is on screen doesn’t mean it won’t also be read by a screen reader.

Chris Eppstein

@necolas right. but to the point, is there no way to use @media queries to target screen readers in a production-quality way? that would be severely disappointing if it were true.

Nicolas Gallagher
Owner

@chriseppstein I don't think so :(

There's this stuff - http://www.w3.org/TR/CSS21/aural.html - but afaik, it has pretty much zero support in existing screenreaders. Was looking at using speak to prevent the reading of chars inserted as generated content and used by icon fonts, but no screenreaders supported speak. Maybe one day.

Jonathan Neal
Collaborator

For the record, Safari 4 was released before Internet Explorer 8, and Safari 5 has been on the market since June of 2010.

Related: Are there statistics we trust to provide us the latest browser usage trends? How can I find out which versions of Opera, Chrome, Firefox, IE, and Safari are supported by the manufacturer? A combination of those sets of information would be very useful when evaluating the pros and cons of these css image replacement methods.

Nicolas Gallagher
Owner

@jonathantneal http://gs.statcounter.com/#browser_version-ww-monthly-201112-201202

Safari 4 died ages ago. The fix for it is more of a technical novelty than a necessity.

Jonathan Neal
Collaborator

Well, looks like font: 0/0 will work. For the record (if it even came up), I don't want anything named after me. :P

http://jsfiddle.net/355CP/show/ is working well for me in IE7-10, Opera 11.61, Chrome 17.0, Firefox 10.0, and Safari 5.1.2.

Scott Kellum

Settling on this then? Looks good to me.

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

Merging into H5BP might be a little weird. There are a lot of properties in the current version that might cause issues with people upgrading to this. I’m not a H5BP user though, not sure how you roll these things out :P

Nicolas Gallagher
Owner

@scottkellum Yeah I think so! This technique works and seems pretty robust. We don't encourage people to upgrade live sites so it shouldn't be an issue for H5BP users.

I'll merge this in over the weekend. I've actually been using the font hack part of this technique for nearly a year when making icon components...but didn't think anything of it. It's already in this early version of the H5BP UI toolkit - https://github.com/h5bp/h5bp-ui/blob/alpha/scss/_icons.scss - but I should probably use the shorthand that I used to help remove IE6/7 whitespace in this expression-powered clearfix experiment that Jon and I worked on: https://gist.github.com/935783/

As an aside: The reason I had to use it for icon components was because of a weird IE7 layout bug that seems to occur when text-indent is used, inner text is used for screenreader love, the icon is inline-block, and it's nested within another element (I seem to remember it happening in combo with my button components). The suffering never ends.

Chris Eppstein

Talking to a coworker: we are curious whether this will have negative SEO impacts compared to the negative text-indent approach. From what I could discern, one should expect that this text will not be indexed and if used on a lot of text, one might expect to be flagged as a spammer.

Nicolas Gallagher
Owner

All these techniques appear to work with VoiceOver. Text is not hidden from the screenreader.

Nicolas Gallagher
Owner

I came across an early version of the text-crushing approach (2003) - http://www.maxdesign.com.au/articles/headings-as-images/

Nicolas Gallagher necolas closed this issue from a commit March 05, 2012
Commit has since been removed from the repository and is no longer available.
Nicolas Gallagher necolas closed this in 09134cd March 05, 2012
Dorian Patterson imaginationac referenced this issue from a commit in imaginationac/html5-boilerplate March 05, 2012
Nicolas Gallagher Update CSS image replacement technique
The new technique avoids various problems with any text-indent method.
The benefits are:

* No box of any kind is drawn offscreen, so there is no risk of
  related performance problems in old iOS devices.

* No need to specify a text-alignment and hide overflow since the text
  is crushed to take up no space.

* No need to hide `br` or make all fallback HTML `display:inline`
  because unlike the text-indent approaches, this method is not
  affected by those scenarios.

* Fewer styles are needed as a result of these improvements.

The function of the new CSS is as follows:

* `font: 0/0 a` is a shorthand property that reduces the font-size and
  line-height to 0. The `a` value acts as a font-family. The CSS
  validator complains that using `0/0` in the shorthand `font` property
  is not valid, but every browser accepts it.

* `text-shadow: none` makes sure than any inherited text shadow is
  removed, otherwise it will show over the image.

* `color: transparent` is only really needed in browsers than don't
  completely crush the text to the point of being invisible. Safari 4 is
  such a browser (but extremely rare). Leaving it in for now in case
  there are any mobile browsers that require it. Upon further testing,
  it may be possible to remove this declaration.

Some parts of the pre-existing image replacement technique have been
retained. The border and background resets are useful when using IR on
form submit inputs or buttons, as well as when links use default borders
or backgrounds

Close #1005
aa0396e
Brendan Falkowski

The new image replacement technique is bugging when the element has display:inline-block. See: http://jsfiddle.net/brendanf/SGPqc/2/

Jonathan Neal
Collaborator

They look the same to me in that fiddle, @brendanf . What browser and could you include a screenshot?

Brendan Falkowski

Tested in latest Mac versions of Chrome/Safari/Firefox/Opera. Screenshot: http://cl.ly/FYVx

Notes in the 'Info' panel. Example 2 has odd ghost-padding.

cust0dian

Same with Windows in Chrome 18 (latest); Firefox 10, 11 (latest); Opera 11.62 (latest); IE 8.

Darryl Pogue

This is fixed (at least in Chrome 19-dev on Linux) if you set a vertical-align on foo.
Doesn't seem to matter what the value is, as long as it's set (I've tried top, middle, and bottom).

EDIT: Just tested, and vertical-align: baseline causes the extra padding to appear.
You can also fix it by setting a line-height on ir, but it's unlikely all your replacements need to be the same height.

cust0dian

Setting vertical-align on ir fixes this (latest Chrome, Firefox, Opera; IE8; Windows), but what is the cause? Padding is 15px, is text flown out of the foo?

Nicolas Gallagher
Owner

There is no padding; it's because the font: 0/0 a means the ir-ed element's baseline is at the top of its box, so the default vertical alignment (baseline) results in it lining the top of the box with the baseline of its parent's line-box. Setting it to middle seems the best option.

FYI, the old IR techniques break in IE6/7 when used on inline-block.

Brendan Falkowski

I updated the JSFiddle with more test cases, and the vertical-align:middle fix:
http://jsfiddle.net/brendanf/SGPqc/4/

Also confirmed in IE8 + IE9. Not relevant to IE7 and below since inline-block isn't supported.

Patched proposal:

.ir {
    color:transparent;
    font:0/0 a;
    text-shadow:none;
    vertical-align:middle;
}

Note: I removed border:0 and background-color:transparent which where added in this commit: imaginationac@aa0396e

Zeroing border doesn't affect the behavior, but implies styling (for form inputs). I think this goes too far. Adding the ir technique shouldn't require extra specificity in rules to override its style. It's simpler for authors to extend styles as needed when ir is chained than making border:0 an absolute. Extend is better than override.

Same argument for background-color:transparent. It's one extra thing to override.

Nicolas Gallagher
Owner

IE7 is relevant. The inline-block works on inline by-default elements, and there is a hack to have it work on block by-default elements.

Jonathan Neal
Collaborator

In regards to vertical-align, I'm not sure that we're discussing a bug that needs to be fixed, but rather we're discovering the default behavior of vertical-align.

http://css-tricks.com/what-is-vertical-align/

The default value of vertical-align (if you declare nothing), is baseline. Images will line up with the text at the baseline of the text. Note that descenders on letters dip below the baseline. Images don't line up with the lowest point of the descenders, that isn't the baseline.

In regards to IE6/7 and inline-block, the solution is simple:

display: inline-block; /* inline-block is half-supported in IE7, unsupported in IE6 */
*display: inline; /*  asterisked CSS is only used in IE6/7, and inline is supported */
*zoom: 1; /* zoom causes inline to behave like inline-block */
Brendan Falkowski

@necoloas: Ah, yes. Forgot about that.

Added a test case (Ex. 6) using span set to inline-block for IE7:
http://jsfiddle.net/brendanf/SGPqc/7/

Setting vertical-align:middle creates 1px offset at the top in IE7. This doesn't happen with top, bottom, or baseline (which causes the larger offset in every other browser).

Setting vertical-align:top (or bottom) seem the most bullet-proof.

@jonathantneal: Wasn't trying to solve IE6/7 behavior, but the updated ir technique breaks on any element having inline-block in sub-modern browsers and up. Setting vertical-align fixes that behavior. I think helper classes should have the smallest footprint to solve the issue.

Nicolas Gallagher
Owner

In regards to vertical-align, I'm not sure that we're discussing a bug that needs to be fixed, but rather we're discovering the default behavior of vertical-align.

Yeah, it's the default behaviour of baseline...but the outcome isn't desired, so it's probably worth using middle instead.

Brendan Falkowski

Yeah, it's the default behaviour of baseline...but the outcome isn't desired, so it's probably worth using middle instead.

Note: middle breaks in IE7 though (1px offset). Screenshot: http://cl.ly/FZyU

Setting top or bottom works best cross-browser as far as I've tested.

Jonathan Neal
Collaborator

@brendanf with small graphics, especially icons, vertical-align: middle is often preferred because it vertically centers an image with a line of text.

An example of vertical-align middle.

However, for larger images, vertical-align: top is often preferred because it vertically stacks itself to the top like other (block) layout elements.

Here is an example of a large image vertically aligned 8 different ways. http://jsfiddle.net/mUQLz/

Nicolas Gallagher
Owner

@brendanf I don't think a 1px gap means something is "broken" :)

Brendan Falkowski

@jonathantneal Agreed, that's a common use case and worth giving priority. Typically (and in the case that brought me here) I'm using sprite images within pseudo-content rather than inline images. Necessary for optimizing icons on standard and high DPI displays.

@necolas Ha! Owed to my mis-spent youth in the dark age of pixel-perfect tables.

I yield that vertical-align: middle is probably the most comprehensive and forgiving option.

Logan Franken loganfranken referenced this issue in ucla/WebBlocks October 08, 2012
Closed

Image Replacement #60

David Clark davidtheclark referenced this issue in davidtheclark/scut November 24, 2013
Closed

Include full-width color mixin #101

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.