Padding outside the Box
There’s always been something rather, well, disconcerting to me about the CSS Box Model. I could understand it well enough for most things, but every time I started to do something more complicated it never came out the way I wanted without a lot of tweaking. Something always seemed wrong with my understanding of it.
Today I have figured out what that is. Observe:
The width and height of the inner green box are both set to be 100%. Yet the green box is larger than the blue box. Why is that?
It’s because I set padding: 1em;. That’s right. The padding is added to the width and height of the box. I thought to myself, “Surely this must be a bug in Safari.” So I tested in Camino and got the same results. “Fine,” I thought, “Let’s go look at the specifications and see where I went wrong.”
Reading it shocked me. width and height do indeed specify only the innermost part of the box. This means that if I want a green box inside my blue box with padding, I have to subtract and do the math to make sure it fits correctly. Even more importantly, this means I cannot mix px with em with % units!
Say I want the above blue box to be 100px by 100px, and the green box inside of it should fit it precisely but the text should be offset by a padding of 0.5em. I can’t really do that with CSS.
I expected that width and height acted on the padding edge or even the border edge—I certainly didn’t expect it to be working on the content edge! How is that even useful? Padding is something which should be inside the area I’ve specified, a sort of inner offset. Instead it’s simply sizing that’s added outside the content specified by inside the border. This is precisely not how InDesign and other page layout applications work. What the heck?
IE used to (and still does in quirks mode) implement a box model how you would prefer it, although IE6 in standards mode uses the W3C model. There is a proposed property for CSS3 called box-sizing (implemented in Gecko as -moz-boz-sizing) that allows you to choose between the current W3C model (content-box) and the “more sane” model (border-box). However, it may get removed now that IE supports the W3C box model.
This has always annoyed me a bit. IE has always had a “broken” box model that behaves in the way you would expect. You can get Mozilla and Opera to behave this way with the -moz-box-model and box-model properties, but it all feels a little hackish to me.
As an aside, one thing I’ve always thought CSS needed was the ability to perform basic arithmetic operations, eg:
width: 100% - 10em;
That would make a lot of peoples lives much easier.
Well, it’s bad that IE didn’t follow the specification, but in this case I think the specification is bad. The IE developers should’ve pushed harder to get CSS fixed, rather than just go and implement it without doing so…
Either a fixed box model or the simple math as suggested by Tom would be incredibly useful.
I want to say that margins do exactly what you want padding to do by providing some inner spacing, so I’m in the boat with Tom in saying that CSS needs some basic math support.
No, Nolan, margins and padding are different. margins are *outside* a box, padding is the spacing to the contents *inside*. This is common terminology in page layout, and typically sizing is based on what the CSS spec calls the “padding edge” or the “border edge”. You set a size, and you set a padding. The padding is the spacing between the size you specified and the actual appearance of content.
Er, some CSS does math?
Let me see if I get this then:
Ideally we should have something like this (I hope it formats right):
|Margin|Padding|Content|padding|margin|
| specified Width |
But instead we get:
|Margin|Padding|Content|padding|margin|
|padding| width |padding|
| true width |
Unfortunately this is HTML and it removed all your extra spaces, so I’m not quite sure what you’re saying.
Ideally I should be able to say
height: 100px; padding: 10px; border: thin solid black;and get a 100px by 100px box. The actual text inside would be offset by 10px. But what I actually get is a 120px by 120px box, because there’s 10px of padding on every side. That makes padding rather useless because then it’s the same thing as a margin.Yes, I could emulate padding by putting a box with a margin inside another box—but then there’s no reason to have padding at all!
Satya,
What do you mean? I can’t specify
height: 100px - 0.5em;as a height in CSS. CSS is just supposed to be a style expression, so it doesn’t actually perform actions (except for some special cases likeurl()).Adding math would help alleviate the problem, but at the cost of making CSS do things that it really shouldn’t have to do in the first place… if the box sizing model were actually specified from the right place.
I was hoping that the HTML would be maintained somewhere. To make sense of those, align the end bars in the 2nd and 3rd lines up with the outside bars of the padding section in the 1st line.
try using non-breaking spaces next time if you are tryinging to align something like that Nolan & n b s p; without the spaces.
Wow — this CSS ‘bug’ just bit me, working on that Dashboard widget I showed you. What a pain in the butt!