CSS Flex: first child stretch, other children wrap - html

I'm trying to achieve this result, using css only: I have a container with a bunch of children inside. I would like the first child to stretch vertically and having the other children to wrap beside the first child.
expected result
this is the code:
.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
align-content: center;
width: 350px;
border: 1px solid;
}
.container div {
min-height: 30px;
width: 100px;
background: green;
margin: 3px;
}
.container div:first-child {
background: red;
align-self: stretch;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
this is how it looks
But apparently it is not possible with flexbox. Is there any other solutions?
I know I can achieve this by taking the first child out of the container and treat it separately. But I was wondering if I could do it without changing the markup?
Thank you all!

You need CSS grid for this. Resize the container to see the result:
.container {
display: grid;
grid-template-columns: repeat(auto-fit,100px); /* width of your element */
width: 350px;
border: 1px solid;
/* resize the container*/
overflow: auto;
resize: horizontal;
}
.container div {
min-height: 30px;
background: green;
margin: 3px;
}
.container div:first-child {
background: red;
grid-area:1/1/span 200; /* 1s row/1st column/ take many rows (stretch)*/
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
position: absolute can also do the job since the width is fixed:
.container {
display: flex;
flex-wrap: wrap;
padding-left: 106px;
width: 350px;
border: 1px solid;
position: relative;
/* resize the container*/
overflow: auto;
resize: horizontal;
}
.container div {
min-height: 30px;
width: 100px;
background: green;
margin: 3px;
}
.container div:first-child {
background: red;
position: absolute;
inset: 0 auto 0 0;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>

Related

CSS Flexbox with Margin Spacing Causing Unwanted Stretch of Items

I've got a flexbox. There are 4 circles that are 25% width of the parent element. I added margin between the items but now the circles "stretch" because of my padding %. I'd like to keep the padding as a % to maintain an aspect ratio I require. But when I add margin to create spacing between the items stretch.
.items {
display: flex;
flex-wrap: wrap;
}
.items>* {
flex: 1;
flex-basis: 25%;
}
.items>*:after {
content: '';
display: block;
background: #000;
margin: 5px;
padding-bottom: 100%;
border-radius: 50%;
}
<div class="items">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
The shape I want, but not the spacing:
The spacing I want, but not the shape:
Also, the reason I use margin is to have equal spacing all around the element in the case there are rows of elements.
How do I get the spacing and shape I want together?
Insert a gap in your flex element, then remove the padding and margin for the pseudoelement (::after) and use aspect-ratio
.items {
display: flex;
flex-wrap: nowrap;
gap: 20px;
}
.items > * {
flex: 1;
flex-basis: 25%;
}
.items > *::after {
content: '';
display: block;
background: #000;
aspect-ratio: 1;
border-radius: 50%;
}
<div class="items">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
Why not remove the margin from the :after pseudo element and use padding on the main element? (also added box-sizing on main element):
.items {
display: flex;
flex-wrap: wrap;
}
.items>* {
flex: 1;
flex-basis: 25%;
padding: 5px;
box-sizing: border-box;
}
.items>*:after {
content: '';
display: block;
background: #000;
padding-bottom: 100%;
border-radius: 100%;
}
<div class="items">
<div></div>
<div></div>
<div></div>
<div></div>
</div>

Horizontally distribute elements of varied width while keeping the middle item centered

I am trying to find a way to distribute an uneven number of elements across the horizontal axis that satisfies the following:
the left border of the first child overlaps the left border of the container
the right border of the last child overlaps the right border of the container
uneven number of children (that is, there exists a middle item)
the middle item must be properly centered
the remaining items (i.e. items between the first and middle items and between the middle and last items) are evenly distributed
the items can vary in width (no fixed width)
Here is an example of the problem I encounter (4th condition not satisfied) with my current implementation:
#container {
display: flex;
justify-content: space-between;
}
#container > div {
background-color: black;
}
#container > div:nth-child(1) {
width: 100px;
height: 20px;
}
#container > div:nth-child(2) {
width: 80px;
height: 30px;
}
#container > div:nth-child(3) {
width: 50px;
height: 50px;
}
#container > div:nth-child(4) {
width: 40px;
height: 30px;
}
#container > div:nth-child(5) {
width: 90px;
height: 10px;
}
p {
width: 100%;
text-align: center;
}
<div id="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<p>
↑<br>
actual center
</p>
Another possible approach is given here:
#container {
display: flex;
}
#container > div {
flex: 1;
display: flex;
justify-content: center;
}
#container > div > div {
background-color: black;
}
#container > div:nth-child(1) > div {
width: 100px;
height: 20px;
margin-right: auto;
}
#container > div:nth-child(2) > div {
width: 80px;
height: 30px;
}
#container > div:nth-child(3) > div {
width: 50px;
height: 50px;
}
#container > div:nth-child(4) > div {
width: 40px;
height: 30px;
}
#container > div:nth-child(5) > div {
width: 90px;
height: 10px;
margin-left: auto;
}
p {
width: 100%;
text-align: center;
}
<div id="container">
<div><div></div></div>
<div><div></div></div>
<div><div></div></div>
<div><div></div></div>
<div><div></div></div>
</div>
<p>
↑<br>
center
</p>
While aesthetically more pleasing, this is not ideal because the second and fourth divs are centered relative to their given flow space instead of their surrounding space:
By contrast, here is what I am trying to achieve:
One possible solution would be to break the container into three flex children; left, center, and right.
To keep the center anchored, apply flex: 1; to left and right.
To get even space on the last child of left, and the first child of right, you can add an empty block psuedo-element.
#container {
display: flex;
justify-content: space-between;
}
#container>div {
display: flex;
justify-content: space-between;
}
#container>div.left,
#container>div.right {
flex: 1;
}
#container>div.left::after,
#container>div.right::before {
display: block;
content: '';
}
#container>div>div {
background-color: black;
}
#container>div.left>div:nth-child(1) {
width: 100px;
height: 20px;
}
#container>div.left>div:nth-child(2) {
width: 80px;
height: 30px;
}
#container>div.center>div {
width: 50px;
height: 50px;
}
#container>div.right>div:nth-child(1) {
width: 40px;
height: 30px;
}
#container>div.right>div:nth-child(2) {
width: 90px;
height: 10px;
}
p {
width: 100%;
text-align: center;
}
<div id="container">
<div class="left">
<div></div>
<div></div>
</div>
<div class="center">
<div></div>
</div>
<div class="right">
<div></div>
<div></div>
</div>
</div>
<p>
↑<br> actual center
</p>

