hasLayout.net

CSS "Shrink Wrap"

Description

Description of various methods to make block-level elements to be only as wide as their contents, i.e. "shrink wrap"

Date of the Tutorial

Sat Aug 22 14:47:10 2009

Overview

In this tutorial I will first explain what is the "shrink-wrap" concept and will show you several examples of achieving this effect along with explanations of when each of them would be appropriate to use.

Unless mentioned otherwise, methods described in this tutorial are supported in all modern browsers as well as IE7.

There is a great page on Brunildo.org that you can use as a quick refference.

What Is "Shrink-Wrap" or "Shrink-To-Fit"?

Default behaviour of block-level elements (or rather, elements with display property set to block, list-item and possibly run-in) is to expand width-wise as wide as they can; to take all available width. However, this behaviour may be not wanted in certain cases and instead you would prefer that the element would be just as wide as the content it contains. You could set width to gain something along those lines, but what if content is dynamic or you want the same style to apply to several elements and setting different widths on each is not something you would enjoy doing? This is where "shrinkwrapping" comes into play.

Shrink-wrapping is more "officially" known as "shrink-to-fit" and describes a behaviour of the element where such element's width is defined by its content and it is smaller than the maximum available width if there is not enough content to expand it to such width; much like how height behaves by default.

There are several properties that make elements shrink-to-fit their content. Each of these has certain side-effects (nope, there is no shrink-to-fit: yes) as well as varying browser support; for that reason, you need to know which properties would be the most appropriate to use in any given situation. Grab a glass of your favorite drink and let's go!

Shrinking With Floats

Shrink-to-fit using float property is by far my favorite one. All sane browsers support it and the side effects are miniscule: all is needed sometimes is to either contain floats or use clear property on the following element to force it to appear below our shrinkwrapped element. Let's take a look at the demo:

Ahhhh!! What a shrink!

HTML Code:
<div>
    <p>Ahhhh!! What a shrink!</p>
</div>
CSS Code:
div {
    padding: 10px;
    overflow: hidden;
    display: inline-block;
}
div { display: block; }
p {
    float:left;
    background: #A5A5A5;
    border: 1px solid #000;
}

All we did to our ' element"><p> element is apply float set to value left, although value right works just as well with the exception that your element will be on the right. If you want your element centered, then you probably should use a different shrink-wrap method.

The overflow set on the containing ' element"><div> is for containing floats and the display property toggle in two rulesets gives IE7 need for containing floats.

Shrinking With display: inline

Despite the fact that setting display property to value inline on the element and this seems to be a popular thing to recommend by beginners, this method has a ton of quirks most of those beginners are not aware about, and they get bitten more than required by it. Let's see what "limitations" you would acquire using this shrinkwrap method:

  • Can't set width or height
  • Vertical padding does not affect surrounding content
  • Side borders do not show up on "middle" lines if the content wraps over several lines
  • Top and bottom borders show up on each line of text if the content wraps over several lines
  • background is not drawn between lines of text if the content wraps over several lines and sufficient line-height is present; even if the gaps are not visible due to small enough line-height, background-image will not show up correctly as now we would be dealing with several line boxes instead of one block-box.
  • The element does not create a "line break", in other words styling several consecutive ' element"><p> element with {display: inline;} will make them appear side-by-side.

*phew* quite a "disability" list, huh? There are more side-effects for this method, however in some cases it could be just the thing to hit the spot - for once, you can apply text-align on the ancestor element to affect the position of the shrink-wrapped element. Let's take a look at our demo:

Ahhhh!! What a shrink!

HTML Code:
<div>
    <p>Ahhhh!! What a shrink!</p>
</div>
CSS Code:
div {
    padding: 10px;
    text-align: center;
}
p {
    display: inline;
    padding: 10px;
    background: #A5A5A5;
    border: 1px solid #000;
}

Setting {display: inline} on our ' element"><p> element caused it to shrinkwrap around its content as can be seen by the border and background applied to it.

Also, notice that we have padding set to 10px on both, this is not related to the shrink-to-fit, however, notice that the vertical "gaps" between the border edges of our ' element"><p> and its containing ' element"><div> are far less than 10 pixels; this is one of the draw-backs of this method that I've mentioned earlier.

