Why Do The CSS Width and Height Properties Not Adjust for Padding

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:

  1. without squishing the content unreasonably
  2. 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 value

This 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 value

The 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:

..


  1. 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:
    1. 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.
    2. 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 it
  • content-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



Leave a reply



Submit