This question already has answers here:
Grid with viewport height and inner scrolling div
(2 answers)
Closed 4 years ago.
I have a chat system with a very simple header-body-footer layout, except the body needs to be scrollable. I've been trying to come up with a non-hacky (fixed heights for each viewport) solution and this was the final result, which happened entirely by accident:
flex-basis: auto;
overflow-y: scroll;
height: 1px;
It works perfectly across all resolutions, the body takes as much space as it can and the rest of it scrolls as intended. The problem is that i don't really understand this solution, shouldn't flex-basis: auto be sufficient for this calculation to happen? why do i have to set a height?
I've set it as 1px because if height is a value higher than the space available, height takes precedence over flex height.
[flex-basis] defines the default size of an element before the remaining space is distributed. It can be a length (e.g. 20%, 5rem, etc.) or a keyword. The auto keyword means "look at my width or height property" (which was temporarily done by the main-size keyword until deprecated). The content keyword means "size it based on the item's content" - this keyword isn't well supported yet, so it's hard to test and harder to know what its brethren max-content, min-content, and fit-content do.
It is likely because when setting it to auto, it is looking for the width or height property, which is otherwise unset.
For more information on flexbox, see https://css-tricks.com/snippets/css/a-guide-to-flexbox/
If you would like the container to grow to the space allocated without defining a set height / width, you can always use flex-grow.
[flex-grow] defines the ability for a flex item to grow if necessary. It accepts a unitless value that serves as a proportion. It dictates what amount of the available space inside the flex container the item should take up.
If all items have flex-grow set to 1, the remaining space in the
container will be distributed equally to all children. If one of the
children has a value of 2, the remaining space would take up twice as
much space as the others (or it will try to, at least).
Related
I have a flexbox container and several items within. Its flex-wrap property is set to wrap.
Width of the items dynamically increases (via animation property) and at a given point some of them are moved to a new line. I'd like to prevent this behavior, reserving for the items as much space as they will occupy at the end.
I see two ways to achieve this. The first is setting initial margins and decrease them as the items width increases. The second is placing the items in wrappers with fixed width equal to their maximal width.
Is there a better way based on some flexbox properties? I can't apply min-width to the items as it breaks their layout.
This question already has answers here:
flex-grow not sizing flex items as expected
(5 answers)
Closed 5 years ago.
I have a grid in flexbox, like so:
They're all positioned using flexbox, and then the panels themselves (the coloured bits) have margin: 5px.
codepen here: https://codepen.io/callumacrae/pen/bRoZdp
Because the top right section has two elements, there's more margin there, so it's pushing down slightly—I don't want this to happen!
I guess the two possible fixes are either to make the margins not do that, or make the components five pixels smaller instead of five pixels larger like they are right now - but I don't know how to do either of those things.
How can I make adding more elements not change the size of the parent?
The main problem is that you are sizing the elements using flex-grow. flex-grow is not the right property as it, together with flex-shrink is used to distribute the space left (or if to little).
You should use flex-basis, because as soon as you start fill these empty boxes with content, and their content will differ in size, they will misalign even more.
Here is an updated version of yours, where I changed to style="flex-basis: calc(50% - 10px);" (the 10px is to make up for your margins).
Codepen with flex-basis
And here is a version of yours, with the same text I used in mine
Codepen with flex-grow
I am reading the book Head First HTML and CSS and there it is written that a requirement for any floating element is that it must have a width. I tried floating right a div element without specifying width on it, and the float property works(it moves the div furthest right as possible) as supposed. Does this mean that there is an error in the book, or it is something that i am missing ?
Yes, you can have floated elements with no width values declared in the cascade. Then, through a defaulting process, the specified value will be the initial value.
For width, the initial value is auto.
CSS explains what should happen when a floated non-replaced element has width: auto:
If width is computed as auto, the used value is the
"shrink-to-fit" width.
Calculation of the shrink-to-fit width is similar to calculating the
width of a table cell using the automatic table layout algorithm.
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, find the available width: in this case, this is the width of
the containing block minus the used values of margin-left,
border-left-width, padding-left, padding-right,
border-right-width, margin-right, and the widths of any relevant
scroll bars.
Then the shrink-to-fit width is:
min(max(preferred minimum width, available width), preferred width)
The "shrink-to-fit" algorithm is now called fit-content measure.
float:right is simple stacking of elements, left to right until a line width is filled, then top to bottom. Like writing an English newspaper page.
float:left is used for things like a sidebar, it would take up the whole page, unless its width is constrained. This is why the width must be specified.
<div style = "float : left; background-color: #dd3fb8;">
<a style = "margin-left : 10%;">a</a>
<a>b</a>
<a>c</a>
</div>
In the example above, the letter "c" would be on new line, but if I set "margin-left" to px unit, "c" would be on the same line as "a" and "b". Why does this happen?
Unfortunately, the CSS2.1 spec doesn't appear to have a clear answer to this. In fact, I would say this is well within the realm of undefined behavior.
Here are the relevant points I can find:
Floats without a specified width will shrink to fit their contents. In the case of floats with only inline content, the float needs to be made just wide enough to fit its contents on a single line (notwithstanding explicit line breaks) and no more.
Percentage margins are calculated based on the width of the containing block.
Note that it says:
If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1.
... but as far as I can see, the behavior is consistent across all browsers.
That being said, the reason this statement applies is because since the margin of the inline element falls within the content bounds of the float, it can be said that the width of the float (the containing block of the inline elements) depends on the this element (the element having the margin).
Here's what I can deduce based on the points above:
When the margin is specified as a percentage, the width of the float is calculated without taking the margin into account, because it's not possible to calculate the margin until the width of the float has been determined.
The margin is then calculated based on the used width of the float, and the letter "c" wraps to a new line as a result of being pushed forward by the margin on "a". The width of the float does not change.
Again, none of this behavior is specified at all, and so technically it's not in violation of the spec. However, it seems sensible.
When the margin is specified as a pixel value, the margin is calculated first. The width of the float is then calculated taking this margin into account (remember that horizontal margins do apply to inline elements as normal). Per the shrink-to-fit algorithm, this is the preferred width: just wide enough to contain all the inline elements on a single line.
Unlike with percentage margins, this is very clear-cut, as implementations should have no trouble calculating computing absolute values for margins first.
I would be hard-pressed to call this a bug in any of the browsers, especially since they all behave consistently.
Lastly, of course, you can avoid this undefined behavior entirely simply by giving your floats explicit widths where possible. It does help to understand why you should do so, however.
Since your div is floated, and its width is auto (implicitly), http://www.w3.org/TR/CSS21/visudet.html#float-width applies:
If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width.
“shrink-to-fit” width basically means, let the element be as wide as its content requires it to be.
Now without the margin-left, that is no problem: All three of your a elements are inline elements that contain a specific character each – easy enough to determine their individual widths, and add them up.
But now you want a margin-left in percent, and here things get complicated – if we look at the definition for margin-left, it says:
Percentages: refer to width of containing block
Now, that leaves us in a bit of a pickle, since the width of the containing block (which is established by the floated div element), is computed based on its content – but now this margin-left would change the overall width of that content, but is in itself dependent on the width of the containing block, which it itself influences …
That’s a classical problem of two measurements that are dependent on each other … and that is therefor basically unsolveable.
http://www.w3.org/TR/CSS21/box.html#margin-properties says,
The percentage is calculated with respect to the width of the generated box's containing block. […]
If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1.
Edit: Basically the same as what BoltClock said in his answer, just took me a little longer …
The link has a left margin of 10%, 10% of how much? The parent element is floated left which means it does not have a width of its own, instead it expands as much as its contents. If you try to imitate how the browser would compute the resulting box and you will find yourself in a fix:
Let the width of the content (and therefore the container) be 30px
Add 10% of 30px = 3px left margin to the link
The resulting width of the container is 30 + 3 = 33px
This creates a loop where margin increases as outer width is increased and outer width increases as the margin is increased (10% of 33px = 3.3px means container width changes from 33px to 33.3px and so forth). For such computations the resulting behavior is undefined (as pointed out by CBroe).
The browser seems to avoid the loop and sticks with the 30px width. The 3px margin introduced after calculation causes the third link to flow into second row. The browser again avoids the loop by sticking with 30px width.
I am using a table based layout (using display: table properties). The container has a dynamic height (I have set min and max height properties on the container). All the inner elements within the container have their heights set to 100%. The idea being that they will always fill the available space.
The problem I am having is that elements that have display: table-cell will continue to expand above the 100% allocated space if they contain content that is taller than them. This happens even if I set overflow: auto.
I have created a jsfiddle to demonstrate the issue. Please see here:
http://jsfiddle.net/eSRA8/
In this example, the max-height of the container is 300px, but an inner element called .tall-content has a height of 400px. This makes the container grow taller than its max-height.
In Chrome this actually works how I want it to. However it does not work in Firefox or IE.
Please note that since the container height is dynamic, I can't set a fixed height on any of the inner elements (unless it is possible to use jQuery to assign the correct height on document load and on window resize, but this would need to respect the min and max height settings of the container).
Does anyone have any idea how I can achieve the desired result? I would like to keep as much of the existing structure as I can but if the same result can be achieved in a slightly different way then I'm open to that. Either way it needs to work the same in all browsers.
That looks to be a limitation of display:table;
You may be able to put the "container" in another div with max-height:300px;overflow:auto;
Here's some info which might explain why you are having difficulty:
http://www.w3.org/TR/CSS21/tables.html#height-layout