What is the difference between CSS fit-content and max-content? - css

I'm following this article https://css-tricks.com/almanac/properties/w/width/ to try to understand how this rules work.
I have this example:
*{margin:0; padding:0}
.box{
background: lightgreen;
margin: 0 auto;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
<div class="box">
<img src="https://tyrannyoftradition.files.wordpress.com/2012/05/cutest-kitten-hat-ever-13727-1238540322-17.jpg" alt="" />
<figure>Yes, put some text here that is wider than the image above to try some new rules</figure>
</div>
The article says that fit-content can be used to center a div of unknown width with margin: x auto;
But if you change fit-content for max-content in this example, this is working anyway and they seem to behave always in the same way.
Does anyone know what is the difference between this two rules and in which cases should I use one or the other?

fit-content uses max-content, unless available < max-content, then it uses available. Unless available < min-content, then it uses min-content.

In a few words width: fit-content; means :
"Use the space you can (available) but never less than your min-content and never more than your max-content"

As you can see it here https://developer.mozilla.org/en-US/docs/Web/CSS/width the max-width simply sets the size based on the space its children needs regardless if it's available or not, while the fit-width checks if the space the children needs using max-width is available and if not, it uses the min-width instead.
For further reading about the difference between max-width and min-width see http://dev.w3.org/csswg/css-sizing/#block-intrinsic.

the one scenario in which max-content and fit-content don't behave the same way is when you set a 'max-width' property on the element, and the viewport size is narrower than the max-width value. in this case the 'max-content' value will result in a layout in which the text will be cut arbitrarily (and the only way to see the entire text is to scroll horizontally). using the 'fit-content' value, on the other hand, will ignore the max-width property and adjust the text nicely inside the viewport.

It seems these two codes are the same:
.fit-content {
width: fit-content;
}
// is same as
.fit-content {
width: max-content;
max-width: 100%;
min-width: min-content;
}
In my experience I either go with width: fit-content or width: max-content; max-width: 100%. The latter is for cases when the element shouldn't have a min-width.

Related

For a CSS flexbox, allow an element to shrink to minimum(its intrinsic width, an absolute length) [duplicate]

This question already has answers here:
Flexbox children shrink up to a certain point (but don't expand if they don't need to)
(3 answers)
Closed 2 years ago.
I have a box that displays a number of text elements, one after the other along a row. I do not want the text within each element to wrap. Instead if there is insufficient room then it should truncate the text and show an ellipse.
This is easy to obtain using display: flex, and allowing each element to shrink to zero.
But the smaller elements are shrunk so much that the text almost completely disappears. In that case I would rather shrink the smaller elements a little less, and shrink the bigger elements more. This can also be obtained by giving each element a bigger min-width (say 100px) so that it cannot shrink beyond a certain point.
My problem occurs when one of the text element's intrinsic width is already smaller than 100px. Since I just specified that the element had a longer min width, the browser leaves extra space after the element. I don't want that extra space.
I would prefer not to use java-script. I'm seeking a solution using CSS. It's so close that I feel that it should be possible, but none of my attempts have come out correctly.
If I knew in advance which text elements were tiny, then I can specify that the tiny elements should not flex at all, and get the desired outcome. But without using javascript I do not know which elements are tiny.
If I could set the min-width of an element to the minimum of its intrinsic width and 100px then I would get the desired outcome. Although CSS does have a min() function which may be used for min-width, unfortunately it appears that I am not allowed to use max-content as an argument to that function.
The description of min-width on MDN (https://developer.mozilla.org/en-US/docs/Web/CSS/min-width) states that fit-content(100px) is a syntactically valid way of specifying the min-width. I hoped to craft an element whose minimal content size is zero, and max size is the text element's intrinsic length. Then fit-content(100px) would either be 100px, or if that's larger than the intrinsic length, the intrinsic length. But whenever I use fit-content() with an argument the browser says that the expression is invalid.
Finally I tried to use a grid display. But then fit-content() either uses the intrinsic width or 100px, but does not expand further. I tried experimenting with minmax with no luck (it seems I cannot put fit-content() as an argument to minmax()). Besides I do not know the number of text elements, but a grid display wants me to specify that number so I don't think a grid can be made to work.
So is there any way to obtain the desired outcome using just CSS. Since this text is for an Electron program, I only care about Chrome as a browser. I have an example below showing each of my attempts.
main {
display: flex;
flex-direction: column;
width: 600px;
border-style: solid;
border-color: black;
border-width: 1px;
}
span {
background-color: skyblue;
padding: 10px;
margin: 0 10px 10px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 0 1 auto;
}
section {
width: 100%;
display: flex;
}
.set-min-width span {
min-width: 100px;
}
.set-min-width .no-shrink {
flex: none;
min-width: initial;
}
.use-max-expression span {
min-width: min(100px, max-content);
}
.use-fit-content div {
flex: 0 1 auto;
min-width: fit-content(100px);
display: flex;
}
.use-fit-content div span {
min-width: 0;
}
.use-grid {
display: grid;
grid-template-columns: fit-content(100px) fit-content(100px) fit-content(100px);
}
.use-grid span {
min-width: 0;
}
<main>
<h4>The hidden overflow allows each text item to shrink to nothing<br> Both small and medium elements are heavily truncated<br></h4>
<section>
<span>Medium length</span>
<span>Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
<h4>By setting a min-width to 100px I can control truncation of medium element. But the tiny element now has extra space after it that I do not want.</h4>
<section class="set-min-width">
<span>Medium length</span>
<span>Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
<h4>1: This is what I want.<br> But to obtain it I had to specify a different style for the tiny element so that it would not flex. But I don't know in advance which elements are tiny.</h4>
<section class="set-min-width">
<span>Medium length</span>
<span class="no-shrink">Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
<h4>2: I want the min-width to be the element's max-content if this is smaller than the truncation limit<br> `min(100px, max-content)` would return the correct result, but it is not valid CSS and so is ignored</h4>
<section class="use-max-expression">
<span>Medium length</span>
<span>Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
<h4>3: I tried to use fit-content(arg)<br> The inner element has min-width 0, so its min-content size should be 0<br> Its max-content size is the intrinsic width of the text<br> So the fit-content(100px) size should be 100px if that's smaller than intrinsic
width, or the intrinsic width otherwise.<br> Despite MDN stating that fit-content with argument is valid CSS for min-width, the browser rejects `fit-content(100px)`</h4>
<section class="use-fit-content">
<div><span>Medium length</span></div>
<div><span>Tiny</span></div>
<div><span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span></div>
</section>
<h4>4: Using fit-content(100px) in a grid does not work either. The elements are indeed not expanded if natural width is smaller than 100px. But the elements do not flex to take rest of space.<br> Besides a grid won't work because the number of columns is
not known in advance.
</h4>
<section class="use-grid">
<span>Medium length</span>
<span>Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
</main>
I was giving this a little play around and this was the best I could come up width. The problem that I can see is that flex-box is terrible for not obeying boxes without setting its inner elements with a max-width of some kind. There is a few other answers I found on Stackoverflow but none of them seem to really fix what you are asking for. In my answer I used max-width on the spans, along with text-overflow: ellipsis and overflow: hidden to create something close to what you had requested.
code below and codepen - here https://codepen.io/rl4444/pen/oNLQVRr?editors=1100
HTML
<main>
<h4>my solution</h4>
<section class="box-items">
<span>Medium length</span>
<span>Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
</main>
CSS
main {
max-width: 600px;
width: 100%;
border-style: solid;
border-color: black;
border-width: 1px;
position: relative;
box-sizing: border-box;
}
span {
background-color: skyblue;
padding: 10px;
margin: 0 10px 10px 0;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 300px;
}
section {
display: flex;
box-sizing: border-box;
max-width: 100%;
}
.box-items span {
border: 1px solid red;
overflow: hidden;
}

Width ignored on flexbox items

http://jsfiddle.net/XW9Se/
I've set width: 200px; on the left <div> but if I view it with the browser inspector tool it appears that the real width is random or something. It keeps changing depending on the window size.
Why doesn't the width take effect?
EDIT: If I remove width: 100% the width stays fixed. But I need that so the #main div takes the remaining width :( Is there any way to have the sidebar # fixed width and the other <div> fill the rest of the container width? width: auto; on #main doesn't work..
The answer from Adrift is perfect; but a change to make it more flex would be
#left{
flex-basis: 200px;
flex-grow: 0;
flex-shrink: 0;
}
And remove the width property entirely.
It would be the flex way to say that the element will have an invariable width of 200px
My preferred way of dealing with this situation is to add:
flex-shrink: 0;
This way you may continue using width in your Flex container and you've given it specific information about how you wish this flex item to behave.
Another option, depending on the requirement is to use min-width, which is respected when using flex.
Give the #left div a min-width of 200px, should do the job.
Remove the width on .container > div and use flex: auto; on #main: fiddle
#main {
flex: auto;
background: lightblue;
-webkit-order: 2;
order: 2;
}
Also (if nothing from above works)
Check your min-width and max-width.
It fixed the same problem for me by increasing their range.
add display: contents on the element or div you want to maintain the width.
Solved this with a flex not respecting min-width when there was not enough content to fill that width.
Added the CSS rule box-sizing: initial; on the same flex element that had the non-working min-width declaration.
Add display:inline-block; in left class

