What is the internet made of? At least the UI layer is mainly composed of media blocks. I talked about the Facebook stream story before, and all the tiny objects of which it is composed. For the most part, the stream story is made up of the media object repeated over and over.
The media object is an image to the left, with descriptive content to the right, like this Facebook story:
The content area on the right can contain any other objects. In this case, it contains text, but we could put lists, grids, or even other media objects inside. As we’ve seen before, there are actually many different versions of the media block on the Facebook website (and on most websites). These five are just a few examples of the way this object might be used:
Sometimes the image is a tiny icon, a large video, or an avatar, but it is the same basic object. When I’m building a new object, the first thing I do is to figure out which parts are reusable components, and define what I know and do not know about them.
what do we know?
- Can be nested
- Optional right button
- Must clearfix
What have we decided *not* to know? (Think flexibility!)
It is equally important to define what is flexible, or unknown, about a new object.
- Image width, margins, and decoration vary
- Right content is unknown
- Width unknown
Once it is built, we can use it to create many of the same basic object. In the following image, I’ve highlighted all the media objects on the facebook homepage. You can see that even implementing this one object can save a ton of code because we stop repeating ourselves.
Implementation Details
How does it work? The hard part is making sure that the image can be any width, so that the element is reusable. It means our content area needs to be flexible so that it can fill in all the remaining space available. We’ll have to create a new formatting context to make a flexible column.
The HTML:
<div class="media attribution">
<a href="http://twitter.com/stubbornella" class="img"> <img src="http://stubbornella.com/profile_image.jpg" alt="me" /> </a>
<div class="bd"> @Stubbornella 14 minutes ago </div>
</div>
The CSS:
/* ====== media ====== */ .media {margin:10px;} .media, .bd {overflow:hidden; _overflow:visible; zoom:1;} .media .img {float:left; margin-right: 10px;} .media .img img{display:block;} .media .imgExt{float:right; margin-left: 10px;}
- We clearfix both the wrapper element, media, and the inner content wrapper, bd (body) using the secret benefits of overflow. There are other ways we could have implemented the clearfix plus new formatting context. More on that in a later post.
- Then we float our image wrapper (generally a link) left and our optional right region to the right.
- Finally, we set some margins and paddings to keep everything lining up nicely. You might choose to set margins via a class which extends the .img object if you have several different kinds of images with different spacing and decoration.
Voila, we’re done. It is a very simple object, but it is very powerful. We can eliminate a lot of lines of code abstracting this repeating pattern. The code for the media block and many other “web Lego” are available on the Object Oriented CSS open source project.
Comments
24 responses to “The media object saves hundreds of lines of code”
Really enjoyed your talk at Velocity.
Imo, you’re the CSS visionair and I hope you keep posting these useful articles.
[…] Sullivan explains how the media object saves 100s of lines of code in CSS – with object she means a reusable page […]
[…] The media object saves hundreds of lines of code […]
Hi Nicole,
I see you mention that this is a repeating, and possible nestable pattern, as the Facebook screenshot shows by highlighting them in pink.
Now, some rhetorical questions:
1) How do you nest this pattern? I suppose you embed another “.media” object inside the “.bd” of its “.media” parent and so on, for each new nested “.media” object. Correct?
2) Nesting objects of equal type will probably lead to some level of class-itis, when the need to style the nested objects in an slightly different way arises, as you will need to somehow isolate (probably thru the use of “.objectExt” classes), the nested/child objects.
How do you overcome this?
3) More an OOCSS question now: similarly to previous point, I understand that OOCSS objects (“.mod” class applied) are nestable. Correct?
If so, which is the “point of insertion” of a nested “.mod”. Is it mandatory to be nested inside “.bd” of its parent “.mod”? Or could it be nested inside “.hd” and “.ft” (may not make sense).
4) Back to “.media”: assuming that “yes, OOCSS objects are nestable”, then..
Wouldn’t “.media” object benefits of just being similar in structure to “.mod” object? That means: having mandatory “.inner” and “.bd” blocks, and some optional “.hd” and “.ft”?.
By looking at the OOCSS UML [1], I would answer: “no, ‘.media’ is a ‘content block’, not just a [container?] ‘block’…”
Of course, this “lets make everything an extension/variation of .mod” may add some unnecessary overhead.
On the other hand, if a class convention like “.bd” is used for classing both a mandatory block inside a “.mod” object and a mandatory block inside the “.media” object, being that a “.media” object is necessarely (?) nested inside a “.mod” object (.mod > .inner > .bd > .media), things start to become a little more complicated… particularly when it comes the time to style stuff.
Of course, (over)using the > child selector may be everything you need to overcome any inheriting issue… if only IE6 would support it. But let’s disregard IE6 for now…
Brain overheating and already melting here… what about there?
I may be leaving open more doubts that certainties with this comment, sorry 🙂
[1] http://www.flickr.com/photos/nicole_hugo/3296789176/sizes/o/
Now, it’s rant time 🙂
The last hours, I’ve been reading about the OOCSS project and the concepts/ideas behind it, and studying the bits of current implementation/code (yours), while discussing the concepts with a teammate
.
I like some of those concepts/ideas behind OOCSS, and I find that after a few years of doing front-end development (enjoying and struggling in equal parts), and I’ve “naturally” developed a similar approach, although less documented ;).
It’s good to see that you documented those concepts, helping newcomers to learn the “correct way”, while avoiding bad habits and unnecessary/difficult un-learning of bad habits.
On the other hand, I disagree with some strong advocacy about avoiding applying styles directly to #IDs selectors, or avoiding location-dependent styles. I think both technic still have place if applied wisely, which would mean that someone with a good knowledge/thinking of CSS engineering should be in charge of CSS maintenance. The CSS shouldn’t be a sacred, untouchable file.
Of course, it always seems to be a matter of trade-offs. You probably said it already: OOCSS may be a better approach for large sites that evolves continuously, adding new “objects” frequently
As my teammate said: “It also makes a mockery of the long-cherished notion that you can fully separate content from style – remember the idea that you could even redesign a site without touching the HTML (!). Sullivan seems to almost advocate the opposite – saying you should never need to change the CSS to simply extend the site content, ”
Now, what I dislike about OOCSS, (after a first quick glance, I must confess) is its current implementation.
I’ve looked at the files (libraries.css, template.css, grid.css, mod.css, etc, etc, etc), and, sorry to say it this way, it looks just ugly, an overbloated gibberish, to say the least. It seems (superficially, at least) that it doesn’t leave up to the OOCSS ideas…
I know I should be more specific in my criticism, instead of just vomiting the above statements about ugliness.
A great developer taught me once: “Not writing code can be very productive, if it’s the right code.”
Similarly, I think that the concepts/ideas/teachings of OOCSS should have remained in that conceptual state, and not on a particular utopian implementation. Of course, OOCSS code is currently a great example of a lot of do’s (and some don’ts too).
That being said, I will try to contribute some ideas, and stop my harshness complains full of emptiness:
* I think OOCSS project (both the conceptual documentation and the implemented code) will benefit if following some HTML5-like class conventions, particularly for the “mod.css” module. IMO, following some HTML5-like class conventions will make it easier to grasp OOCSS concepts, with the added benefit of learning some HTML5 in the process, and better yet, of writing (x)HTML that looks like HTML5, making the code more future-proof, easily-upgradable, for when the HTML5 era finally arrives.
Not sure exactly which OOCSS conventions will match each HTML5 elements, but maybe:
.mod = section
.hd = header
.ft = footer
.bd = ? (article? section?)
.media = figure
.media .bd = figcaption
* What about just reducing the number of files on OOCSS?
I think a basic grid.css (1kbgrid), a basic reset,css (sen css) and a very basic mod.css, without any IE hack nor any presentational “freebie” included will serve better the purposes of spreading the benefits of OOCSS.
Apologizes for the somewhat harshness complaints. English is not my native language, and sometimes I may sound more rough than I would like to.
My less than 2 cents.
@Julián Wow, that is a looong comment. Not sure I have time to address all of your points, but I’ll hit a few.
1. Yes, nest
2. Not really, as long as you always apply the class to the object you are trying to extend (for example, if you are modifying only the image, apply the class to the image)
3. I try to leave things as open as possible, hd, bd, and foot are all content areas, I let the visual design dictate what should be nested or not.
4. Good point, media is a weird block and I go back and forth about whether it is content or container. I guess it is both, but I lean toward content, which is why I allowed a simplified structure, trying to keep it as lean as possible since it repeats everywhere.
Yes, nesting will be easier when we have consistent support for the “>” selector, or if you decide to feed a simplified design to IE. Until then, nesting is unnecessarily complicated.
Check out my detailed stuff about modularity/encapsulation. You’ll see that I don’t make “rules” but guidelines. There is a time and place to break every rule. 🙂 Location dependent styles make sense when a node belongs to a more complex multinode object. I also use IDs to sandbox styles that don’t fit with site legos, like page header or footer styles. I just don’t use IDs to change the default behavior of the little objects that make up the site.
Re: tradeoffs, YES! Exactly, that is what being an architect is all about. Choosing wisely in the face of inevitable tradeoffs between good and competing goals. However, OOCSS is good even for small blogs. I’ve recently been converting my own site (ever so slowly) and it has gotten so much easier to write articles now that I’m starting to have basic objects available to me. OOCSS benefits big sites and CMS based sites more, but it is useful even on tiny sites.
Now, I disagree with your teammate’s assessment. I’m using classes to describe the visual semantics of the site, not the specific presentation. Most of the classes define the structure of the page, only a scant few in the chrome layer are purely about colors and backgrounds (and even then, I never tie them to the particular look and feel currently used. This means they are free to evolve as the site design changes.
re: HTML5, the new elements (header, footer, figure) are far from being the most interesting part of HTML5, they offer no advantage over the current implementation, and in fact require JavaScript to display properly in older browsers. Yuck! (bad for performance)
OOCSS is an open source project, the goal being to provide a practical example of one way these principals might be implemented. You can fork the project and even contribute back changes. If you think things should be different, by all means, make it so! 🙂
The project is broken into multiple files so that no one needs to take more code than they are actually using. You should combine the files as a part of your build process in the way that makes sense for your project.
Ok, I think I actually did address all of your comments!
@Nicole, thank you very much for your thorough reply to my comments.
You have address most of my concerns.
I think the OOCSS concepts, and probably some parts of your implementation, will grow on me as I use them on upcoming projects, while also revising what I did in old projects.
Re: HTML5. I wasn’t suggesting to change OOCSS “classed” elements to HTML5 real elements, but to change the class names to match HTML5 elements: “.section” instead of “.mod”, “.header” instead of “.hd”, “.figure” instead of “.media”. “.figcaption” instead of “.media .bd”, and so on.
I’ll stay tunned to the OOCSS project and follow its evolution. Will try to collaborate, if not by forking and real coding, at least with feedback and comments (hopefully not ranting). 🙂
Hello.
I’m a big fan of your OOCSS project and thanks for this great article.
I just have one question, it’s a stupid one I guess.
On your media module, you’ve wrote:
.media .img {float:left; margin-right: 10px;}
I’ve learned that float should always have width and this doesn’t
But this seems work as expected.
I thought
.media .img img{display:block;}
This does the trick, but I couldn’t figure it out.
I just wonder why this work…
@Yuya It doesn’t need a width because it contains an image which has fixed dimensions.
Hi Nicole.
Thanks for replaying!
and oh!
I always thought that that apply only on image not the container.
Hi, Nicole,
I’m using this pattern in a project and instead of using .img class, I use :first-child. See, you apply this .img class only to the first child of .media. If it has no other use, I think it’s better to use :first-child and forget about writing another class in your html:
.media > :first-child { float:left; margin-right:10px; }
.media > :first-child img { display:block; }
Must thank your for standing up and saying this speech out loudly (I mean both, literally the speech and figuratively the OOCSS project). It has let me, a programmer, catch up with CSS again, be able to handle it with a little effort, which was unthinkable for a few years.
@Dmitri – I’m glad I helped you catch up on CSS. I can’t use first-child because support for it is pretty poor in IE. I would use pseudo classes for table decoration an other purely presentational aspects, but for something essential like this, the fallback isn’t reasonable. Support for the child-node selector, “>” is also not great. I can’t wait until older browsers get retired, for now, I’m using this selector for decoration only.
Hi Nicole,
I was revisiting a couple of your (fantastic) posts and I think there’s a typo in the code above:
/* Instead of this: */
.media, .bd {overflow:hidden;…
/* I believe it should be: */
.media, .media .bd {overflow:hidden;…
Otherwise you’re polluting .bd, which is used in other objects…
(just an FYI, no need to post this comment!)
Mike
@Mike Hairston – good point. Actually, the .bd already has the clearfix applied in the .mod code. I just repeated it here for clarity.
Wow. This is great. I’m in process of turning all my components that have this layout into media objects.
Nicole, when the text in the body gets too long, it will wrap below the image. Shouldn’t the .bd element be floated or get a margin to prevent this?
@Ron Derksen – it gets a new formatting context via mod.css. http://github.com/stubbornella/oocss/blob/master/core/module/mod.css#L10-11
This is the key to it not needing a ton of extra classes for different sized images. I haven’t written about this method of creating a new formatting context (yet!), but you can check out the overflow method in this post: http://www.stubbornella.org/content/2009/07/23/overflow-a-secret-benefit/
Nicole, what is the benefit of applying the margin and float to the wrapper, instead of simply the image itself?
I tried doing so, and noticed no difference in the layout in any browser.
.media .img {float:left; margin-right: 10px;}
.media .img img{display:block;}
@Patrick – I don’t know if there will be an image inside. It could be a sprite which just has a background image on a link or span. So I apply the float and margin to the piece that is always there.
Nicole,
It seems to make more sense to me that the img class is put on the image instead of on the link. It seems more reusable that way because all my images will be images but they won’t all be anchor links.
I’ve messed with it both ways and it seems to work my way just fine but I’m wondering if there is a downside to doing it this way. I will now defer to the master…
Thanks,
Kiko
[…] frequently on the Facebook site is something she has coined a “Media Block,” which she defines as “an image to the left, with descriptive content to the right.” Simply put, this is […]
Necolas made a nice demo of this technique I wanted to keep a reference to: http://jsfiddle.net/necolas/rZvEF/
Hi Nicole,
Fwiw, I’d not use the term “clearfix” to describe the styling of these elements. I think for most people “clearfix” is a method that clears floats via hasLayout in IE and via a pseudo-selector in modern browsers.
But such styling does *not* create a block formatting context across the board (only in IE lt 8 ) which is very different than what you do here – where the styling is the same across browsers.