Bye Bye CSS Box Model...
Introduction
As some of you may know, one of the main building blocks of learning HTML + CSS is the Box-model.
The Box-model is a sum of element size (content + padding + borders) and there is the margins that is out side of the element.
A lot of people break their heads when calculating the sum of content + padding + border of an element
. and don’t forget every change in width + padding + border, need recalculation.
In the history of IE, when standards weren't so common, old IE's versions were working differently than current implementation of the box-model. For example given an element who has width:200px + padding:10px (every side) + border 10px (every side) the element overall size was 200px, contrary to this modern days which the result would be 240px.
And if you think's about it, it's really much easier in the nonstandard way.
Meet box-sizing
In CSS3 we were introduced with a new property called Box-sizing, it has 3 optional values
content-box(default), padding-box, border-box. (only 2 works fully in all browsers, but the 2 options that is working, are the most important.)
Box-sizing - values
1. content-box(default) - element width doesn’t include padding and border.
div#test{
box-sizing:content-box;
width:200px;
padding:20px;
border:20px solid red;
}
2. padding-box(only FireFox) - element width include padding and doesn’t include border.
div#test{
box-sizing: padding-box;
width:200px;
padding:20px;
border:20px solid red;
}
3. border-box - element width includes padding and borders.
div#test{
box-sizing:border-box;
width:200px;
padding:20px;
border:20px solid red;
}
This is a screenshot from my example to show all differences between all options - Watch Example (note: only firefox support padding-box)
Pros and Cons
To my opinion border-box is the most intuitive for most beginner developers and my solve a lot of frustration, A lot of newbies developers get confused in setting & calculating different width across all elements of the DOM, when using the box-model.
The issues, is that you need to get used to it and it's support from IE8 and above, quite good.
How To Work With It? (Reset All Elements to Border-Box)
In this new perception, the best way is to reset all elements in page, you just need to add this styles to the reset page:
CSS - reset stylesheet
*{
-moz-box-sizing:border-box;
box-sizing:border-box;
}
This will make all your elements to behave in the "new box-model", more accurate is to call it the "border-box method".
I saw websites that use it little different, and reset the pseudo element :before and :after too, like in this example:
CSS - reset stylesheet
*,
*:after,
*:before {
-webkit-box-sizing: border-box;/*unnecessary in new webkit browsers */
-moz-box-sizing: border-box;/*unnecessary in new Firefox browsers */
box-sizing: border-box;
}
It's make sense, it the same idea, It does not matter what you choose, It just important that you understand this new concept.
Maybe, not far from now the box-model will be belongs to the past, and people will talk about, how we worked in such strangest way.
Support
- Work in all browsers the values content-box and border-box.
- padding-box, works only in Firefox.
- IE - works from IE8 and above.
That’s all, I hope you enjoy it.
If you like this post, I will be happy to get your UPVOTE. You are welcome to follow me or my team @Walla! R&D and endorse my skills.
Elad Shechter.
Written by Elad Shechter
Related protips
19 Responses
Very helpful! Thanks Elad.
Nice summary - note your first CSS snippet should have a "-webkit-box-sizing:" in there too :D
Well, this remind me this article from Paul Irish http://www.paulirish.com/2012/box-sizing-border-box-ftw/ but I don't know, I've always thought that universal selectors have a heavy performance impact, more if we are changing layout, which implies reflow.
So I consider this solution a bad practice, I can't say I don't use the border-sizing
property, I use it where I need it, but not everywhere!
@davsket , It's your choice to use it or not, time will tell if it's good or bad - after more Experience with it. There are website like css-tricks that are already using it now. To say this solution is bad practice Because you think reset isn't a good idea, it's a whole topic in itself.
@magnetikonline, From what I know all web kit browsers support it without prefix
@elad2412 true, true - http://caniuse.com/css3-boxsizing but for the sake of one line of CSS I personally keep it in to provide some backward compat. support.
@davsket since everything works "right to left" a universal selector is really only going to be slow if it's part of a CSS chain - e.g. "* { my-css-rule: value }" would be much, much worse if I wrote ".my-class * { my-css-rule: value }" - since now EVERY element needs to know if it has ".my-class" anywhere as it's (grand)parent or higher.
This is where CSS parsing is going to really choke, if anywhere.
@magnetikonline I disagree because of merely logic, using a rule like *
applies to every element in your DOM, which at the end is one of the more expensive tasks you can do. Thats why at the end is better to use a normalization of elements, like Normalize.css than use a reset ( my opinion @elad2412 ).
I wrote a post about universal selectors: http://monoku.tumblr.com/post/18624340662/universal-selectors but even one year later I have found that is better to use Normalize.css than use any other reset css.
Finally, I quote Mozzilla: "Use the universal selector very carefully, as it is the most expensive CSS selector in terms of webpage performance."[https://developer.mozilla.org/en-US/docs/Web/CSS/Universal_selectors]
@davsket The * selector is expensive in combination with other selectors, but having just * is same as having any other single selector. Think of it this way - when calculating rules for adding styles, the browser considers a * rule as just another rule to be added to each element it renders - no additional computation is needed. More here: http://www.paulirish.com/2012/box-sizing-border-box-ftw/
@nikola @magnetikonline well, you know what? you are all right! I found this article from Todd Angling [http://www.kendoui.com/blogs/teamblog/posts/12-09-28/css_tip_star_selector_not_that_bad.aspx] where he reveals the results from many experiments with CSS in different scenarios. Is really good to know that the use of universal selector have unnoticeable impact in performance.
@davsket @nikola exactly, that's always been my understanding of single selectors like */h1/p/div/etc. it's only when chained up with parent selectors that the browser needs to start sniffing the DOM tree and flex it's muscles... ;)
+1 border-boxing is the most intuitive. That the standard is the very opposite is a clear case of the failure of standard committees to make decisions with due consideration of real world use.
For me, one of the major achievements of "border-box method" is the safe use of mixed units; i.e. width of 50% and border of 1px.
There is no effect on performance, so it's not "bad pratice" to use it everywhere
Nice article, I also agree that border-box is not only the most intuitive but also the most practical. It is worth mentioning that the border-box model is the default in IE and Opera, something that has driven many of us crazy.
My suggestion is to not use the * selector and instead use box-sizing only when it is required: when, in addition to width/height, also border or padding are specified. This doesn't happen as often as you might think.
What can I say about using before and after pseudoclasses with the universal selector: I just don't see the point, but maybe someone can explain it to me...
@hector The point of the before and after pseudo classes, is for resetting them to, the * selector isn't resetting them.
For if it's good or bad practice time will tell.
@elad2412 But the * selector should already apply to all elements. Why are the pseudoclasses necessary? Does * exclude some elements?
I would like to know if you have experienced corner cases using *, thanks!
@hector ,before and after aren't real elements. the * isn't apply them.
check my example I made for you(checked in chrome).
http://codepen.io/elad2412/pen/mJwpG
the before element isn't catching the box-sizing, even when i had the * selector. try to add to the before element box-sizing:border-box;, in my example, to see the different.
@elad2412 I see, they aren't DOM nodes and therefore * doesn't affect them. Thanks for creating an example.
A lot of people just copy-paste these examples, it would be good to mention that using the pseudoclasses is only necessary if they are using them to actually create elements.