Create X shape layout using 5 elements

So my task is to align 5 divs to be positioned in an X position:
body{
height:300px;
width: 300px;
}
div{
height:100px;
width:100px;
float:left;
background:black;
overflow: none;
}
div:nth-child(2) {
margin-left: 100px;
}
div:nth-child(3) {
margin-left: 100px;
margin-right: 100px;
}
div:nth-child(5) {
margin-left: 100px;
}
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
As you can see I already aligned them. I can't use any other additional elements, only 5 divs. But I have a feeling that there is a more elegant solution, with less lines of css. Would be nice to see the best solution :)
body {
display: flex;
flex-wrap: wrap;
justify-content: space-between; /* align items to edges, horizontally */
align-content: space-between; /* align items to edges, vertically */
height: 300px;
width: 300px;
}
div {
height: 100px;
width: 100px;
background: black;
}
div:nth-child(2) {
position: relative; /* in-flow positioning */
top: 50%;
transform: translateY(-50%);
}
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
jsFiddle

Height of flex container not working properly in Safari

So I have a flexbox with columns and max-height to make the columns stack next to each other in 3 columns.
This works fine in Chrome, but in Safari it seems to only use the last (rightmost) column to set the actual height of the container.
I've made an example here:
section {
display: flex;
flex-direction: column;
flex-wrap: wrap;
max-height: 400px;
padding: 10px;
border: 1px solid green;
}
div {
flex-basis: 100px;
width: 100px;
background-color: red;
margin: 10px;
}
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
Results in Chrome and Safari are screencapped below.
Chrome:
Safari:
This seems to be an obvious bug, but I can't find any information about it.
What I want to know is:
Are there any workarounds to this? and
Has it been reported as a bug?
As stated in another answer about Safari problems with flexbox, because flex is relatively new (CSS3), not all browsers work as expected. In some browsers, flex layout is partially supported or fully botched, depending on the combination of properties you apply.
In this particular case, Safari simply refuses to acknowledge max-height: 400px on the flex container. However, if the flex container isn't responding, you can get help from the parent.
This is where you are now:
section {
display: flex;
flex-direction: column;
flex-wrap: wrap;
max-height: 400px; /* not working in Safari */
width: 400px;
padding: 10px;
border: 1px solid green;
}
Try this instead:
body {
display: flex;
max-height: 400px;
}
section {
display: flex;
flex-direction: column;
flex-wrap: wrap;
width: 400px;
padding: 10px;
border: 1px solid green;
}
body {
display: flex;
max-height: 400px;
}
section {
display: flex;
flex-direction: column;
flex-wrap: wrap;
width: 400px;
padding: 10px;
border: 1px solid green;
}
div {
height: 100px;
width: 100px;
background-color: red;
margin: 10px;
}
<section>
<div></div>
<div></div>
<div></div>
<div style="height:200px"></div>
<div></div>
<div></div>
<div></div>
</section>
Another thing to keep in mind is that flex layout with column wrap has many bugs. It's possibly the most bug-ridden area in flexbox today. Here are two more examples:
When flexbox items wrap in column mode, container does not grow its width
Flexbox: wrong width calculation when flex-direction: column, flex-wrap: wrap

How can I make a Windows 8 style layout using CSS3?

I am trying to create a Windows 8 'tile'-style layout using HTML with CSS3 and am having some trouble. I drew a little diagram to convey what I am trying to achieve -- the problem is that this layout is very easy to achieve vertically, but not horizontally.
Here is a vertical example:
http://jsfiddle.net/tAdjY/
#container {
width: 320px;
height: 300px;
overflow: scroll;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
flex-flow: column nowrap;
}
#container > section {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
flex-flow: row wrap;
flex: none;
-webkit-flex: none;
/* Safari 6.1+ */
-ms-flex: none;
/* IE 10 */
margin-bottom: 20px;
box-sizing: border-box;
}
#container div {
box-sizing: border-box;
width: 90px;
height: 90px;
margin: 5px;
background: blue;
}
<div id="container">
<section>
<div></div>
<div></div>
</section>
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
</div>
But here, if I try to make it horizontal (same markup, different CSS), it gets smushed:
http://jsfiddle.net/tAdjY/1/
#container {
width: 320px;
height: 320px;
overflow: scroll;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row nowrap;
flex-flow: row nowrap;
}
#container > section {
display: flex;
-webkit-flex-flow: column wrap;
flex-flow: column wrap;
box-sizing: border-box;
margin-right: 20px;
}
#container div {
box-sizing: border-box;
width: 90px;
height: 90px;
margin: 5px;
background: blue;
}
<div id="container">
<section>
<div></div>
<div></div>
</section>
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
</div>
I don't know if there's a real solution for this or if flexbox is just limited, but I look forward to any decent answers. Thanks!