I have a variable number of divs, which should be displayed on two lines, as follows
[1] [3] [5] [7]
[2] [4] [6] ...
I looked at the column-count property, however it's not exactly what I need, as it fixes the number of columns, whereas in my case it should be dynamic. (what I need would be a similar line-count property, which doesn't seeem to exist).
Is there a pure CSS solution, or should I make container divs for every groups of 2 vertical divs?
Thanks,
Edit :
Here is a simplified code of my case. Actually, As I set the height property on my container div, shouldn't the article divs be stacked by at most 2 ? Now they're overflowing the container.
<html>
<head>
<link rel="stylesheet" type="text/css" href="test.css">
</head>
<body>
<div class="container">
<div class="article">A</div>
<div class="article">B</div>
<div class="article">C</div>
<div class="article">D</div>
<div class="article">E</div>
</div>
</body>
</html>
and the CSS
.article {
width:50px;
height:50px;
border:1px gray dashed;
margin:1px;
}
.container {
height:110px;
max-height:110px;
}
However with this code all the article divs are in one column.
You can use the columns css property on a container:
#columns-holder {
-moz-columns: 100px;
-webkit-columns: 100px;
columns: 100px;
-moz-column-gap: 15px;
-webkit-column-gap: 15px;
column-gap: 15px;
}
.box {
width: 100px;
height: 100px;
margin-bottom: 15px;
background: grey;
-webkit-column-break-inside: avoid;
page-break-inside: avoid;
break-inside: avoid;
}
<div id="columns-holder">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
<div class="box">5</div>
<div class="box">6</div>
<div class="box">7</div>
<div class="box">8</div>
<div class="box">9</div>
<div class="box">10</div>
</div>
You can do this using flexbox and flex-direction: column;
Doing so will allow you to have new columns once the bottom of parent element is reached.
Here is an example:
*
{
box-sizing: border-box
}
.flex-parent
{
display: flex;
flex-flow: column wrap;
/* this indicates, when a new "column" will be started */
height: 200px;
align-content: flex-start;
}
.flex-parent .col
{
flex: 0 0 auto;
width: 100px;
height: 50px;
background-color: silver;
margin: 4px;
}
<div class="flex-parent">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
<div class="col">6</div>
<div class="col">7</div>
<div class="col">8</div>
<div class="col">10</div>
<div class="col">11</div>
<div class="col">12</div>
</div>
When I have to do something like this i use float property with a code like this to be applied to each div you want to display:
.divclass{
float: left;
margin: 10px;
width: 300px;
}
don't forget to clear float after the list of divs:
<br stytle="clear: both;">
With this structure I get to put as many divs as they can fit on the screen width and to put the others on a new line. Obviously the number of divs on each row will be dependent on the screen width or container div width.
Can help you a bit more if you provide more code of yours.
For Column-count
With a simple list mark up
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
<ul>
Use this CSS:
ul {
-moz-column-count: 2;
-moz-column-gap: 20px;
-webkit-column-count: 2;
-webkit-column-gap: 20px;
column-count: 2;
column-gap: 20px;
}
Another option is CSS3 as below:
CSS3 solution would look like this:
HTML
<div id="wrap">
<div class="list_item">A</div>
<div class="list_item">B</div>
<div class="list_item">C</div>
<div class="list_item">D</div>
<div class="list_item">E</div>
<div class="list_item">F</div>
<div class="list_item">G</div>
<div class="list_item">H</div>
</div>
CSS:
.list_item {
float: left;
margin: 5px;
padding: 5px;
width: 200px;
border: 1px solid gray;
}
#wrap {
width:460px;
column-count:2;
column-gap:20px;
-moz-column-count:2;
-moz-column-gap:20px;
-webkit-column-count:2;
-webkit-column-gap:20px;
}
you can see more details at here
Here is an example of a grid where the elements will be 4 elements on each row.
You can adjust the size of the .container element to what you want. If you don't want to support vw units.
Why widht:22%;?
The logical way would be to set width:25% right if we want 4 elements? 4x25=100.
Try to edit the code below to that :)
As you see it will wrap to a new line.
Setting it slightly less 23% or 22% I went with 22%.
Now you have some space for border margins and paddings.
If you want them to fit perfectly next to one an other.
set the box-sizing: borderbox. and 0 margin 0 padding (and no white space)
and a width of 25%. Should get you close to a perfect fit.
.container {
width: 50vw;
border: 5px solid pink;
}
.container .item {
display: inline-block;
border: 2px solid firebrick;
width: 22%;
height: 50px;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Related
I get a list using the CSS display: grid as shown below
My task has to be edited so that the list will look like this when it is displayed on PC, while on my mobile it will look like the first image.
The first 3 elements will be larger than the rest.
And responsive support
Here is my code:
HTML:
.grid {
width: 638px;
display: grid;
grid-row-gap: 68px;
grid-column-gap: 12px;
grid-template-rows: auto auto;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
justify-content: space-between;
}
.item {
border: 3px solid green;
width: auto;
height: 150px;
}
<div class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
I tried to fix it but it doesn't work like, thanks everyone!
you may rethink it from a 12 columns grid and reset grid-column spanning to the item.
possible example
.grid {
width: 638px;
display: grid;
grid-row-gap: 68px;
grid-column-gap: 12px;
grid-template-rows: auto auto;
grid-template-columns: repeat(auto-fit, minmax(35px, 1fr));/* 35 x 4 = 140 */
justify-content: space-between;
}
.item {
border: 3px solid #4285F4;
border-radius:3px;
width: auto;
height: 150px;
grid-column:auto / span 4; /* about 35px X 4 of width */
margin-right:8px;
}
.item:nth-child(3), .item:nth-child(3)~.item {
margin-right:0;
}
.item:nth-child(3)~.item {
grid-column:auto / span 3;
}
<div class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
spanning columns rules and grid-template-columns can be reset via the mediaquerie your want to use.
You have to use a number that contains 3 and 4 as multiplicator. For example 12. So You divide the grid into 12 columns. Then you use nth-child pseudo selctor to selct the first 3 and give them a span of 4 and every other child a span of 3.
with :nth-child(-n+3) you select the first 3 elements. As you want them to be 3 boxes in one row the need to span 4 to fit the 12 columns.
with :nth-child(n+3) you select all element with exeption of the first 3. Now you need to let them span 3 columns to fit 4 boxes within the 12 column wide row.
.grid {
width: 638px;
display: grid;
grid-row-gap: 68px;
grid-column-gap: 12px;
grid-template-rows: auto;
grid-template-columns: repeat(12, 1fr);
}
.item {
border: 3px solid green;
height: 150px;
}
.item:nth-child(n+3) {
grid-column: span 3;
}
.item:nth-child(-n+3) {
grid-column: span 4;
}
<div class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
I am trying to have an angular component that can dynamically position and resize div elements depending on how many div elements are to be displayed. This is what I have achieved so far.
EDIT: If you checkout my stackblitz example I am using display: flex
(thus flexbox). The issue I am having is how can I make sure that a
row will at most only have 3 divs and then wrap to the next line and
that the divs length will always be the same?
.
EDIT 2: My goal is that when there is one or two divs the length of
the div is half that of the container. That is why I put a 'ruler' at
the top in the image below. If there are more than 2 divs the length
of the divs should be 1/3 of the length of the container. And a row
should be filled by three divs before wrapping to the next row.
Below is a visual representation of what I am trying to achieve:
All the divs in a particular set are of the same width and height.
I see how I can hack around by using calc() in width but then I will have to pass the number of divs variable to my css file. Also I am aware that using Multiple conditions in ngClass - Angular 4 is an option, but I would like to use that if I did not have any other option.
How can I achieve what I am trying to achieve with css only (if possible)? If it is not possible to use css only I will gladly take any other recommendation.
First make flex container with
.container1 {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
Second use calc() to specify items width
.item {
width: calc(33.33% - 0px);
}
Third specify first and second child behavior. They should grow, but max-width: 50%
.item:first-child, .item:nth-child(2) {
flex-grow: 1;
max-width: 50%;
}
.container1 {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
outline: dashed red 1px;
margin: 10px 0
}
.item {
height: 100px;
background-color: green;
outline: 1px dashed blue;
width: calc(33.33% - 0px);
}
.item:first-child, .item:nth-child(2) {
flex-grow: 1;
max-width: 50%;
}
<div class="container1">
<div class="item"></div>
</div>
<div class="container1">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="container1">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="container1">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="container1">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="container1">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="container1">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="container1">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Checkout sample working copy Check the flex will slove the above issues i guess.
.parent {
display:flex;
justify-content:space-around;
flex-wrap:wrap;
}
.option-box{
width:40%;
border: 1px blue solid;
margin: 3px
}
#media screen and (max-width: 600px) and (min-width: 301px) {
.option-box {
width:30%;
}
}
#media screen and (max-width: 300px) {
.option-box {
width:100%;
}
}
I want to make flexbox with responsive to content items.
Here is example code:
HTML:
.container {
width: 200px;
height: 400px;
display: flex;
flex-flow: row wrap;
}
.item {
flex-basis: 40px;
background-color: orange;
margin: 0 10px 10px 0;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item">this is text content and again and again this is text content and again and again</div>
</div>
And this is what I want to achieve:
How can I achieve that behavior? Thanks!)
If you want your page to be responsive to different resolution then u shouldn't adopt the habit of defining height and width in terms of px.
instead try to put width and height interms of % , width defined in % tend to adjust with resolution but width defined in terms of px tend to remain static and insensitive to changing resolution.
try this instead,
.container {
width: 800px;
height: 400px;
display: flex;
flex-flow: row wrap;
}
.item {
flex-basis: 25%;
background-color: orange;
margin: 0 10px 10px 0;
height: 50%;
}
.items {
flex-basis: 51%;
background-color: orange;
margin: 0 10px 10px 0;
height: 50%;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="items">this is text content and again and again this is text content and again and again</div>
<div class="item"></div>
</div>
This Works fine. All the best
Any reason you have a strong attachment to flexbox? This would be super easy using the bootstrap grid. (I see you have the container class, so you likely already have bootstrap installed)
<div class="container">
<div class="item col-md-3"></div>
<div class="item col-md-3 col-md-offset-1"></div>
<div class="item col-md-3 col-md-offset-1"></div>
<div class="item col-md-3"></div>
<div class="item col-md-3 col-md-offset-1"></div>
<div class="item col-md-3 col-md-offset-1"></div>
<div class="item col-md-6">this is text content and again and again this is text content and again and again</div>
<div class="item col-md-3 col-md-offset-1"></div>
</div>
If you're not into using bootstrap, CSS3 now has a native grid layout which should also suit your purpose.
In your situation, I think this would be the way to go. Flexbox is a great layout, but it's meant more for dynamic displays where you don't need precise control over the size/dimension of the items.
You can add a class, let's say extra.
And add assign property of max-width:max-content; to it.
.container {
display: flex;
width: 300px;
height: 300px;
flex-wrap: wrap;
border: 2px solid red;
}
.item {
flex: 1;
min-width: calc(100px - 10px);
max-width: calc(100px - 10px);
height: calc(100px - 10px);
margin: 5px;
background: green;
}
.extra {
max-width: max-content !important;
max-width: -moz-fit-content !important;
color: white;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item extra">this is extra text and expands</div>
<div class="item"></div>
</div>
.page {
width: 90% margin: auto;
}
.row-container {
width: 100%;
display: flex;
}
.item-container {
flex: 1;
padding: 16px;
}
.item-container-2x {
flex: 2;
}
.item {
background-color: #e7e8e9;
height: 50px;
border: 1px solid #dddddd;
}
<div class="page">
<div class="row-container">
<div class="item-container">
<div class="item"></div>
</div>
<div class="item-container">
<div class="item"></div>
</div>
<div class="item-container">
<div class="item"></div>
</div>
</div>
<div class="row-container">
<div class="item-container item-container-2x">
<div class="item"></div>
</div>
<div class="item-container">
<div class="item"></div>
</div>
</div>
</div>
The issue here is with the paddings. It causes the grid on the second row to be misaligned.
I'm using flex: 1; for the equal width grid items, and flex: 2; next to one with flex: 1; for the second row. My understanding is that the flex numbers add up. I'm trying to add them up to 3, but in the second row, having only one margin between the two grid items is impacting to spacing. I'm not sure if this approach is better than defining variable widths for the gird items, but using flex seems simple to me.
I think there's also a problem that I'm using fixed paddings of 16px with the variable width withflex: 1/2. I did try percentage margin and still had the same problem. And I'm having a hard time getting my head around needing to use a combination of padding and margin, and maybe even negative margin.
Thanks for any help.
When using padding on a flex item, Flexbox has a somewhat more complicated way of calculating the space left, which makes it a little more tricky to make that work.
In this case, and to keep using flex-grow for sizing, using margin on the flex item's child (item) would be simpler. It will give the same output as padding does on a parent, with a non-flex child.
Stack snippet
.page {
width: 90%;
margin: auto;
}
.row-container {
width: 100%;
display: flex;
}
.item-container {
flex: 1;
}
.item-container-2x {
flex: 2;
}
.item {
background-color: #e7e8e9;
height: 50px;
border: 1px solid #dddddd;
margin: 16px; /* moved from ".item-container" and changed to "margin" */
}
<div class="page">
<div class="row-container">
<div class="item-container">
<div class="item"></div>
</div>
<div class="item-container">
<div class="item"></div>
</div>
<div class="item-container">
<div class="item"></div>
</div>
</div>
<div class="row-container">
<div class="item-container item-container-2x">
<div class="item"></div>
</div>
<div class="item-container">
<div class="item"></div>
</div>
</div>
</div>
If you need, or have, to use padding on the flex items, you need to compensate for the removed item's padding (16px on each side), and add it as an initial flex-basis on the spanned item.
Stack snippet
.page {
width: 90%;
margin: auto;
}
.row-container {
width: 100%;
display: flex;
}
.item-container {
flex: 1;
padding: 16px;
}
.item-container-2x {
flex: 2 32px; /* changed */
}
.item {
background-color: #e7e8e9;
height: 50px;
border: 1px solid #dddddd;
}
<div class="page">
<div class="row-container">
<div class="item-container">
<div class="item"></div>
</div>
<div class="item-container">
<div class="item"></div>
</div>
<div class="item-container">
<div class="item"></div>
</div>
</div>
<div class="row-container">
<div class="item-container item-container-2x">
<div class="item"></div>
</div>
<div class="item-container">
<div class="item"></div>
</div>
</div>
</div>
In another answer of mine, I made a flex box table version, which might help you further. Check out the "Stack snippet - Flexbox" sample at this link:
Layout a flex box similar to a table?
As a side note, and since you mentioned trying with percent value, that is gonna give you some more issues, which you can read more about here:
Why doesn't percentage padding / margin work on flex items in Firefox?
And here is some more reading about sizing items with flex-grow:
flex-grow not sizing flex items as expected
I have a container with a random number of elements which should always align on the left side. The container width can increase or decrease.
If the container size is increasing then the first element from the row+1 should go one row back and should appear on the right side. But it should only go one row back if it can fit there with a padding on the left and right side.
While the element does not have space one row abouve, then the space between the elements should grow until the element from row+1 can fit in this row.
The same functionality should work also in the reverse way.
Here is my code:
.container {
min-height: 400px;
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-around;
align-items: center;
align-content: flex-start;
}
.container:after {
display: block;
content: " invisible node ";
flex(999 999 auto);
}
.item {
flex: 0 0 auto;
margin: 5px;
width: 50px;
height: 50px;
background-color: green;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
https://jsfiddle.net/p6k537ep/
My Problem ist that in the second row the space between the elements is not the same as in the first row (It depends how many elements are there).
Edit:
But it is working that the elements from the second row can only move one row abouve if they have anough space. The Gap is growing in the correct way in the first row but not in the second one.
AFAIK, this is not solvable in Flexbox without adding invisible non-semantic helper elements to hold the horizontal rhythm of the last row (with the same width and horizontal margins as .items, but zero height).
However, this is easily solvable in CSS Grid, which seems perfect for this:
.container {
min-height: 400px;
display: grid;
grid-template-columns: repeat(auto-fill, 60px);
justify-content: space-around;
align-items: center;
align-content: start;
}
.item {
flex: 0 0 auto;
margin: 5px;
width: 50px;
height: 50px;
background-color: green;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
and kind of solvable with inline-blocks, using the similar pseudo-element hack and some "magic" of the inline formatting:
.container {
min-height: 400px;
text-align: justify;
font-size: 5px;
line-height: 0;
}
.container:after {
display: inline; /* it's important, it should continue the same line! */
/* each character below acts as an invisible placeholder for the item */
/* with em dashes, they would be 1em (5px here) wide each */
content: '— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — ';
letter-spacing: 55px; /* expand each placeholder to the item width */
word-spacing: -56px; /* collapse the whitespaces */
margin-left: 5px;
}
.item {
display: inline-block;
margin: 5px;
width: 50px;
height: 50px;
background-color: green;
vertical-align: top;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
But, honestly, I'd not recommend using the second option in production. Left-aligning the items instead would probably be a better fallback for browsers that don't support Grid.
You could use the margin property on the :after pseudoelement to keep the blocks together.
fiddle
.container {
min-height: 400px;
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-between;
align-items: center;
align-content: flex-start;
}
.container:after {
display: block;
content: " ";
margin-left: auto; /* added */
}
.item {
flex: 0 0 auto;
margin: 5px;
width: 50px;
height: 50px;
background-color: green;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>