Limit the height of a responsive image with css

My end goal is to have a fluid <img> that won't expand past an explicitly set height of a parent/grandparent element using only css.
Currently I'm doing this with a normal (max-width:100; height:auto;) fluid image and javascript by reading the height/width attributes from the img tag, calculating the aspect ratio, calculating the correct width of the image at the desired height restriction, and applying that width as a max-width on the image's container element. Pretty simple, but I'd love to be able to do it without javascript.
height:100%; width:auto; doesn't work the same as its transverse, and I've made some attempts with Unc Dave's ol' padded box and absolute positioning that function but require knowing the aspect ratio of the image beforehand and therefore cannot be applied across images that have different proportions. So the final requirement is the css must be proportion agnostic.
I know, I know, the answer to this question is probably sitting next to the unicorn farm, but I thought I'd throw it out there anyways.
The trick is to add both max-height: 100%; and max-width: 100%; to .container img. Example CSS:
.container {
width: 300px;
border: dashed blue 1px;
}
.container img {
max-height: 100%;
max-width: 100%;
}
In this way, you can vary the specified width of .container in whatever way you want (200px or 10% for example), and the image will be no larger than its natural dimensions. (You could specify pixels instead of 100% if you didn't want to rely on the natural size of the image.)
Here's the whole fiddle: http://jsfiddle.net/KatieK/Su28P/1/
I set the below 3 styles to my img tag
max-height: 500px;
height: 70%;
width: auto;
What it does that for desktop screen img doesn't grow beyond 500px but for small mobile screens, it will shrink to 70% of the outer container. Works like a charm.
It also works width property.
You can use inline styling to limit the height:
<img src="" class="img-responsive" alt="" style="max-height: 400px;">

CSS display: table min-height not working

Does anyone know I can make min-height work with the latest browsers? I am using CSS tables and it seems to ignore min-height.
<div style="background-color: red; display: table; min-height: 100px;">
abc
</div>
Fiddle
When using tables, height essentially is min-height, as tables always stretch. Just get rid of the "min-" and it will work as you expect.
Use height: 1px; on the table or any value. Basically you need to give table some height to make it work with min-height. Having only min-height won't work on tables on firefox.
Solution for Firefox
Add height to unlock setting the min-height
div {
display: table;
width: 100%;
height: 0;
min-height: 100px;
}
The number in height can be any other real value less or equal to min-height for making it work as expected.
Whenever you are using display:table; or any deeper property like display:table-cell; consider using height instead of min-height. As in tables height = min-height considering the auto-span feature in them.

CSS: Can you prevent overflow: hidden from cutting-off the last line of text?

When using CSS overflow: hidden , I've often found that the last line of text gets partially cut-off. Is there a way to prevent this so that any partial lines do not show-up. Almost like a vertical word-wrap.
You can use wrapper div and multi-column css:
.wrapper {
-webkit-column-width: 150px; //You can't use 100%
column-width: 150px;
height: 100%;
}
Solution example: http://jsfiddle.net/4Fpq2/9/
Update 2017-09-21
In Firefox this solution still works but broken in Chrome. Recently Chrome started break column by small parts, also stop break content if you set height.
In this http://jsfiddle.net/4Fpq2/446/ example, I change hight to max-height and show strange Chrome behavior.
If you have ideas please write in comments.
Update 2019-03-25
Basically, it's work even for Chrome but you should have at least two lines. For a block with some amount of visible text this approach still should work fine.
http://jsfiddle.net/ncmo9yge/
Once you understand how the column-width work, #stalkerg's answer makes a lot of sense.
The column-width splits the content in columns, so the last line of the text would not fit, it will be moved to the next column. Now the trick is to make the column-width as wide as the container. The container has overflow: hidden, so the 2nd column won't show.
.box {
width: 200px;
}
.container {
-webkit-column-width: 200vw;
-moz-column-width: 200vw;
column-width: 200vw;
height: 100%;
}
This solution worked for me: https://stackoverflow.com/a/17413577/2540428
Essentially create a wrapper div with the appropriate padding and put the content in the main div where you edit its height and hide the overflow. See link for more details.
Rob is correct. I was making a div that had a max-height of 11em and the last line of overflow text was only half there. white-space: nowrap just eliminates that last line all together.
I tried
white-space: nowrap;
and Gaby is also correct that this causes problems too.
The best I came up with was to fiddle with the line-height and div height until the fewest lines were cut-off
that worked for me:
.wrapper_container{
width: 300px;
height: 200px;
overflow: hidden;
}
.wrapper{
-webkit-column-width: 300px;
column-width: 300px;
height: 100%;
}
There are two css3 property exist. 1) word-break & 2) word-arap
Don't forget these are new property that is css3. So that older browsers do not support such property.
.class-name {word-break: break-all;}
.class-name {word-wrap: break-word;}
just add column-width attribute and set width of the container, it will work.
just use the border instead of padding.

Resources