Editor’s note: Looking for a more modern way to get consistent bottom spacing between elements? Heydon Pickering’s “Lobotomized Owl” selector is a good way to do it while we wait for the margin-trim
property to gain support.
Ah the humble module! A good many designs these days make use of modules in the content-y and app-y sites alike. A chunk of information, an advertisement, a grouped set of functionality… could be anything. The fact that they likely have visual similarity yet can contain anything leads to an interesting CSS challenge: how do you pad the inside consistently?
Here’s a simple example where the module is set apart from the background through color differences:
html {
background: #333;
}
.module {
width: 20rem;
padding: 1.5rem;
margin: 1.5rem auto;
background: white;
}

But as soon as that module contains other elements, the padding can get “off”.
Module
Pellentesque habitant morbi tristique senectus…
The paragraph will very likely have some global typography rules applied to it which very likely have some bottom margin. Even if you go with opt-in typography, you’d probably opt-in here since there is type present.

See the heavy bottom padding? Perhaps that’s OK to you, but I’d suspect it’s not. That heaviness comes from the consistent set of padding you’ve set on the module itself plus the bottom margin on the paragraph.

So what do we do here? A wet band-aid would be to remove margins on those paragraphs.
.module p {
margin: 0;
}
But I’m sure we agree that’s pretty gross. What if a module contains two paragraphs? Now they butt up against each other awkwardly.
Perhaps just the last one?
.module p:last-child {
margin: 0;
}
That might work. But this fix is still feeling a little hacky. What if the problem element isn’t a paragraph at all someday? It could be an
-
- or
-
-
- . Or
-
- . Or any other HTML element… Are we going to list every single HTML element out?
.module p:last-child,
.module ul:last-child,
.module ol:last-child,
.module dl:last-child {
/* losing battle */
margin: 0;
}
That’s a losing battle for sure.
But we could match any element…
.module *:last-child {
margin: 0;
}
You could even omit the “*” there since it’s implied and has no specificity, but I think it makes it more clear. I think that’s closer to a good fix, but it’s a little heavy. Lists always have child elements that this would effect. Anything with decendants would be a problem. To fix that, we’ll just ensure only the top level element under the module gets this treatment with the child selector.
.module > *:last-child {
margin: 0;
}
That’s decent. I still wouldn’t call it perfect since descendants might actually be the cause of the final extra bottom padding. Like if the list items had paragraphs in them. You might want to chain them up a few times to match up to a reasonable level of DOM depth.
.module > *:last-child,
.module > *:last-child > *:last-child,
.module > *:last-child > *:last-child > *:last-child {
margin: 0;
}
That might just do it.
Here’s a visual demo:
See the Pen JFynD by Chris Coyier (@chriscoyier) on CodePen
A totally different approach might be to leave the bottom padding off the module and let the child elements provide it, but that feels a bit dangerous to me as there is no guarantee the child element would come with its own (e.g. some generic
).
Have you run into this? Do you have your own solution you like?
What I did was exactly up to the second to last block of code. Didn’t really think about chaining up the DOM a few times just to be safe. Either way, feels pretty good to see we have the same solution to this whole trailing margin malarkey.
I always hear about the poor performance of the * selector. So, isn’t chaining it a threat to performance?
Does someone know how much impact does it have on a real web page?
@Luca R.: I always use this method and I’ve never experienced any performance issues. But I guess it depends on the complexity of the project.
Luca – I think that the performance of the * selector is more talking when you apply it to EVERY element on a website, * {} like. And even then I’m pretty sure that it’s been covered here that it’s not an entirely too bad of a hit on performance.
Well, that’s good news. :)
I have definitely run into it, but used something like your first iterations of the fix only to find out later I was losing the battle. And that’s where I gave up.
Thanks a lot for shedding some light!
Hey Chris, what about the following?
http://codepen.io/catalinred/pen/yHsop
.module *:last-of-type {
margin: 0;
}
Looks like your losing the margin on the h3 then, which is likely to be the last of its type in a module but unlikely to be the last child.
Yep, I’ve seen that right just after I posted the reply. I was so close! :)
I would do this
.module *:last-child {
margin-bottom: 0;
}
Example added
Yes! I was just using this code to solve the bottom spacing issue and ran into other spacing issues with the removal of all margins.
margin-bottom: 0
is the way to go!The article doesn’t go this way because “it’s a little heavy”. Any way to optimize without chaining child selectors?
This is exactly what I have done in the past. I didn’t think of decendants, but then again the issue had never came up. It is a nice solution :)
I normally solve this in one of two ways:
1. Make the module have less padding at the top and bottom, which gets compensated by the content’s margins.
2. Set a 1px padding on the bottom of the container (in case the margin of the contents is the same as the padding of the container).
Number 2 is a bit ‘hacky’ and should only be used if you’re in full control of what goes into the container (and you’re sure the lay-out won’t change).
:last-child doesn’t go well with IE8 (although you might not be interested in fully supporting IE8).
Alternatively you can set all contents to have only top-margin, that way you can target :first-child, or use an OOCSS class structure (but that’s more mark-up).
Only top-margin isn’t completely nice either, normally you’d want either both top and bottom margins or at least the bottom one, but I guess it’s an option.
Something like this: http://jsfiddle.net/ReinierK/CwReR/
Only problem with #1 is if you have an element without a margin in the first place (like a div).
If your content is only wrapped in a
<
div>, then you have other problems with accessibility anyway.
I’ve always done the wet band-aid approach,
.module p:last-child { margin: 0; }
, and then just pay attention to if I add any nested elements later on and manage them then. Quite messy and inefficient. I’m interested in a better way too!What I usually do is add the margin on top of adjacent sibling elements, instead of on bottom of every element. I use something like:
p + p { margin-top: 1em; }
I adapt this depending on the content module. It works well, most of the time.
That’s a killer idea, I’ll have to remember that.
I used this method too. Works fine with paragraphs, but it’s hard (and verbose) to make it bulletproof for all the possible adjacent elements combinations.
I was going to suggest the exact same thing.
We use this technique at work. :)
The best approach, until now. :-)
Beat me to it!
I think it’s important to only null out the margin-bottom… there might be an important layout piece within the module disrupted by killing it’s top, left and right margins when all we’re really going for is the bottom spacing. But excellent technique!
Hey Chris,
Just curious about your use of the universal selector – does it do anything in the example? Does it help or hurt performance? What about removing it: http://codepen.io/mikevoermans/pen/ILida
Just curious your thoughts.
Another solution is to use additional classes:
// removing margins for first/last elements
.first { margin-top: 0 !important; margin-left: 0 !important; }
.last { margin-bottom: 0 !important; margin-right: 0 !important; }
I use them when I know that added :last-child is overkill, e.g. because a case is special and the rule would match one element on the entire site.
Yeah, this is exactly what I was thinking. It’s better to rely on classes than it is on advanced selectors, even if it’s clunkier, although, in this case, I would argue this is a bit more elegant.
Well, I say “it’s better.” I mean I FEEL it’s better to rely on classes vs. advanced selectors. I think advanced selectors work better in an atmosphere where you are in control over the content, i.e. a personal website.
Not really. If the module content comes from a CMS how will you add the first and last classes?
You will need to insert it via backend or javascript.
The advanced selectors will work fine if the content comes from a CMS.
I hate when I get a redesign project and I need to keep the previous html but it is full of extra classes, like “clearfix” everywhere.
The HTML have to be simple enough to CSS be replaced anytime. Using too much extra classes is not a good idea.
At least, in that case, the first and last classes will do nothing if i replaced the CSS.
Why not use a negative margin on the bottom of .module?
You tried this?
The problem is not with the module margin, but with the module padding.
I think this should work at the expense of an :after pseudo-element (which may or may not already be accounted for in your real world markup).
here’s a link to your modified codepen with the solution in place. Haven’t tested across all browsers yet. The top margin needs to be greater than any bottom margin on a contained element and will force a column-collapse with the last element so that you have a consistent amount of extra space at the bottom of each module. The bottom negative margin just compensates for that collapsed margin by swallowing it up. I usually look to negative margins for tricks like this.
I really really like this solution. As fsr as I can understand it without testing it (I’m on a phone), it accommodates the bottom margin of any last element (even grandchildren) then swallows that margin up again with its own negative margin, right? Brilliant; I’m looking forward to trying it. Box formatting contexts are a thorn in my side, and I always felt uncomfortable relying on styling the last direct descendant — o4 a chain of last d3scendants of last descendants of last descendants. It always seemed too brittle and reliant on predictable markup. This one Just Works — unless one of the descendants creates its own block formatting context and prevents margin collaps3
I really like this solution solely because of the use of :after pseudo selector. I suppose this would work with IE 8 and up.
Why not add top padding to every second element? Something like
.module > * ~ * {padding-top:1em} // every child after the first element
That way, you separate stuff, and no bottom padding?
I use
.module > :last-child { margin-bottom: 0; }
+ a generic helper class.vertical-rhythm--none { margin-bottom: 0; }
for nested or oddball cases. I only apply vertical margins in one-direction (down).I think this is the best solution so far.
I’m a huge fan of single direction margins, it makes everything amazingly predictable! I heard it first from CSS Wizardry.
I’ve been using the following code in Cascade Framework to deal with the extra padding across the site’s grid structure :
.cell>:last-child {
margin-bottom: 0;
}
I chose to use
margin-bottom : 0
instead ofmargin: 0
because the selector is too generic to throw in a reset for top, left and right margins as well.I went only one level down for the same reason. I may want a bottom margin for the element’s children or its children. With such a generic use case, there’s no way of knowing. And if you really do need a margin reset for children’s children and so forth, it seems better to me to just use class based selectors to adjust them.
I tend to do it once for all block elements at the base typography level rather than at the module level, eg (Sass)
p
margin-bottom: 2em
&:last-child
margin-bottom: 0
Cases where I actually want a
p
,ul
orol
that is a:last-child
to have that bottom margin are few & far between, so it’s easy & sensible to override those edge cases at the module level.oops formatting died there, but you get the picture :)
true vertical centering often “looks” wrong. that’s why in print you’ll often see if weighted to the top somewhat. to my eyes, your “heavy bottom padding” looks better than no padding at all.
Wow, much tidier approach than my methods… will be using this from now on. Thanks!
If only this could be checked with logic in the CSS itself, like a media query.
I usually add top margin/padding instead:
.module p {
margin: 20px 0 0;
}
Here is example.
Or some simple math:
$mod-bottom-padding: 1.5rem;
$mod-element-bottom-margin: 1rem;
.module {
padding-bottom: $mod-bottom-padding - $mod-element-bottom-margin;
}
Ok if your module elements all have the same bottom margin.
What about using collapsing margins and pseudo elements. See
http://codepen.io/getdave/details/gfEiq
We create a psuedo element, apply top margin which then “collapses” into the bottom margin of the last element. Works best if the module padding is based on the base line height/margin.
Wow this is smart! Seems pretty fool proof as it’s relying on the logic of margin collapses rather than double guessing with CSS selectors. Are there any cases where it doesn’t work?
This is brilliant! Do you need the height 1px? Won’t the margin still appear if it’s display: block even if there is no height?
IMHO, the only predictable, sustainable solution is for the markup to be more descriptive. By specializing the module classname, you can address your design need in a straightforward, idiomatic (and performant) way. Demo pen.
(There are other ways to enrich the markup. You can leave the module generic, but wrap the contents in an element that has a specializing classname. E.g. essentially
<module><module-titled-list><h3/><ul/></module-titled-list></module>
or<module><module-list><ul/></module-list></module>
.)The argument that modules should be mindless generic zombies is an interesting but artificial hypothetical. Whatever CMS or app is rendering this module can be augmented to specify type at the time of content entry. If you cannot modify the app or whatever is rendering the structure, then you have a much bigger problem confronting your design.
Thanks for the interesting post.
Gotta admit I usually go the losing battle route. However, I’ve decided after reading this that my css needs to be a bit more generic. Thanks for the interesting read.
I suggest just using top margin for general spacing, as when planning a specific page you most of the time know what content you’ll have at the beginning of the page. You usually don’t know how a page will end – will there be a paging component, action buttons, author information or whatever (depending on the dynamics of specific template). This way you can arrange the whole page as a train set – locomotive is the first one with no damper and each following coach has its own spacer designed just for this specific item. First item of the page is 99% time the same, a heading or breadcrumb so you basically just have to deal with this. If you have to focus just on one side spacer then it’s more easier to follow general design grid/spacing.
I’ve been using just top margin for spacing for years and have never had any problems with this approach. So just to throw a special in – IE7 supports first-child: (so you can use it) and doesn’t support last-child:
I set all my top margins to 0 and only use bottom margin ala vertical rythum. I would set the bottom padding of the module to 0 as any contained element will have bottom margin.
Used this technique for years and never had a problem with heavy padding.
I have always just left the bottom padding off the module.
Most items of content need bottom padding/margin and if you use layout divs with this in mind you just give them some bottom love too. Also you are almost never going to end a module with an H3 etc..
I deal with this using sass by keeping it abstract so I can reuse it for every module that needs it:
%last-child { & > :last-child { margin-bottom: 0; } }
So when a module needs to remove the margin-bottom of his last child element:
.module { @extend %last-child; }
If the
.module
will always contain an element that has amargin-bottom
, and its margin is equal to or greater than the internalpadding
, then instead of resetting themargin-bottom
on all of the “last” elements, set the.module
‘spadding-bottom
to1px
.Throwing semantics out of the window, I’ll often use some helpers:
.remove-margin-bottom {
margin-bottom: 0 !important;
}
And in other cases:
.give-margin-bottom {
margin-bottom: $spacing-variable !important;
}
Might sound horrid, but there are too many times when I find myself giving an element a class just to take or give a bottom margin away. Feel free to hate. ;)
By the way, it could be useful to have some kind of recursive selectors. For example:
:last-child-recursive {margin-bottom: 0; }
would automatically zero bottom margin for last child, last child of this last child, and so on for all nested last children — regardless of actual nesting level.
There is a message in www-style mailing-list about this idea.
What happens when a designer comes along and wants a header with a background color or image to start on the edge of the module? Now you have to use a negative offset, which I suppose is OK for just one element…
Leaving this here:
Clever in that it uses margin collapsing to fix the issue. Would work great if the margin/padding was equal in most cases and the children weren’t floated/inline-block.
I would go for an extra class since it’s clearly states my intention of removing the padding for this element. Using something like _spaces.sass and removing all marigns and paddings from any core modules styles. Then you would have a spacing component with reusable margin/padding classes like .l-pbn (padding bottom none) or .l-mls (margin left small), etc..
{ margin-top: 10px; }
Would give every child element a margin on the top except the first element, which also solves the issue. Another solution could be to use an element with a margin in stead of a padding and to utilise collapsing margins.
Chris dont use
.module > *:last-child{
//
}
use
.module > :last-child{
//
}
its faster and cleaner
Such a dumb little issue that I find myself thinking about a lot. Thanks for the round-up Chris! I’m usually building for IE8 support so I tend to use margin-top on most things and first-child to zero it out when I need.
I’ve definitely run in to this. Great solutions!
.module *:nth-last-child(1) { margin-bottom: 0; }
Ooops, that does the same thing as
:last-child
. Nevermind.nth-child is not IE8 friendly
It would be better to use !important rule.
See http://jsfiddle.net/guimihanui/9hCdC/
No.
This type of code may look very basic but it’s a great code to use and has lots of applications. Thanks for posting this.
Why not leave it at .module :last-child ?
specified rules will most likely override this one.. example: .module ul li { padding: 10px}
also I tend to use the method Sugareina mentioned, figuring that the adjacent sibling selector is far more backward compatible than :last-child.
MHO
Sometimes I use the :not selector like this :
.my-spacing-element:not(:last-child) { margin-bottom: 15px; }
You could also do something like this:
.container { padding: 5px 20px 20px; }
.container > h1 { margin-top: 15px; }
.container > p { margin-top: 10px; }
.container > [any other element you might need] {margin-top: [something]px; }
Assuming the container always starts with a h1 this gives us a nice spacing of 20px on every side inside the container while having a space of 10px before each p (15px before each h1 except of the first one which makes sense because of the consistent container spacing) and you don’t have to style the first or last element in the container any different from the others.
It’s sufficient for most situations I find myself in. Then again, I don’t usually develop websites where a single container must be adaptable to every single effin type of element the client wants to shove into at the start of the container. :D
.module > * {margin:1em;}
Provides a nicely spaced grid for all children. Margin can be retracted from individual elements if needed. Been using this for the past 5 years or so, the only tricky part is when .module doesn’t have any borders and margins may start collapsing. A clearfix or overflow:hidden can fix that, but that’s still a bit hacky.
Using some pseudo elements, you could create a reliable solution without modifying any children elements. Take a look.
Above: Self-contained sexiness
Here’s that codepen again: http://codepen.io/thejameskyle/pen/pthGd (be sure to checkout the mixin I created in there too!)
I’d just omit the bottom spacing of the container. That’s the most straight-forward way for me, since I would be very uncomfortable to use something containing the * selector. Moreover :last-child isn’t supported in IE8 – which becomes more and more unimportant these days, but it’s a disadvantage you shouldn’t forget about.
Hi Chris, nice technique !
I have modified it a bit to include
first-child
, like this :.module > *:first-child,
.module > *:first-child > *:first-child,
.module > *:first-child > *:first-child > *:first-child {
margin-top: 0;
}
.module > *:last-child,
.module > *:last-child > *:last-child,
.module > *:last-child > *:last-child > *:last-child {
margin-bottom: 0;
}
The only issue I see with this is the fact that it’s not fully IE8 compatible.
I have a different solution that does not require the removal of excess glue.
Excess glue??
Let me explain: When you use bottom margins, the last element is always left with a margin that does not separate it from anything. In the solution offered this margin always gets put on and then has to be taken away again, like excess glue.
The code I use for “modules” uses top margin instead, but only on elements that follow other elements.
.module * + * { margin-top: 1.5em }
This reads as “any element preceded by any element should be separated with a top margin”. Glue is only applied when it’s needed.
This works at an infinite number of nesting levels because, although each nested element receives the top margin, no first child does: No doubled up margins to worry about or have to anticipate.
Since
:first-child
has deeper legacy IE support, I got in the habit a long time ago to only apply margins and padding to the tops of elements and remove them from first children. http://stackoverflow.com/questions/7938521/browser-support-for-css-first-child-and-last-childHere’s another semi- to sub-optimal solution to add to the mix. It adds no new elements:
The upside is that this tackles any level of nesting, even if descendants prevent their own descendants’ margin collapsing (floated children, children with
overflow: hidden
, children with padding or border, etc).The downside is that it expects all your children to have the same size of margins (in this case, 1em).