CSS: allow a container to grow in increments only - html

I want to grow a container, but only when there is enough space to add a new element. Say my elements are 100px, this would mean the acceptable widths for my container would be 120, 230, 340, and so on.
Although I am demoing flex and margin-right: auto, I do not want the margins between the objects to be variable. I want only about 10 pixels between objects. I'm ok with there being a variable horizontal buffer for the container, if that is a solution.
I'm not certain I can do this using flex, so if there's a better way, I'd be grateful.
.container {
display: flex;
flex-wrap: wrap;
border: 3px solid rgb(0, 0, 0);
}
.panel {
height: 100px;
width: 100px;
border: 3px solid rgb(255, 0, 0);
margin: 10px 0px 0px 10px;
}
<div class="container">
<div class="panel"></div>
<div class="panel"></div>
<div class="panel"></div>
<div class="panel"></div>
</div>

There is the CSS code for the container element :
(added width: fit-content with a padding.)
.container {
display: flex;
flex-wrap: wrap;
width: fit-content;
border: 3px solid rgb(0, 0, 0);
padding : .5rem .5rem;
}

Related

Make one flex-item take more height than the others after they wrap

I have a hero section divided in two parts. One is mainly decorative and the other has more text and elements. I want to have it divided in two columns when the screen is wide enough and wrap when the screen gets too small. So far I have accomplished this. However once the items wrap they both use 50% of the parent's height. I want one of them to shrink to the size of it's elements while the other grows to use the reminder of the parent height.
Here is a working example:
.hero {
display: flex;
flex-wrap: wrap;
height: 500px;
}
.hero .item {
flex-basis: 40%;
min-width: 300px;
}
/*PURELY DECORATIVE*/
.hero {
background-color: hsla(0, 100%, 50%, 0.5);
padding: 10px;
border: 2px dotted red;
}
.item1 {
background-color: hsla(120, 100%, 50%, 0.5);
padding: 10px;
border: 2px dotted green;
}
.item2 {
background-color: hsla(240, 100%, 50%, 0.5);
padding: 10px;
border: 2px dotted blue;
}
<section class="hero">
<div class="item item1">Item1. Should be short when wrapped</div>
<div class="item item2">Item2. Should take all available height when wrapped.</div>
</section>
The closest I've got to a solution, whithout adding a media query, is adding the align-content: flex-start property to the flex container and then give height: 100% to the desired item. However this causes overflow once the items wrap.
You can try with CSS grid
.hero {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(300px,100%), 40%));
grid-template-rows: auto; /* first row auto */
grid-auto-rows: 1fr; /* when there is a second row it will take the remaining space */
height: 500px;
}
/*PURELY DECORATIVE*/
.hero {
background-color: hsla(0, 100%, 50%, 0.5);
padding: 10px;
border: 2px dotted red;
}
.item1 {
background-color: hsla(120, 100%, 50%, 0.5);
padding: 10px;
border: 2px dotted green;
}
.item2 {
background-color: hsla(240, 100%, 50%, 0.5);
padding: 10px;
border: 2px dotted blue;
}
<section class="hero">
<div class="item item1">Item1. Should be short when wrapped</div>
<div class="item item2">Item2. Should take all available height when wrapped.</div>
</section>

gaps in background color of parent in childs element

