Why do the CSS width and height properties not adjust for padding?
The reason CSS uses the box model as:
+---------------------
| Margin
| +-------------------
| | Border
| | +-----------------
| | | Padding
| | | +---------------
| | | | Width x Height
Is because CSS is a document styling language. It was (originally) designed with research papers and other formal documents in mind, not as a way to make pretty graphics. As such, the model revolves around the contents, not the container.
CSS isn't a programming language, it's a styling language. It doesn't explicitly tell the document how it should be displayed, it suggests some guidelines the browser should follow. All of these can be overwritten and modified by an actual programming language: JavaScript.
Going back to the content-model idea, consider the following CSS:
p
{
background-color: #EEE;
border: 1px solid #CCC;
color: #000;
margin: 10px;
padding: 9px;
width: 400px;
}
height
isn't specified, because the content defines the height, it may be long, it may be short, but it's unknown, and unimportant. The width
is set to 400px because that's how wide the content (text) should be.
The padding
is just a means of extending the background color so that the text can be nicely legible away from the edges, just like how you leave space when writing/printing on a sheet of paper.
The border
is a means of surrounding some content to differentiate it from the other backgrounds, or to provide a border (go figure) between various elements.
The margin
tells the paragraph to leave some space between edges, and with margin-collapsing, each group will remain evenly spaced without having to specify a different margin for the first or last element.
To maintain fluidity, width
defaults to auto
, which means the width will be as wide as possible:
- without squishing the content unreasonably
- without the padding extending beyond its container
Of course, in edge cases, the padding will extend beyond its container because the content might get squished. It's all about the content.
!important width changes for no reason
You should be familiar with box-sizing
property which determines how the width and height are calculated, in chrome the default value for box-sizing
set on a button is border-box
border-box: The width and height properties includes content, padding and border
Let's now talk about your case:
Content:
<button type="button" class="dot"></button>
The button has no text which means the width of it's content is 0px
Padding:
Default padding
on the button applied by the user agent(chrome in this case) is
padding-top: 1px;
padding-right: 6px;
padding-bottom: 1px;
padding-left: 6px;
Border:
we only care about the width of the border
Default border
on the button applied by the user agent(chrome in this case) is
border-top-width: 2px;
border-right-width: 2px;
border-bottom-width: 2px;
border-left-width: 2px;
we'll talk about the width alone, because it's pretty much same thing for the height
Without applying any styles, let's sum it all up
left border 2px
+ left padding 6px
+ content 0px
+ right padding 6px
+ right border 2px
So the overall width of a button by default will be 16px.
Now when you say width:9px
you explicitly setting the width in which border+padding+content
should live in, but their width is wider so it expands.
Why doesnt it happen on 15x15 tho.. (becomes 16x15 as if it has padding to fill till 16px on
That's because 16px
is the exact amount of space border+padding+content
need to live, that's why you see no change.
Now if you set the width to be wider than 16px
what will change is the content's width because border get set width border property
and padding width padding
property.
Solution
So to fix this we need to reset those predefined styles padding
and border
console.log(document.querySelector('button').getBoundingClientRect().width)
button { width: 9px; padding: 0; border:none;}
<button></button>
why width property is changin when changing the padding property in html
This is standard box-model behavior. To keep borders and padding from affecting the element width, use box-sizing: border-box
on the element. Here is a good explanation - https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing
border-box
- The width and height properties include the content, the padding and border, but not the margin. This is the box model used by Internet Explorer when the document is in Quirks mode. Note that padding and border will be inside of the box e.g. .box {width: 350px; border: 10px solid black;} leads to a box rendered in the browser of width: 350px. The content box can't be negative and is floored to 0, making it impossible to use border-box to make the element disappear.
The default box model box-sizing
value is content-box
. Here is an explanation for why your box is behaving the way it is currently.
content-box
- This is the initial and default value as specified by the CSS standard. The width and height properties are measured including only the content, but not the padding, border or margin. Note: Padding, border & margin will be outside of the box e.g. IF .box {width: 350px;} THEN you apply {border: 10px solid black;} RESULT {rendered in the browser} a box of width: 370px.
What happens when the padding is bigger than the defined size?
Your element will have a width equal to 70px*2 + 1px*2 = 142px
. The sum of the padding and border is bigger than the specified width so it's like you have width equal to 0 and only the padding/border are defining the final width
That is, any padding or border specified on the element is laid out and drawn inside this specified width and height. The content width and height are calculated by subtracting the border and padding widths of the respective sides from the specified width and height properties. As the content width and height cannot be negative ([CSS2], section 10.2), this computation is floored at 0 ref
You can clearly see why the content width will end being equal to 0 and the final width is only the padding and border.
To express this using math, you have the following formula:
content-width + padding + border = final-width
And
content-width = max(0,specified-width - (padding + border))
I am using max()
to express the fact that we take only positive value.
Do the calculation and you will get 142px
If specified-width - (padding + border)
is positive, you will get the logical result of specified-width = final-width
CSS: Padding vs. Height
Both height and padding inherently control the height of an element. I would have to disagree that using padding is wrong, but rather depends on the specific use case.
Use height when you need a fixed container size.
- PRO: Useful for when you don't want the container to stretch vertically.
- CON: Becomes brittle as you change properties like font-size, margin, padding, etc.
- Increasing sizes can cause contents to hide or overflow.
- Changing a font-size, for example, can cause a cascade change (you have to also change the margins/padding, or size properties of sibling/child elements.
Use padding when you don't need a fixed container height, but want to add whitespace.
- PRO: Easier to change font-sizes, margins, paddings, and add additional content to the container that may increase the container's vertical size.
- CON: Adding content/increasing size properties will cause the container to stretch vertically, which is undesirable in some scenarios.
- Not good for scenarios where vertical space is limited or needs to be controlled.
Use min-height and max-height for a hybrid approach.
- PRO: Forces a fixed height, but allows content to grow dynamically until it reaches that min or max.
- CON: You still have the "cascade" update problem with size properties and added content once you hit the min or max.
When does padding affect total width, and when doesn't it?
MDN - Box-sizing property
The
box-sizing
CSS property is used to alter the default CSS box model used to calculate widths and heights of elements. It is possible to use this property to emulate the behavior of browsers that do not correctly support the CSS box model specification.
By default, padding is not included in an element's width/height calculation. It's worth pointing out that the box-sizing
property is set to content-box
in this case.
MDN -
content-box
valueThis is the default style as specified by the CSS standard. The width and height properties are measured including only the content, but not the padding, border or margin. Note: Padding, border & margin will be outside of the box e.g. IF .box {width: 350px}; THEN you apply {border: 10px solid black;} RESULT {rendered in the browser} .box {width: 370px;}
If the box-sizing
property is changed to border-box
, the padding is included the element's width/height calculations, and so is the border.
MDN -
border-box
valueThe width and height properties include the padding and border, but not the margin. This is the box model used by Internet Explorer when the document is in Quirks mode. Note: Padding & border will be inside of the box e.g. IF .box {width: 350px}; THEN you apply {border: 10px solid black;} RESULT {rendered in the browser} .box {width: 350px;}
Further reading:
MDN box model
MDN padding
Why does padding change the height of the child div with border-box set?
From the specification:
The position and size of an element's box(es) are sometimes calculated relative to a certain rectangle, called the containing block of the element. The containing block of an element is defined as follows:
..
- If the element has 'position: absolute', the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed', in the following way:
- In the case that the ancestor is an inline element, the containing block is the bounding box around the padding boxes of the first and the last inline boxes generated for that element. In CSS 2.1, if the inline element is split across multiple lines, the containing block is undefined.
- Otherwise, the containing block is formed by the padding edge of the ancestor.
So the position:absolute
element will use 400px
that include the padding
For other elements, if the element's position is 'relative' or 'static', the containing block is formed by the content edge of the nearest block container ancestor box.
The other one will use the content-box which is 400px - 20px
so you won't have the same height
400*0.8 = 320 [positionned element]
(400 - 20)*0.8 = 304 [non-positionned element]
This is somehow logical since padding is a way to create space so it will get removed from the calculation when considering non-positionned elements. This logic is different for positionned element.
An example to illustrate:
.box {
border:2px solid;
padding:20px;
height:300px;
width:300px;
box-sizing:border-box;
position:relative;
}
.box > div:last-child {
height:100%;
width:100%;
background:red;
}
.box > div:first-child {
position:absolute;
width:100%;
height:100%;
background:rgba(0,255,0,0.5);
}
<div class="box">
<div></div>
<div></div>
</div>
Why padding is included in height sometimes?
That depends on what box-sizing
attribute you have used:
border-box
means that the height and width of the box, defined/calculated in CSS, will also include the padding(s) and border width(s) applied to itcontent-box
is the default behavior, where padding(s) and border width(s) are added onto the defined/calculated height and width of the box.
By setting box-sizing: border-box
as seen in your left example, you have defined the height of the element at 20px. This means that the actual content box will only be 8px tall, because the browser will subtract the border (1px top, 1px bottom) and padding (5px top, 5px bottom) form the defined height, leaving only 8px left, which is a tad bit too short to contain height of the entire line (therefore the word appears to be cut off).
Related Topics
HTML5 Canvas - Fill Circle with Image
CSS Position Absolute and Full Width Problem
How to Set Thymeleaf Th:Field Value from Other Variable
Make Input Type="Password" Use Number Pad on Mobile Devices
How to Handle Xml/HTML in Git Feature Branch Workflow
Content Url Is Not Working in Firefox
Why Is The First Element Always Blank in My Rails Multi-Select, Using an Embedded Array
Flexbox, Z-Index & Position: Static: Why Isn't It Working
How to Vertically Align a Table in CSS
What Happens When Localstorage Is Full
How to Set Favicon.Ico Properly on Vue.Js Webpack Project
Force an Image to Fit and Keep Aspect Ratio
Can't Show Some Websites in Iframe Tag
Negative Margin and Background
Inline Form Nested Within Horizontal Form in Bootstrap 3
Allow Access-Control-Allow-Origin Header Using HTML5 Fetch API