Shrinking With display: inline-block

Aside from a slight kick in the butt that IE needs for this method of shrinkwrapping, this method is quite decent as well. The only drawback I can think of is that the element will start behaving like it's inline-level - in other words, setting several consecutive elements to {display: inline-block;} will cause them to stack up horizontally without causing "line break" and unlike the float method, there isn't much we can do. Let's take a look:

Ahhhh!! What a shrink!

HTML Code:
<div>
    <p>Ahhhh!! What a shrink!</p>
</div>
CSS Code:
p {
    border: 1px solid #000;
    background: #ddd;
    height: 100px;
    display: inline-block; /* gives "layout" to IE */
}
p { display: inline; } /* IE7 fix for inline-block */
/* Set display back for sane browsers */
html > /**/ body p { display: inline-block; }

What a hairy mess! Looks like I'm setting display three times here. You can apply this fix with conditional comments as well to make things clearer. First of all, I've added padding to the containing ' element"><div> simple to show that the padding in my demo is not a side-effect of this method. Also, I have set height on our ' element"><p> simply to show that we still can set dimensions unlike the display: inline method.

What makes the ' element"><p> element shrinkwrap in sane browsers is just one line of code: {display: inline-block;}. The reason I am setting display three times is done for IE7. To acheive the {display: inline-block;} behavior in IE7 we need to give our ' element"><p> "layout" as well as set display property to value inline. To achieve that with conditional comments, we would simply put p { zoom: 1; display: inline; } in IE7 targeted condcoms.

In my example I've put the fix in regular CSS code. First we set {display: inline-block;} on the ' element"><p> element. This will give the element "layout". In a later ruleset we will revert the display value to inline (this "display toggle" makes the "layout" "stick" in IE despite the fact that we are changing the display later on). Now our IE is all set, however, sane browsers not so because we reset display to inline. What we are doing with the last ruleset in my example is settin display back to inline-block for sane browsers, and IE7 will ignore that specially crafted selector because IE7 has "Child Selector Comment Bug".

Shrinking With Absolute Positioning

This method is probably the one you will use the least for the sake of shrinkwrap. Reason for that being that elements with {position: absolute;}, despite getting shrinkwrapped, are taken out of normal flow, which may or may not be what you had in mind for your task.

Note: while this method works in IE7, if an element inside your shrinkwrapped element has "layout", the shrinkwrap will fail.

Ahhhh!! What a shrink!

HTML Code:
<div>
    <p>Ahhhh!! What a shrink!</p>
</div>
CSS Code:
p {
    border: 1px solid #000;
    background: #ddd;
    position: absolute;
    top: 5px;
    left: 5px;
}

The only thing that makes our ' element"><p> element shrinkwrap is position property set to value absolute (fixed shrinkwraps too, but I won't be covering that). However, you can see that I have a couple of extra things set as well. First of all {position: relative;} set on our ' element"><div> is done to make top and left on our ' element"><p> to relate to our ' element"><div>. Most importantly, you can see that I've set height on our ' element"><div>; the reason for that is that {position: absolute;} takes the element out of the flow, without that height our ' element"><div> would have zero height because ' element"><p> is now out of normal flow and therefore does not give any "support" to ' element"><div>s height.

Shrinking With display: table

Lastly, I will talk about shrinkwrapping with display: table. This method of shrinkwrap is quite good as far as draw-backs go (can't really think of anything substantial), however, this method is not supported in IE7. Let's have a look:

Ahhhh!! What a shrink!

HTML Code:
<div>
    <p>Ahhhh!! What a shrink!</p>
</div>
CSS Code:
p {
    border: 1px solid #000;
    background: #ddd;
    display: table;
    margin: 5px auto;
}

Aside from IE7 support, we have quite sweet deal. Not only {display: table;} shrinkwraps our ' element"><p>, we do not need anything special on the container and check this out: left and right margins set to value auto center or ' element"><p> as if width was set on it!

Final Words

In conclusion, I would like to note that there are a few other properties that cause element to shrinkwrap. I will not cover them in this tutorial as I believe they are very rarely used. However, using the knowledge you have gained in this tutorial, you will have absolutely no trouble applying those extra properties should the need arise.