This question already has answers here:
How to make an element width: 100% minus padding?
(15 answers)
Closed 11 months ago.
I have got the design in Figma. I see that button has height as 40px.
How to set it corectly using padding + height?
If to set height: 40px and add padding it comes to more 40px by height.
Setting box-sizing:border-box; on your button or on all your elements (my advise) with * selector solves your problem.
*{
box-sizing:border-box;
}
button{
height:40px;
padding : 0.5rem;
}
<button>My button</button>
To know more about box-sizing, I really recommend you to read here on MDN. And here is an overview:
box-sizing
The box-sizing CSS property sets how the total width and height of an element is calculated.
The box-sizing property can be used to adjust this behavior:
content-box gives you the default CSS box-sizing behavior. If you set an element's width to 100 pixels, then the element's content box will be 100 pixels wide, and the width of any border or padding will be added to the final rendered width, making the element wider than 100px.
border-box tells the browser to account for any border and padding in the values you specify for an element's width and height. If you set an element's width to 100 pixels, that 100 pixels will include any border or padding you added, and the content box will shrink to absorb that extra width. This typically makes it much easier to size elements. box-sizing: border-box is the default styling that browsers use for the <table>, <select>, and <button> elements, and for <input> elements whose type is radio, checkbox, reset, button, submit, color, or search.
Related
EDIT: Not a duplicate of:
Make child element (with padding) 100% width and height of parent
In that question, the person was in need of the box-sizing: border-box model. I already got that model on my snippet.
What I'm trying to wrap my head around is the fact that, when you're using the border-box model with padding and/or border set to the parent, a child with 100% of height/width will only inherit the content-box height/width of the parent, and not the proper height/width (element's inspected height/width) itself. Because if you inspect the parent in my snippet, you'll see height/width set to 100px. And the child will be 80px. So, how come 100% of a height/width of 100px could be equal to 80px? That was counter-intuitive for me, but I think the answer is on the bold parts of the MDN quote below.
MDN Source: box-sizing
By default in the CSS box model, the width and height you assign to an
element is applied only to the element's content box. If the element
has any border or padding, this is then added to the width and height
to arrive at the size of the box that's rendered on the screen. This
means that when you set width and height, you have to adjust the value
you give to allow for any border or padding that may be added.
The box-sizing property can be used to adjust this behavior:
content-box gives you the default CSS box-sizing behavior. If you set
an element's width to 100 pixels, then the element's content box will
be 100 pixels wide, and the width of any border or padding will be
added to the final rendered width.
border-box tells the browser to
account for any border and padding in the values you specify for an
element's width and height. If you set an element's width to 100
pixels, that 100 pixels will include any border or padding you added,
and the content box will shrink to absorb that extra width. This
typically makes it much easier to size elements.
Original Question
I've been faced with a situation where a child element's width and height are set to 100% of the parent's width and height. And I'm using box-sizing: border-box;
Can somebody explain why that happens?
From MDN Docs on box-sizing, we get that:
border-box tells the browser to account for any border and padding in
the values you specify for an element's width and height. If you set
an element's width to 100 pixels, that 100 pixels will include any
border or padding you added, and the content box will shrink to absorb
that extra width. This typically makes it much easier to size
elements.
So in the following snippet, I was expecting that the child would cover completely the parent, because it would have width and height set to 100% of the parent. But that is not the case. The child gets 100% of the parent's height and width minus border and padding.
Question
If you inspect the elements (rendered by the snippet) you'll see that the parent height and width is 100px and the child is only 80px. Shouldn't it be also 100px, since it's set to 100%? Why this happens?
100% of the height is only related to the content box?
const parent = document.getElementById('parentDiv');
const child = document.getElementById('childDiv');
const parentStyle = window.getComputedStyle(parent);
const childStyle = window.getComputedStyle(child);
document.getElementById('description1').innerHTML = 'The parent height is: ' + parentStyle.height;
document.getElementById('description2').innerHTML = 'The child height is: ' + childStyle.height;
document.getElementById('description3').innerHTML = 'The parent width is: ' + parentStyle.width;
document.getElementById('description4').innerHTML = 'The child width is: ' + childStyle.width;
* {
margin: 0;
padding: 0;
}
div {
box-sizing: border-box;
}
#parentDiv {
border: 5px dotted black;
background-color: red;
width: 100px;
height: 100px;
padding: 5px;
}
#childDiv {
background-color:blue;
width: 100%;
height: 100%;
border: 5px dotted green;
}
<div id="parentDiv">
<div id="childDiv"></div>
</div>
<h3>Height</h3>
<div id="description1"></div>
<div id="description2"></div>
<h3>Width</h3>
<div id="description3"></div>
<div id="description4"></div>
I'm in a confusion since yesterday. Actually I have a markup as follows:
<div class="container">
<div class="child>
<div class="descendant">Content</div>
</div>
</div>
And CSS:
.container {
max-width: 500px;
min-width: 100px;
}
The .container element has some width between 100px to 500px according to my content and the child & descendant elements have some other content without any specific width or min/max-width.
What happens is that when I apply horizontal padding to .container, its content-box size remains as is & just padding is added to it. But whenever I apply horizontal padding to any of the child or descendant elements, they do not add padding to their size or the parent's size. Instead, their content-box size reduces and they accommodate padding.
I seriously can't get what is going on here. Can anyone explain me what's actually happening?
The width describes the content width, which you explicitly set to a maximum of 500px. So long as there is room, the content width of the container will be 500px. If you add padding to the container, that doesn't affect the content width because nothing else constrains it.
The descendants, on the other hand, have their width constrained by the container. If you add padding to a descendants, the width is reduced so the whole box can still fit inside teh container.
This is just normal box model behavior. Adding padding to an element that isn't bound by a parent element restricting it's size will grow outward to accommodate the new padding. But if an element is contained within a parent with a fixed width, and you add padding to the inner element, it can't grow outward and force the bounding parent to grow - it can only reduce it's content-box to make room for the padding.
If you want the outer and inner divs to behave consistently, you can add box-sizing: border-box; to .container and the padding will not cause the element to grow beyond the specified width/height.
This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 6 years ago.
I found if we set a block level element with height:auto or height: 0~100% without set up parent's height with explicitly value, and its block level child has bottom margin, then it will calculate height differently in Chrome, but not in Firefox. For the case which set height: 1%:
http://codepen.io/anon/pen/BjgKMR
html {
background: pink;
}
body {
background: yellow;
}
div {
height: 1%;
}
inner {
margin-bottom: 30px;
margin-top: 20px;
}
<div>
<p class="inner">block level element</p>
</div>
The height of div block will be calculated as the margin-bottom + content height of p element. I am confused about why the height: 1% should be computed as to auto because the parent elements(html and body tag) not set its height explicitly, but has different height as we just directly set the height to auto?
If we directly set it to height: auto, it will clearly just set the height as its child block-level element's height, which is not include its bottom margin.
html {
background: pink;
}
body {
background: yellow;
}
div {
height: auto;
}
inner {
margin-bottom: 30px;
margin-top: 20px;
}
<div><p class="inner">block level element</p></div>
I have read the CSS 2.1 spec and think about my question might covered with the height property and margin collapse topic, but still cannot understand why it behaves different in Chrome ver. 47.0.2526, though Firefox ver. 44.0.2 will display the height with same value.
Listed references:
https://www.w3.org/TR/CSS2/visudet.html#the-height-property
10.5: percentage
... If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'. ...
10.6.3: Block-level non-replaced elements in normal flow when overflow computes to visible.
... if 'height' is 'auto', the height depends on whether the element has any block-level children and whether it has padding or borders:
The element's height is the distance from its top content edge to the first applicable of the following:
the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines
the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin does not collapse with the element's bottom margin
the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin
zero, otherwise
https://www.w3.org/TR/2011/REC-CSS2-20110607/box.html#collapsing-margins
8.3.1 collapsing margins.
The top margin of an in-flow block element collapses with its first in-flow block-level child's top margin if the element has no top border, no top padding, and the child has no clearance.
The bottom margin of an in-flow block box with a 'height' of 'auto' and a 'min-height' of zero collapses with its last in-flow block-level child's bottom margin if the box has no bottom padding and no bottom border and the child's bottom margin does not collapse with a top margin that has clearance.
... If the top and bottom margins of a box are adjoining, then it is possible for margins to collapse through it. In this case, the position of the element depends on its relationship with the other elements whose margins are being collapsed.
If the element's margins are collapsed with its parent's top margin, the top border edge of the box is defined to be the same as the parent's.
Otherwise, either the element's parent is not taking part in the margin collapsing, or only the parent's bottom margin is involved. The position of the element's top border edge is the same as it would have been if the element had a non-zero bottom border.
So first you have the W3C standards, which are a set of guidelines for browser makers.
And then you have the browser makers, who are free to do whatever they want (as evidenced by a history of deviations by Internet Explorer).
In particular, with CSS percentage heights, there are clear differences in behavior among browsers.
You've posted one example. Here's another:
Percentage Heights in Flexbox: Chrome/Safari vs Firefox/IE
When working with flexbox, Chrome and Safari resolve percentage heights on flex items based on the value of the parent's height property. Firefox and IE11/Edge prioritize the parent's flex height.
It appears Webkit browsers adhere to a more traditional interpretation of the spec:
CSS height property
percentage Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly and this element is not absolutely positioned, the value computes to "auto".
auto The height depends on the values of other properties.
In other words, for percentage height to work on an in-flow child, the parent must have a set height.
That is the traditional interpretation of the spec: The term "height" means the value of the height property. My own view is that this language is vague and open to interpretation, but the height property requirement has become the predominant implementation. I've never seen min-height or max-height work on a parent when dealing with percentage values.
Recently, however, Firefox and IE have broadened their interpretation to accept flex heights, as well.
Examples of Firefox and IE using a parent's flex height as reference for a child's percentage height:
Chrome ignoring flex-basis in column layout
Chrome / Safari not filling 100% height of flex parent
Height is not correct in flexbox items in Chrome
Flexbox in Chrome--How to limit size of nested elements?
Knowing which browsers are in compliance with the spec is a bit difficult because, as I mentioned before, the spec language seems vague and open to interpretation.
With the last update to this part of the definition being in 1998 (CSS2), and the advent of new forms of height such as flex height, an update seems long overdue.
I think it's fair to say that when it comes to percentage heights, until the spec definition gets an update, you can expect rendering differences among browsers.
Alternative Solutions
Here are two alternatives to consider when wanting a child element to take the parent's full height.
Apply display: flex to the parent. This automatically sets align-items: stretch, which tells the child to expand the full available height of the parent.
Apply position: relative on the parent and position: absolute; height: 100%; width: 100% on the child. With absolute positioning, a percentage height will work without a specified height on the parent.
Why does adding some padding affects elements outside the DIV box? Padding isn't supposed to create some space between the border of the DIV and contents inside it? How can you create this space without affecting elements outside the DIv box?
How can you create this space without affecting elements outside the
DIv box?
Use box-sizing: border-box
From MDN:
border-box
The width and height properties include the padding and
border, but not the margin.
The reason that this property must be set is because by default the value for box-sizing is content-box. Again from MDN:
content-box 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.
Assuming you have specified a content height or width, then padding will be placed around that. That moves the border outwards. That moves the margin outwards. That pushes nearby elements away.
You can change it by reducing the height and/or width to compensate or by using the box-sizing property to make height and width determine the distance between the outside edges of the border instead of the outside edges of the content.
Try looking into the box-sizing property...
https://css-tricks.com/box-sizing/
Today, the current versions of all browsers use the original "width or
height + padding + border = actual width or height" box model. With
box-sizing: border-box;, we can change the box model to what was once
the "quirky" way, where an element's specified width and height aren't
affected by padding or borders. This has proven so useful in
responsive design that it's found its way into reset styles.
The value you're after is border-box:
.class {
box-sizing: border-box;
}
Previously my assumption about width: auto was that the width is set to that of the contents. Now I see that it takes the full width of the parent.
Can anyone please describe the differences between these?
Width auto
The initial width of a block level element like div or p is auto. This makes it expand to occupy all available horizontal space within its containing block. If it has any horizontal padding or border, the widths of those do not add to the total width of the element.
Width 100%
On the other hand, if you specify width:100%, the element’s total width will be 100% of its containing block plus any horizontal margin, padding and border (unless you’ve used box-sizing:border-box, in which case only margins are added to the 100% to change how its total width is calculated). This may be what you want, but most likely it isn’t.
To visualise the difference see this picture:
Source
width: auto; will try as hard as possible to keep an element the same width as its parent container when additional space is added from margins, padding, or borders.
width: 100%; will make the element as wide as the parent container. Extra spacing will be added to the element's size without regards to the parent. This typically causes problems.
Width 100% :
It will make content width 100%. margin, border, padding will be added to this width and element will overflow if any of these added.
Width auto :
It will fit the element in available space including margin, border and padding. space remaining after adjusting margin + padding + border will be available width/ height.
Width 100% + box-sizing: border box :
It will also fits the element in available space including border, padding (margin will make it overflow the container).
It's about margins and border. If you use width: auto, then add border, your div won't become bigger than its container. On the other hand, if you use width: 100% and some border, the element's width will be 100% + border or margin. For more info see this.
As long as the value of width is auto, the element can have horizontal margin, padding and border without becoming wider than its container (unless of course the sum of margin-left + border-left-width + padding-left + padding-right + border-right-width + margin-right is larger than the container). The width of its content box will be whatever is left when the margin, padding and border have been subtracted from the container’s width.
On the other hand, if you specify width:100%, the element’s total width will be 100% of its containing block plus any horizontal margin, padding and border (unless you’ve used box-sizing:border-box, in which case only margins are added to the 100% to change how its total width is calculated). This may be what you want, but most likely it isn’t.
Source:
http://www.456bereastreet.com/archive/201112/the_difference_between_widthauto_and_width100/
The initial width of a block level element like div or p is auto.
Use width:auto to undo explicitly specified widths.
if you specify width:100%, the element’s total width will be 100% of its containing block plus any horizontal margin, padding and border.
So, next time you find yourself setting the width of a block level element to 100% to make it occupy all available width, consider if what you really want is setting it to auto.
When we say
width:auto;
width will never exceed the total width of parent element. Maximum width is it's parent width. Even if we add border, padding and margin, content of element itself will become smaller in order to give space for border, padding and margin. In case if space required for border + padding + margin is greater than total width of parent element then width of content will become zero.
When we say
width:100%;
width of content of element will become 100% of parent element and from now if we add border, padding or margin then it will cause child element to exceed parent element's width and it will starts overflowing out of parent element.
For positioning elements,
width: 100%, not relative to the parent, but the nearest positioned element.
If they are all statically positioned, it is the nearest parent element.
Using width:auto; + display:inline-block; in css giving awesome effect.
width : auto; makes element width auto for adjustment with another object using with display: inline-block; like if we have a div element and another one also div element and div elements are block level element so showing them together in one line use width: auto; and display:inline-block