I try to make parent div - background color, rounded corners and overflow hidden,
put inside child div with background color, but I see small gap of parent color.
How can it be and how to fix this?
the main task is not to change the HTML
here code
https://codepen.io/batareika007/pen/ZERWmBM
.container {
max-width: 300px;
margin: 0 auto;
}
.parent {
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
overflow: hidden;
border-radius: 1rem;
height: 100px;
background: red;
}
.child {
padding: 1rem;
height: 50px;
background: rgb(230, 230, 230);
/* if you make background white, you see the gap more clearly */
/* background: white; */
}
<div class="container">
<div class="parent">
<div class="child">some content here</div>
</div>
</div>
tried position, z-index, play with the borders...
Adding height or padding to the parent element causes this issue to happen.
I'm not sure if this is problem with chrome's engine or just a bug.
Here's a hacky solution.
Remove overflow: hidden from the parent.
Add a box-shadow with the same background-color as the child to the child.
Offset the box-shadow down a bit.
And finaly add border-radius to the child.
.container{
max-width: 300px;
margin: 0 auto;
}
.parent{
width:100%;
display:flex;
flex-direction:column;
justify-content: flex-end;
border-radius: 1rem;
height: 100px;
background: red;
}
.child{
padding: 1rem;
height: 50px;
background: rgb(230, 230, 230);
border-radius: 0 0 1rem 1rem;
box-shadow: 0 2px 0 rgb(230 230 230);
/* if you make background white, you see the gap more clearly */
/* background: white; */
}
<div class="container">
<div class="parent">
<div class="child">some content here</div>
</div>
</div>
I replaced the child's bottom padding with the parent's bottom border.
Now you can change the height of the child, but you'd also need to adapt the height of the parent.
.container {
max-width: 300px;
margin: 0 auto;
}
.parent {
width: 100%;
height: calc(100px - 1rem);
display: flex;
flex-direction: column;
justify-content: flex-end;
overflow: hidden;
border-radius: 1rem;
border-bottom: 1rem solid rgb(230, 230, 230);
background: red;
}
.child {
height: 50px;
padding: 1rem 1rem 0 1rem;
background: rgb(230, 230, 230);
/* if you make background white, you see the gap more clearly */
/* background: white; */
}
<div class="container">
<div class="parent">
<div class="child">some content here</div>
</div>
</div>

Flex container with 3 columns, 100% height, and fixed-width side columns

I have a 3-column body with fixed width on the sides and the middle column filling the remaining width.
I need however to make all columns fill the entire height of the page.
I set the height of all parents to height: 100% and I don't want to use a workaround with huge margin or padding, as I'm using a scroll-bar.
#container {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
height: 100%;
}
.col-side {
width: 240px;
height: 100%;
}
#col1 {
border-right: 2px solid rgba(0, 0, 0, 0.12);
}
#col3 {
border-left: 2px solid rgba(0, 0, 0, 0.12);
}
<div id="container">
<div class="col-side" id="col1">
Left
</div>
<div class="col" id="col2">
Center
</div>
<div class="col-side" id="col3">
Right
</div>
</div>
Small demo can be found here:
https://jsfiddle.net/ysn3q6aL/#&togetherjs=H9pEenhcqQ
When you create a flex container (display: flex or display: inline-flex), it automatically applies flex-direction: row and align-items: stretch (among other initial settings).
These default settings line up flex items in a row and give them each the full height of the container. However, if you set a height on a flex item, it overrides align-items. So remove any heights you've set on the items.
This should work for you:
#container {
display: flex;
justify-content: space-between;
height: 100vh;
}
.col-side {
flex: 0 0 240px;
}
#col2 { flex: 1; }
#container > div + div {
border-left: 2px solid rgba(0, 0, 0, 0.12);
}
#col1 { background-color: lightgreen; }
#col2 { background-color: tomato; }
#col3 { background-color: aqua; }
body { margin: 0; }
<div id="container">
<div class="col-side" id="col1">Left</div>
<div class="col" id="col2">Center</div>
<div class="col-side" id="col3">Right</div>
</div>
.col-side{
width: 240px;
height: 100%;
flex: 1 1 0;
}
might help. I was asking the same some time before, the flex: 1 1 0 part helped.
the defaults are 0 1 auto. The first param is flex grow, so you want them all to grow to the same height.
https://css-tricks.com/snippets/css/a-guide-to-flexbox/#article-header-id-13
Set the container height to 100vh.
That's all
#container{
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
height:100vh;
}
.col-side{
width: 240px;
height: 100%;
}
#col1{
border-right: 2px solid rgba(0, 0, 0, 0.12);
}
#col3{
border-left: 2px solid rgba(0, 0, 0, 0.12);
}

Make first element full width and the rest in one line [duplicate]

