Can someone explain why my div with table-layout:fixed is changing the width of its parent element (body in this case) to make it 100% when it shouldn't be 100% since it's positioned?
body {
border: 2px solid red;
height: 100vh;
margin:0;
padding: 0;
position: absolute;
}
.c{
display: table;
width: 80%; /* Any percentage value different from 0 */
table-layout:fixed;
outline: 2px solid blue;
}
<div class="c">d</div>
As you can see above, adding table-layout:fixed forces the body to be full width AND the percentage width on the div will work relatively to the width of the body!
This is not the case with the below snippet, where the behavior is somehow logical and intuitive:
body {
border: 2px solid red;
height: 100vh;
margin:0;
padding: 0;
position: absolute;
}
.c{
display: table;
width: 80%;
/* table-layout:fixed; */
outline: 2px solid blue;
}
<div class="c">d</div>
How does table-layout:fixed affect the parent element, which is positioned in this case?
As a side note, using pixel values with width produces a logical result:
body {
border: 2px solid red;
height: 100vh;
margin:0;
padding: 0;
position: absolute;
}
.c{
display: table;
width: 200px;
table-layout:fixed;
outline: 2px solid blue;
}
<div class="c">d</div>
We can also have some overflow with that strange behavior:
body {
margin:0;
position:relative;
width:300px;
border-top:20px solid green;
}
.container {
border: 2px solid red;
height: 100vh;
position: absolute;
}
.c {
display: table;
width: 120%;
table-layout: fixed;
outline: 2px solid blue;
animation:change 2s linear infinite alternate;
}
#keyframes change {
from{width:1%;}
to {width:150%}
}
<div class="container">
<div class="c">d</div>
</div>
Looks like you're not the first to bring this up. You might be the second, though.
To be clear, this is a combination of two issues:
The width of an absolutely positioned element is shrink-to-fit. Somehow the shrink-to-fit width is being determined to be as wide as the absposed element's containing block will allow. (The containing block for the absolutely positioned body is the initial containing block.)
A percentage width on an element whose containing block depends on its contents for auto sizing results in undefined behavior.
Issue #2 is pretty easy to write off:
implementations agree not to calculate the width of either element more than once.
i.e. body is sized using shrink-to-fit, then the table is set to 80% of that width, and the size of body is "not computed again". The only "undefinedness" of this is that the spec doesn't require or disallow, or indeed care what implementations do.
So the question then boils down to why shrink-to-fit is yielding "as wide as possible" in #1 prior to determining the size of the table in #2. Here is how the spec describes shrink-to-fit for absposed elements:
[...] Roughly: calculate the preferred width by formatting the content without breaking lines other than where explicit line breaks occur, and also calculate the preferred minimum width, e.g., by trying all possible line breaks. CSS 2.1 does not define the exact algorithm. Thirdly, calculate the available width: this is found by solving for 'width' after setting 'left' (in case 1) or 'right' (in case 3) to 0.
Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width).
But this doesn't tell us why, or even that, the preferred width of a fixed-layout table is "as wide as its containing block will allow". Neither css-sizing-3 nor css-tables-3 appears to contain the answer.
According to David Baron (from the same thread), who works on Gecko:
Fixed-layout tables report an intrinsic max-content inline size as infinite.
(note that "max-content inline size" means the same thing as "preferred width")
So there's our answer. The unbounded max-content inline size of fixed-layout tables is what causes this table's absolutely positioned parent to be stretched as wide as its own containing block (the initial containing block) will allow, in contrast to auto-layout tables.
And, at least for now, this is as close as I'll get to an official source because I'm having trouble reaching the same conclusion just by reading css-sizing-3, and I'm unsure if David's statement is based on Gecko's behavior alone, behavior of all implementations, or on specified behavior.
This is my explanation based on the described above issue so it can be viewed as speculation based on the bounty requirements for "official resources".
When table-layout: fixed is applied, the content no longer dictates the layout, but instead, the browser uses any defined widths from the table's first row to define column widths. If no widths are present on the first row, the column widths are divided equally across the table, regardless of content inside the cells.
In order for a value of fixed to have any effect, the table's width has to be set to something other than auto (the default for the width property) ... source
Once table-layout:fixed; is applied without the parent container having any set width and its own width set in percents it would expand its parent container (whatever that container is body/div/etc) to 100% and take the specified width (in this case 80%) relative to that of the parent.
It would do this since its default purpose is with width being set to make sure its columns width is distributed evenly regardless if there are columns or not. If they aren't any columns it would treat the element as one column. To do that it would still need its width to be relative to its parent (when its own width is set in %).
Example table-layout:fixed is not applied since it has no defined width although it is set in the CSS, table-layout:auto is applied as that is the default:
body {
border: 2px solid red;
height: 100vh;
margin: 0;
padding: 0;
position: absolute;
}
.c {
display: table;
table-layout: fixed;
/* width: 80%; */
outline: 2px solid blue;
}
<div class="c">d</div>
Now let's set the width:
body {
border: 2px solid red;
height: 100vh;
margin: 0;
padding: 0;
position: absolute;
}
.c {
display: table;
table-layout: fixed;
width: 80%;
outline: 2px solid blue;
}
<div class="c">d</div>
In your second example,
body {
border : 2px solid red;
height : 100vh;
margin : 0;
padding : 0;
position : absolute;
}
.c {
display : table;
width : 80%;
outline : 2px solid blue;
/* table-layout : fixed; */
}
You have absolutely positioned the body, so it's taken out of normal flow and it doesn't influence the positioning or sizing of its .c child.
So the width of .c isn't 80% of the body as you might initially expect.
You can however use units like pixels or vw to set the width of .c and the result will be more intuitive, like this.
.c {
display : table;
width : 80vw;
outline : 2px solid blue;
/* width : 80%; */
/* table-layout : fixed; */
}
Similarly, when you use table-layout:fixed; your browser uses an algorithm to calculate the width of the table which is similar to using units like pixels or vw to calculate the width for the table.
To quote from the W3C spec
17.5.2.1 Fixed table layout With this (fast) algorithm, the horizontal layout of the table does not depend on the contents of the cells ...
Related
I'm attempting to understand why in this codepen the two boxes aren't perfectly aligned.
https://codepen.io/mburke05/pen/BYXOGP
html
<div class="div_one">pixel</div>
<div class="div_two">percent</div>
css
.div_one {
border: solid red;
transform: translate(70px, 20%) ;
width: 140px;
height: 60px;
}
.div_two {
border: solid blue;
transform: translate(50%, 30%) ;
width: 140px;
height: 60px;
}
I thought I understood that, when using %'s rather than pixel or other values, that the % value was based on the height of the element itself rather than the % of the parent (which in this case would be the viewport.)
However, to achieve what I believe is alignment, I would need to set translate(48%, 30%) as the value. Why is this? Isn't 70 50% of 140, or is there more to it than I'm understanding.
As a follow-up, can anybody explain why this is the preferred way of centering an object vertically mathematically?
div {
box-sizing : border-box
}
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.
Read More here
.div_one {
border: solid red;
width: 140px;
height: 60px;
}
.div_two {
border: solid blue;
width: 140px;
height: 60px;
}
remove CSS property "transform", Both Div will align perfectly and if you want to move the position of the box means use padding or margin and if you want to fix in box position then use Position property
I don't get the auto value. If applied to height it will take on the child's height, but if applied to width it will take on the parent's width.
There are no MDN posts on the auto value itself, and Google yields "100% VS auto" hits rather than "width:auto VS height:auto" hits.
For my current needs I would like an element to expand to its child's width, but in general I wish to know what is the deal with auto.
.divXS {
width: 100px;
height: 100px;
background: green;
}
.divXXS {
width: 50px;
height: 50px;
background: yellow;
}
.divSM {
width: 200px;
height: 200px;
}
#Father {
background: blue;
border: 3px solid #20295E;
}
#Mother {
background: pink;
border: 3px solid #DB6DBE;
}
#Daughter {
width: 100%;
height: 100%;
}
#Son {
width: auto;
height: auto;
}
<div class="divSM" id="Mother">
<div class="divXS" id="Daughter">
<div class="divXXS" id="grandDaughter"></div>
</div>
</div>
<div class="divSM" id="Father">
<div class="divXS" id="Son">
<div class="divXXS" id="grandSon"></div>
</div>
</div>
jsFiddle / jsBin
'auto' doesn't even always behave the same way for the width property and the height property respectively. It can have different behaviors for the width property not only depending on the element's display type, but also depending on the value of other properties for the same display type. That's why it's called 'auto' — from my answer here,
The value of said property is adjusted automatically according to the content or the context of the element.
Based on your description I'm assuming your question is in the context of block layout. Block layout consists of a series of block-level boxes stacked vertically in normal flow.
So a block container box, by default, only has to grow tall enough to contain its descendants stacked vertically. And since block-level boxes never stack horizontally in normal flow, there's no reason they can't stretch to the full width of their containing block. (They don't even need to shrink to accommodate floats in the same block formatting context, though the line boxes inside them do, but that's a separate topic altogether.)
And that's why, in block layout, an auto height is based on the total height of descendants and an auto width is based on the containing block width.
I've come across numerous question of the similar nature but my situation is a bit different; my outer container is height 100% instead of a fixed height.
I have a bunch of divs inside a container. They overflow and I want to have a scrollbar to allow scrolling.
This is exactly what I want to achieve: http://jsfiddle.net/jcjw2jmo/
Except, the link I posted has a fixed height: 200px;. I want to have a percentage height instead.
I've tried setting a percentage height and max-height with no luck. Here's my progress: http://jsfiddle.net/k52eh0xr/
How do I get both the fiddles to have the same behaviour but with using percentages instead?
Thanks so much
PS. I know this can be done using Javascript/jQuery but I am looking for a CSS-only solution
I think you need set your html and body tag with height:100% so you can use percent like you want
html, body {height:100%}
DEMO
The problem you're having relates mostly to using percentage heights in CSS.
If you're going to use a percentage height on a child element, you need to specify the percentage height for all parent elements up to and including the body and root elements (html).
Try this in your code:
HTML (no changes)
CSS
/* NEW */
html, body {
height: 100%; /* necessary when using percentage heights within body
on non-absolutely positioned children (such as .outer)
more info: https://stackoverflow.com/a/31728799/3597276 */
overflow: hidden; /* prevent vertical scrollbar on browser window,
in conformance with demos posted in question */
}
.outer {
border: 1px solid black;
height: 50%; /* ADJUSTED */
/* max-height: 10%; REMOVED */
overflow-y: scroll;
width: 300px;
}
.inner {
/* height: 10%; REMOVED
max-height: 10%; REMOVED */
}
.item {
background: grey;
border: 1px solid red;
height: 50px;
}
DEMO: http://jsfiddle.net/k52eh0xr/5/
I have a CSS question you may be able to help with.
I'm trying to build a website with a 'Fluid' layout.
All website content will be contained within a wrapper div
When the screen shirks, I Would like the wrapper div to shirk along with it's content.
However, when the screen size is increased, I would like the wrapper div to maintain a max size. The aim is to prevent images scaling beyond their native resolution and the formatting of text changing (a paragraph may become a single line on very large screen)
Can I apply a max pixel with and a percentage to the wrapper DIV? is there a better way to achieve the goal?
.wrapper {
margin: 0 auto;
max-width: 800px;
width: 80%;
background-color: #ffffff;
border: 1px solid;
height: 1000px;
}
Many thanks,
P
Yes, you can do this and it is a good practice.
Can I apply a max pixel with and a percentage to the wrapper DIV?
YES, you can apply it
.wrapper {
margin: 0 auto;
max-width: 800px;
width: 80%;
background-color: #ffffff;
border: 1px solid;
height: 1000px;
}
the width: 80%; means 80% of the screen width(or browser window) and it will not exceed max-width: 800px;
The max-width property in CSS is used to set the maximum width of a
specified element. The max-width property overrides the width
property, but min-width will always override max-width whether
followed before or after width in your declaration.
I was trying to get a double bordered (underlined) header. First one is full width, second is just text width. Borders should overlap
There is an easy solution with two elements nested like that:
<h1><span>Title</span></h1>
and css:
h1 {
border-bottom: 1px solid red;
}
h1 span {
display: inline-block;
padding: 0 0 10px;
margin-bottom: -1px;
border-bottom: 1px solid blue;
}
Span has inline-block display property so it has right width.
I'm wondering if it's possible to get same effect with :after, :before selectors and only h1 element.
It can be done. I've used vw units.
Take a look at this Working Fiddle
HTML:
<h1 class="SpecialBorder">Title</h1>
CSS:
*
{
margin: 0;
padding: 0;
}
.SpecialBorder
{
display: inline-block;
position: relative;
}
.SpecialBorder:before , .SpecialBorder:after
{
content:'';
position: absolute;
left: 0;
bottom: 0;
}
.SpecialBorder:before
{
width: 100vw;
border-bottom: 1px solid red;
}
.SpecialBorder:after
{
width: 100%;
border-bottom: 1px solid blue;
}
Explanation:
the before & after pseudo elements are the ones that draw the borders.
both of them are empty elements. with a certain width that causes their border to be visible.
they are absolutely position at the bottom of their <h1> parent.
before: responsible for the red border. so his width is set to '100%' of view port.
after: responsible for the red border. so hes width is set to 100% of his parent (the <h1>), that's why the h1 is set to `display:inline-block;" (so it will span ony just as his content)
vw unit is supported by new browsers only.
notice that if you cant use vw units, you can still make something familiar to that.
delete the display:inline-block; from h1 (causing it to span all the way again)
change the width of before to 100% (to make it span all the way),
change the with of after to some fixed value of your choice.
Edit: as thgaskell stated in th comment,
there's a bug where vw units don't update properly on webkit
browsers when the window is resized.
Edit 2:
for making elements to show after the title, you can use a <br /> tag, or clearing techniques like showed here.
I'm not sure if that's what you want, but you could do these rules:
h1 {
...
}
/* here are the direct children of every h1 */
h1>* {
...
}
::after and ::before selectors would make sense when inserting new content (note the double colons). Here's some MDN on ::after selector and some examples:
https://developer.mozilla.org/en-US/docs/Web/CSS/::after