Our Phil (finish your site mate!) asked me to pop this up here, it’s a neat little CSS positioning technique I use all the time. It’s not particularly difficult, nor is it massively new and revolutionary, but I see a lot of people achieving similar results in spectacularly longwinded ways.
There are a loads of instances where this little technique could be employed, but I've used a list as an example because it's one of the most common. Here we have a basic unordered list (<ul>), with floated-left images where the text doesn't wrap under the images. Told you it was simple.
Ignore the extraneous styling I've used in this example (I can't help it!), I'll be dealing with just the layout of the list in the CSS. Also the example images aren't accurate in terms of dimensions, they're shown here merely to assist.
Now I've seen loads of people use two divisions in this situation, one for the image and one containing everything else, floated left and right respectively. It's really not necessary and can be a pain in the arse dealing with all those pesky floats. The HTML for this method is as follows:
<ul>
<li>
<img src="image1.jpg" alt="" />
<h3>A heading</h3>
<p>A nice little paragraph, Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
</li>
<li>
<img src="image2.jpg" alt="" />
<h3>Another heading</h3>
<p>A nice little paragraph, Lorem ipsum dolor sit amet.</p>
</li>
<li>
<img src="image3.jpg" alt="" />
<h3>Final heading</h3>
<p>A nice little paragraph, Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque congue ante et sem. Cras consequat magna nec elit. Maecenas imperdiet augue nec libero mattis faucibus.</p>
</li>
</ul>
Well simple. Next, we'll use some classic CSS that I'm sure you all use everyday (as I mentioned earlier, I'm ignoring all the extraneous styling that would have to happen to realise the examples; the green, the type, spacing, etc):
ul li { padding-left:70px; overflow:hidden; }
ul li img { float:left; }
This will leave you with a nice floated image and some padding where the image will sit. The overflow: hidden; clears the contents of the list-item, meaning you don't have to worry about clearing floats.
Next we need to get that image where it belongs:
ul li img { float:left; position:relative; left:-70px; }
This will give us something like this. Because we're using position: relative;, the image is still in it's place in the flow of the HTML document, hence the gap, but our positioning has simply pulled it over to the left.
Now to closed up that gap:
ul li img { float:left; position:relative; left:-70px; margin-right:-60px; }
Job done. I know that this can be done using absolute positioning on the image, and min-height on the list-item (to make sure the list-item doesn't cut off the bottom off the absolutely positioned image), but this method caters for images of varying heights, and plays nicer with IE6.
Apologies if this insulted everyone's intelligence; blame the Swan.
Posted at 6:54pm on 08/09/08 - Categorised in Websites
Great tip, Greg! I’m one of the people you mentioned, achieving that result with extraneous and unnecessary markup.
I’ll give this technique a try next time.
Great tip, nice to see you did your homework.
Nice one! I would have naturally gone for positioning the image absolutely but I shall give this one a go and add it to my utility belt : )
Maybe overflow:auto? ;)
It is also worthwhile to point out that before and for the img tag was not white spaces.
In the past I’ve used position:absolute and min-height/height to get the same effect. Might consider this one in the future.
Nice write up anyways, hadn’t thought about it before.
Nice trick!
I used to use this one:
li{overflow:hidden}
li img{float:left;margin-right:10px}
li p{display:table;}
To simulate display:table behaviour for IE, you may use zoom:1;
Thanks for your comments chaps, glad to see you find it useful.
@Cezary Tomczyk, what do you mean mate? I don’t understand.
I mean, to build the code was possible without the use in sensitive places without white spaces. For example:
<ul>
<li><img../></li>
<li><img../></li>
</ul>
instead of
<ul>
<li>
<img../>
</li>
<li>
<img../>
</li>
</ul>
@Cezary ah I see. Yeah I know but it’s easier to read with tabbed indents mate, and it really doesn’t matter in the slightest. Thanks for your constructive feedback.
Sweet, wouldn’t have thought to use negative margins for that. Definitely saving this for reference.
Also, loving the use of horizontal rules for structure in the article.
That’s awesome, thanks!
It’s great because the text will still sit in the same place if there is no image, and semantically I can have the image and text in the one container instead of having two floated next to each other.
Good one!
In IE6 the headline does not align with the image.
Same happens with the html for this comment item!
Any solution to this?
@SIMON Try to add display:block for img and then margin:0 auto; for centering or try display:inline; text-align:…
@Simon, you may have noticed that IE6 support for this site (and subsequently the comments) is non-existent. The same goes for this tutorial I’m afraid, and although this technique ‘plays nicely’ with IE6 I never thought it would be perfect.
Off the top of the head, the problem looks margin/padding related, let me know how you get on.
@Cezary Tomczyk
I cant make it work. Can you explain better?
I can only make it work in IE6 with the min-height on the list item.
@simon: try
li{width:100%}
It is an equivalent of the overflow:hidden technique used for IE to clear floats.
Also you may try my method described in 7th comment, it is a bit simpler. Though that doesn’t mean it is better. We should know all of them to use at appropriate times.
@simon: sometimes try do add zoom:1; or position:relative; for <li> or <ul>.
A good tip, the example is very nicely styled might I add.
Another simple way to do it is adding padding-left on the li, and absolutely positioning the img. It’s actually very slightly less of a CSS footprint.
Unfortunately though, both methods require us to know the dimensions of said image beforehand.
If you don’t know the dimensions, an extra div wrapped around the h3 and p will do the trick, floating the img and the div left. Personally I’d prefer to order the content h3, p, then img, and float the div and img right.
@spencer, I mentioned the absolute-positioning way in the article; the relative-positioning method is better because the list item will display properly if the image is greater in height than the rest of the content. When you position the image absolutely, you take the image out of the normal flow of the document, so things could get messy when if you don’t know the heights of your images.
As a result and contrary to your second point, we don’t need to know the dimensions of the image.
Regarding your third point, this whole article was written to avoid this scenario.
Thanks for your comment.
Awesome, will definitely come in handy. Cheers!
I wanted to research this subject and write a paper. Your post what a thousand words would not. Nice job.
@Greg, cheers for the reply. I hadn’t at all considered the height of the images in the whole scenario, in that instance your technique is definitely superior.
Don’t you find that it’s a bizarre scenario these days where we’re using a lot (comparatively) of extra CSS in order to escape using an extraneous div, but I do acknowledge that it exists under the guise of semantics. I’m looking forward to there being a standards body/ruleset for semantics one day, but until then I’ll always opt for interoperability (extraneous at times) over semantics.
Why not just use a margin?
li {
overflow: hidden;
}
* html li {
zoom: 1; /* li needs layout for ie6 and ie 5.5 */
}
img {
float: left;
margin-right: 10px;
}
li h3,
li p {
margin-left: 100px;
}
Tested in FF3, IE5.5, IE 6, IE 7, IE 8b2, Safari 3 and Chrome.
Hi Nataliemac, if you read the article you’ll understand what problem this little technique is solving. Your solution does not result in the same behaviour.
Thanks for your comment.
Here is my solution which is more elegant in realization and takes 2 lines less. What would you say?
ul li img {
float: left;
margin-left: -70px;
}
Fair point Shur, and although I would never call CSS “elegant”, you’re right. One thing I would say though, is that using relative-positioning gives you a little more flexibility and consistency regarding the positioning of the image. Thanks for your input.
I *did* read the article. Unless I’m missing something, the point was to “have a basic unordered list (ul), with floated-left images where the text doesn’t wrap under the images.”
That’s exactly what my code sample does, without requiring absolute positioning or min-heights. How is the behavior different?
Hi Natalie, I must have misread your initial comment - apologies for that. The point of the article was more to show a basic example of how to use relative-positioning and negative margins creatively, the list was merely a way of showing this. I think relative positioning is really underused, underrated and often misunderstood, and I wanted to illuminate it a little using a simple example.
Regarding your method of achieving the result shown in the example, I still think mine is simpler. What if you had a load more HTML elements in your list-item? You’d have to apply the left-margin to everything in there, and there will be instances with CMSs where you won’t know what HTML will be within the list item. Using the relative-positioning technique, the left-padding on the list-item solves this problem.
Greg, thanks for the quick ‘101’ on positioning! I’m still attempting to get my head around the whole CSS document flow and how positioning affects it, and this article was the penny that dropped!
As a side note: it’s nice to see an author who actually read and replies to an article!
Cheers, Chris
Chris, flattering comment mate, cheers. I know what you mean when you say it took a while to “get” CSS positioning, but now that you do you’ll find yourself hardpushed to stop using it, trust me!
Good article.
Copyright © Greg Wood mail@greg-wood.co.uk http://www.greg-wood.co.uk 2008 | Everything here protected and licensed using a Creative commons license | Get some RSS