This question already has answers here:
First-child full-width in Flexbox
(4 answers)
Closed 5 years ago.
I'm trying to create a kind of sub-grid which looks like this:
The first element should be full width and the rest have to be in the same line (same width each one) no matter how many items are present.
My attempt:
HTML
<div class="flex-container">
<div class="flex-item">I'm the biggest!</div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
</div>
CSS
.flex-container {
display: flex;
flex-wrap: wrap;
}
.flex-container .flex-item {
flex: 1;
}
.flex-container .flex-item:first-child {
width: 100%;
}
I'm a newbie in flex, so, in my newbie abstraction, in theory this should work, but it doesn't. It makes all the .flex-item being in the same line with the same width (which I want to happen but only with the :not(:first-child) flex dudes).
This will try to keep all your subordinate items on one row.
See notes in CSS
.flex-container {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.flex-container .flex-item {
background-color: #d94a6a;
flex: 1 1 0; /* for 2nd line to not wrap */
margin: 0 1px;
overflow: hidden; /* for 2nd line to not wrap */
min-height: 75px;
text-align: center;
-webkit-box-shadow: 4px 4px 7px 0px rgba(50, 50, 50, 0.5);
-moz-box-shadow: 4px 4px 7px 0px rgba(50, 50, 50, 0.5);
box-shadow: 4px 4px 7px 0px rgba(50, 50, 50, 0.5);
}
.flex-container .flex-item:nth-child(1) {
background-color: #3b5bb2;
flex-basis: 100%; /* make first take full width */
min-height: 400px;
margin-bottom: 20px;
}
<div class="flex-container">
<div class="flex-item">I'm the biggest!</div>
<div class="flex-item">#2</div>
<div class="flex-item">#3</div>
<div class="flex-item">#4</div>
<div class="flex-item">#5</div>
<div class="flex-item">#6</div>
<div class="flex-item">#7</div>
</div>

Flex basis 100% in column flexbox: full height in Firefox, not in Chrome

I would like a column of divs, of any number, each with width 100% and height 100% of their parent div, so one is visible initially, and the others overflow the parent downwards. I've set the divs to have flex: 0 0 100%;, inside a parent div with display: flex and flex-direction: column to achieve this.
The parent div is itself of unknown height, so it is also a child of a display: flex and flex-direction: column, set to flex: 1 0 0 to take remaining space in its container.
In Firefox the output is as I would like it:
However, not in Chrome:
How can I achieve the Firefox style in Chrome, without Javascript?
You can see this in action at http://plnkr.co/edit/WnAcmwAPnFaAhqqtwhLL?p=preview, as well as the corresponding version with flex-direction: row, which works consistently in both Firefox and Chrome.
For reference, the full CSS
.wrapper {
display: flex;
flex-direction: column;
height: 150px;
width: 200px;
border: 4px solid green;
margin-bottom: 20px;
}
.column-parent {
flex: 1 0 0;
display: flex;
flex-direction: column;
border: 2px solid blue;
}
.column-child {
flex: 0 0 100%;
border: 2px solid red;
}
and HTML
<div class="wrapper">
<p>Some content of unknown size</p>
<div class="column-parent">
<div class="column-child">
Should be inside green
</div>
<div class="column-child">
Should be outside green
</div>
</div>
</div>
This seems to be a bug with Chrome. Similar to the ones reported here (issue 428049) and perhaps related to (issue 346275).
This says:
- Browsers are supposed to resolve percentages on the flex item's child, *if* its flex-basis is definite.
- Gecko is *always* resolving percentages regardless of the flex-basis.
- Chrome is *never* resolving percentages, regardless of the flex-basis.
Summarily, Chrome is not resolving percent heights on flex-item's child (even if the child itself is a flex-item), while all other browsers do.
This can be demonstrated in the below snippet: (Fiddle here)
* { box-sizing: border-box; margin: 0; padding: 0; }
div.wrap {
height: 120px; width: 240px; margin: 0px 12px;
border: 1px solid blue; float: left;
display: flex; flex-direction: column;
}
div.parent {
flex: 0 0 100%;
border: 1px solid green;
display: flex; flex-direction: column;
}
div.item {
flex: 0 0 100%;
border: 1px solid red;
}
<div class="wrap">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c</div>
</div>
<div class="wrap">
<div class="parent">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c</div>
</div>
</div>
The second div should show the same behaviour as the first one. Other browsers (IE11, Edge, FF39) show it correctly. Chrome fails here and does not resolve div.item correctly. It needs a fixed height on its parent, without which it uses min-content as its height and thus does not overflow.
Whereas, in the first div, the div.items are correctly resolved and overflow accordingly. This is because there is a fixed height on the parent (i.e. div.wrap)
Possible Solution:
As a workaround, if you are sure to have only two elements (p and div) inside your wrapper, then you could give them a 50% height. You have to provide a height:50% to your .column-parent. Chrome needs a fixed height on parent as demonstrated above.
Then everything will work as you need to.
Demo Fiddle: http://jsfiddle.net/abhitalks/kqncm65n/
Relevant CSS:
.wrapper > p { flex: 0 0 50%; } /* this can be on flex-basis */
.column-parent {
flex: 1 0 auto; height: 50%; /* but, this needs to be fixed height */
display: flex; flex-direction: column;
border: 2px solid blue;
}
.column-child {
flex: 0 0 100%; /* this flex-basis is then enough */
border: 2px solid red;
}
PS: There also seem to be differences in the way jsfiddle and plnkr render. I don't know why, but sometimes I get different results!
As stated in Abhitalks response, there is a bug (or a different interpretation of the standard) in the way Chrome handles the height attribute here.
I have found a hack that is working both in Chrome FF and IE
The only issue is that you ned to have as many rules as posible children there are.
The trick is to set the flex-direction to row, set the flex-basis (that is now the width) to 100%, and then translate the elements
.container {
border: solid 2px blue;
height: 200px;
width: 200px;
display: flex;
flex-direction: column;
position: relative;
}
.filler {
border: solid 1px black;
flex: 0 0 80px;
background-color: lightgreen;
transition: flex 1s;
}
.container:hover .filler {
flex: 0 0 40px;
}
.test {
border: solid 1px red;
flex: 1 0 25px;
display: flex;
flex-direction: row;
position: relative;
}
.child {
background-color: rgba(200, 0, 0, 0.26);
flex: 0 0 100%;
}
.child:nth-child(2) {
background-color: rgba(255, 255, 0, 0.48);
transform: translateX(-100%) translateY(100%);
}
.child:nth-child(3) {
background-color: rgba(173, 216, 230, 0.28);
transform: translateX(-200%) translateY(200%);
}
<div class="container">
<div class="filler"></div>
<div class="filler"></div>
<div class="test">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
</div>
</div>
If there could be another child, you would need a nth-child(4) rule, and so on
I have added an hover effect to check how the size adapts
My previous answer is a hack that exploits a particular setup of the layout wanted.
An alternate way, more general, of getting around this Chrome bug is to use an intermediate element in the layout, and set this element size using top: 0px and bottom: 0px. (instead of height: 100%) There is still a bug in the way Chrome handles the calculus, that needs a fake animation to make it adjust properly
.container {
border: solid 2px blue;
height: 200px;
width: 200px;
display: flex;
flex-direction: column;
position: relative;
}
.filler {
border: solid 1px black;
flex: 0 0 94px;
background-color: lightgreen;
transition: 1s;
}
.container:hover .filler {
flex: 0 0 50px;
}
.test {
border: solid 1px red;
flex: 1 0 25px;
display: flex;
flex-direction: row;
position: relative;
}
#-webkit-keyframes adjust2 {
0% {flex-basis: 100%;}
100% {flex-basis: 100.1%;}
}
.child {
background-color: rgba(200, 0, 0, 0.26);
width: 100%;
height: 100%;
flex: 1 0 100%;
-webkit-animation: adjust2 1s infinite; /* only needed for webkit bug */
}
.intermediate {
width: 100%;
position: absolute;
top: 0px;
bottom: 0px;
display: flex;
flex-direction: column;
}
.child:nth-child(n+2) {
background-color: rgba(255, 255, 0, 0.48);
}
.child:nth-child(n+3) {
background-color: rgba(173, 216, 230, 0.28);
}
<div class="container">
<div class="filler"></div>
<div class="test">
<div class="intermediate">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
</div>
</div>
What about adding 100% to the container:
.column-parent {
flex: 1 0 100%;
}
And flex-grow to 1 in the contained element without adjusting the flex basis:
.column-child {
flex: 1 0 0;
}
Here's how it would look: http://plnkr.co/edit/H25NQxLtbi65oaltNVax?p=preview