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
Description of various methods to make block-level elements to be only as wide as their contents, i.e. "shrink wrap"
Sat Aug 22 14:47:10 2009
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 IE6 and IE7.
There is a great page on Brunildo.org that you can use as a quick refference.
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!
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!
<div> <p>Ahhhh!! What a shrink!</p> </div>
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 <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 <div> is for containing floats and the display property toggle in two rulesets gives IE6 "layout" that it and IE7 need for containing floats.
display: inlineDespite 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:
width or heightpadding does not affect surrounding contentbackground 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.<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!
<div> <p>Ahhhh!! What a shrink!</p> </div>
div { padding: 10px; text-align: center; } p { display: inline; padding: 10px; background: #A5A5A5; border: 1px solid #000; }
Setting {display: inline} on our <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 <p> and its containing <div> are far less than 10 pixels; this is one of the draw-backs of this method that I've mentioned earlier.
display: inline-blockAside 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!
<div> <p>Ahhhh!! What a shrink!</p> </div>
p { border: 1px solid #000; background: #ddd; height: 100px; display: inline-block; /* gives "layout" to IE */ } p { display: inline; } /* IE6 and 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 <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 <p> simply to show that we still can set dimensions unlike the display: inline method.
What makes the <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 IE6 and IE7. To acheive the {display: inline-block;} behavior in IE6 and IE7 we need to give our <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 IE6 and IE7 targeted condcoms.
In my example I've put the fix in regular CSS code. First we set {display: inline-block;} on the <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 and IE6 will ignore that specially crafted selector because IE6 does not support child selector and IE7 has "Child Selector Comment Bug".
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 IE6 and IE7, if an element inside your shrinkwrapped element has "layout", the shrinkwrap will fail.
Ahhhh!! What a shrink!
<div> <p>Ahhhh!! What a shrink!</p> </div>
p { border: 1px solid #000; background: #ddd; position: absolute; top: 5px; left: 5px; }
The only thing that makes our <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 <div> is done to make top and left on our <p> to relate to our <div>. Most importantly, you can see that I've set height on our <div>; the reason for that is that {position: absolute;} takes the element out of the flow, without that height our <div> would have zero height because <p> is now out of normal flow and therefore does not give any "support" to <div>s height.
display: tableLastly, 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 IE6 and IE7. Let's have a look:
Ahhhh!! What a shrink!
<div> <p>Ahhhh!! What a shrink!</p> </div>
p { border: 1px solid #000; background: #ddd; display: table; margin: 5px auto; }
Aside from IE7 and IE6 support, we have quite sweet deal. Not only {display: table;} shrinkwraps our <p>, we do not need anything special on the container and check this out: left and right margins set to value auto center or <p> as if width was set on it!
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.
Mon Dec 26 04:22:30 2011
none of the sane options worked in Chrome...
Sat Jul 16 17:24:05 2011
You are the King! Thank you for your help on fixing page shifting!
Tue May 3 00:31:52 2011
Since this is one of the the first google hits for "css shrink wrap", I wanted to post on the best method I've found. By putting the target in a one-row one-cell table with no border, etc, I am able to center the table and everything in it, unlike shrinking with floats, and I don't have any of the negative side effects of display:inline.
It would go something like:
<style>
.tight{
border: 0px;
padding: 0px;
margin: 0px;
border-collapse: collapse;
}
</style>
...
<table class="tight" style="margin: auto;">
<tbody class="tight">
<tr class="tight">
<td class="tight">
<div> content... </div>
</td>
</tr>
</tbody>
</table>
The div is squeezed to fit the content by the table, and the table takes up no more space than the div. The table can be centered with margin:auto or moved anywhere else, and the well-behaved div will go with it.
Fri Dec 17 18:21:14 2010
Yes, I have, and in fact, spent quite a bit of time trying to find a solution to no avail.
Just a semi-relevant idea: try to set position: absolute; on the container and shrink wrap the inner element?
Fri Dec 17 12:08:09 2010
I came across your article while searching for solutions to a problem I have with IE7. It seems that an element that hasLayout and is position: absolute will have an auto-width of 100%. I can't seem to find a way to make it shrink to fit in IE 7, and its cramping my layout. Display: inline or inline-block does not work. Have you ever encountered this problem?
Tue Jul 27 17:08:27 2010
I type with a lisp :)
Tue Jul 27 16:49:29 2010
not sure where you get archeive as a word; achieve is what you are looking for
Wed May 26 02:39:35 2010
Thank you.
If you found materials on this site useful, please consider donating a few bucks to the author. Thank you.
Alternatively, purchase my books: