How can I auto-flow: column but specify the columns - html

I would like to have a CSS grid that renders the items column by column, where the max number of columns and rows is not assumed. I have below the best version that I was able to come up with, although with some workarounds that I am hoping to not be required:
.grid {
display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(4, 1fr);
}
.item {
margin: 1em;
}
.column {
display: contents;
}
.clear {
grid-row-end: -1;
}
<div class="grid">
<div class="column">
<div class="item">A1</div>
<div class="item">A2</div>
<div class="clear"></div>
</div>
<div class="column">
<div class="item">B1</div>
<div class="item">B2</div>
<div class="item">B3</div>
<div class="clear"></div>
</div>
<div class="column">
<div class="item">C1</div>
<div class="clear"></div>
</div>
</div>
As you can see:
The CSS hard codes the number of rows using grid-template-rows. Removing this will cause items to appear in incorrect columns if there are more items than the hard-coded number of rows, while making the hard-coded number extremely large (e.g., 1000) will work for all practical number of items in a column, but cause a large amount of blank space to be added to the bottom of the document.
There is a "clear" div that I'd rather not need in each column to force the auto-placement to the next column.
Note that just having each column lay itself out (using something like flexbox or CSS Columns) will not work, as it is important that the grid items (which may have varying heights) remain aligned with their horizontal neighbors.

You can easily get rid of the clear element by setting the row of the first element of each column then you can consider the trick of a big number of rows but with auto sizing and not 1fr. You won't have any blank space if you don't use row gaps:
.grid {
display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(1000, auto);
}
.item {
margin: 1em;
}
.column {
display: contents;
}
.column .item:first-child {
grid-row: 1;
}
<div class="grid">
<div class="column">
<div class="item">A1</div>
<div class="item">A2</div>
</div>
<div class="column">
<div class="item">B1</div>
<div class="item">B2</div>
<div class="item">B3</div>
</div>
<div class="column">
<div class="item">C1</div>
</div>
</div>

Related

How to divide divs into rows equally

Apologies if this has been asked before but I couldn't find exactly the same question.
I have the following:
.main{
display: inline-flex;
flex-direction: row;
}
<div class = "main">
<div class="sub-div">1 </div>
<div class="sub-div">2 </div>
<div class="sub-div">3 </div>
<div class="sub-div">4 </div>
<div class="sub-div">5 </div>
<div class="sub-div">6 </div>
</div>
What this does is it displays all the divs in same line. But how can I divide the divs such that there will be 3 divs on top row and 3 divs on bottom row?
Additionally, if the screen size gets smaller, how can I divide the divs such that there will be 2 divs on top row, 2 on middle row, and 2 on last row?
Can I do it without changing HTML structure or using Javascript?
Use flex-wrap: wrap on .main to allow its children to wrap onto multiple lines. Then, you could explicitly set the width equal to calc(100% / n) where n is the number of children you want per row.
To change the layout from 2 divs per row to 3 divs per row, use a media query, as shown in the code snippet below.
.main {
display: inline-flex;
flex-wrap: wrap;
}
.sub-div {
width: calc(100% / 2);
}
#media screen and (min-width: 600px) {
.sub-div {
width: calc(100% / 3);
}
}
<div class="main">
<div class="sub-div">1 </div>
<div class="sub-div">2 </div>
<div class="sub-div">3 </div>
<div class="sub-div">4 </div>
<div class="sub-div">5 </div>
<div class="sub-div">6 </div>
</div>
You may achieve it with Grid and media query.
.main {
display: grid;
/* grid-gap: 50px 100px; */
grid-template-columns: auto auto auto;
}
#media only screen and (max-width: 768px) {
.main {
grid-template-columns: auto auto;
}
}
<div class="main">
<div class="sub-div">1 </div>
<div class="sub-div">2 </div>
<div class="sub-div">3 </div>
<div class="sub-div">4 </div>
<div class="sub-div">5 </div>
<div class="sub-div">6 </div>
</div>

CSS grid create not equal grid

started using CSS grid instead of boostrap, and im having some issue to get it right.
i want to create a grid layout that have 4fr, and 8fr columns (just like boostrap 8 and 4 columns)
and when the divs inside the grid of 4r gets fill its the divs go to a second row just like flex-wrap:wrap.
BUT Its not work its only push it inline one after another, and ignoring the grid boundaries
.home {
display: grid;
grid-template-columns: 4fr 8fr;
grid-template-rows: 100%;
height: 100%;
}
<div class="home">
<div class="col-8">
</div>
<div class="col-4">
<mat-button-toggle-group class="side-menu-button">
<mat-button-toggle>test </mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
</mat-button-toggle-group>
</div>
</div>
i even tried changing it to
grid-template-columns: repeat(1, auto-fill, 4fr 8fr);
If you're just wanting to use the grid to have items wrap inside of a div, what you're doing should basically work. Don't forget to tell .col-8 and .col-4 where they belong inside of the grid you've set up, and set the children you want to wrap to inline-block:
* {
box-sizing: border-box;
}
.home {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 100%;
height: 100%;
width: 100%;
grid-gap: 20px;
}
.col-8 {
grid-area: 1/1/1/9;
}
.col-4 {
grid-area: 1/9/1/13;
}
.bluebox,
.blackbox {
display: inline-block;
width: 50px;
height: 20px;
}
.bluebox {
background-color: blue;
}
.blackbox {
background-color: black;
}
<div class="home">
<div class="col-8">
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
</div>
<div class="col-4">
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
</div>
</div>
The reason I set up 12 columns instead of one that's 8fr and one that's 4fr is because I'm unclear about whether you're wanting a 12 column usable system like bootstrap (which is the way I implemented it), or literally only two columns. Either way should function for what you are describing in your question, but 12 separate columns is arguably more extensible later-on.
Here's a pen that contains the above code:
https://codepen.io/grantnoe/pen/MdOQOv
grid-area is what I used to set the location of .home's children. The format is as follows:
grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
The only caveat is that you've nested the children you're wanting to wrap inside of secondary element <mat-button-toggle-group>. Consider adjusting the width of that element to 100% to fill the grid's child .col-4.

Why are my template areas not stacking as I expect?

Using the following css:
.container {
display : grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-template-areas:
'first second'
'first second'
;
}
.first {
grid-area: first;
width: 200px;
height: 200px;
background-color: red;
}
.second {
grid-area: second;
width: 200px;
height: 200px;
background-color: #0eb5d6;
These boxes will stack (appearing as one red, 1 blue):
<div class="container">
<div class="first"></div>
<div class="second"></div>
<div class="first"></div>
<div class="second"></div>
</div>
However, these will not stack, and correctly appear as 2 rows with the same css:
<div class="container">
<div class="first"></div>
<div class="second"></div>
</div>
<div class='container'>
<div class="first"></div>
<div class="second"></div>
</div>
In my actual use case I'm trying to align a form using css grid. I would like to not need divs for rows if possible. Or is this the only way to avoid stacking of elements into one row?
Note that here grid-template-areas form a rectangle and so first and second spans their columns. And multiple declaration will only overlap:
A row is created for every separate string listed, and a column is
created for each cell in the string. Multiple named cell tokens within
and between rows create a single named grid area that spans the
corresponding grid cells. Unless those cells form a rectangle, the
declaration is invalid.
MDN
You can remove grid-template-areas here - it works fine without it. See demo below:
.container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
.first {
width: 200px;
height: 200px;
background-color: red;
}
.second {
width: 200px;
height: 200px;
background-color: #0eb5d6;
}
<div class="container">
<div class="first"></div>
<div class="second"></div>
<div class="first"></div>
<div class="second"></div>
</div>

Got some unwanted whitespace in css grid layout

Playing around with display: grid and got some unwanted space. Am I missing some specs in my css?
What I'm after is vertically align the 5 links at the bottom of the purple'ish plane.
Following are the codes I used:
.grid {
display: grid;
}
.-twoColumns {
grid-template-columns: repeat(2, 50%);
}
.-grid-gap {
grid-gap: 1rem;
}
<div class="grid -twoColumns -grid-gap">
<div class="column">
column
</div>
<div class="column">
column
</div>
</div>

Create a Table with CSS grid

I'm trying to create a table using CSS grid, with equal columns based on the content. I want to avoid using <table>. This is a follow-up to this question: Auto-adjusting columns with CSS grid
What I'm trying to achieve:
This table works: https://codepen.io/anon/pen/baExYw
But I want to wrap the each row in a div, which unsurprisingly breaks the table.
This table is broken: https://codepen.io/anon/pen/qpbMgG
app.html
<div class="wrapper">
<div class="box a">col 1</div>
<div class="box b">col 2</div>
<div class="box c">col 3</div>
<!-- Table Row -->
<div class="row">
<div class="box d">short data</div>
<div class="box e">a really long piece of data</div>
<div class="box f">short data</div>
</div>
<!-- Table Row -->
<div class="row">
<div class="box d">short data</div>
<div class="box e">a really long piece of data</div>
<div class="box f">short data</div>
</div>
</div>
app.css
.wrapper {
display: grid;
grid-template-columns: repeat(3, auto);
background-color: #fff;
color: #444;
max-width: 800px;
}
.box {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 20px;
font-size: 150%;
}
I'm still very new to CSS Grid, so I'm still having trouble understanding how half of this stuff works behind the scenes.
Any help is appreciated. Thanks in advance.
display: contents is what you need.
contents
These elements don't produce a specific box by themselves. They are
replaced by their pseudo-box and their child boxes.
Add this CSS (example):
.row {
display: contents;
}
More links:
Get Ready for `display: contents;`
Browser support table
In your first example, your data cells are children of the container. Hence, grid properties – which only work between parent and child – work as you expect.
In your second example, you have some data cells that are children of .row containers. These cells are no longer children of .wrapper, the grid container. Therefore, these cells are outside the scope of grid layout, do not recognize grid properties and are rendered as standard block-level elements.
So, basically, grid containers with different child elements render different layouts.
One solution to get your examples to match would be to make the grid items into grid containers having the same properties as the parent. Here's the general idea:
Revised Codepen
.wrapper {
display: grid;
grid-template-columns: repeat(3, minmax(50px, 1fr));
background-color: #fff;
color: #444;
max-width: 800px;
}
.row {
grid-column: 1 / -1;
display: grid;
grid-template-columns: repeat(3, minmax(50px, 1fr));
}
div:nth-child(4) { grid-row-start: 2; }
div:nth-child(5) { grid-row-start: 3; }
.box {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 20px;
font-size: 150%;
}
<div class="wrapper">
<div class="box a">col 1</div>
<div class="box b">col 2</div>
<div class="box c">col 3</div>
<!-- Table Row -->
<div class="row">
<div class="box d">short data</div>
<div class="box e">a really long piece of data</div>
<div class="box f">short data</div>
</div>
<!-- Table Row -->
<div class="row">
<div class="box d">short data</div>
<div class="box e">a really long piece of data</div>
<div class="box f">short data</div>
</div>
</div>
It didn't break, it works exactly as intended.
Every child element is using one cell of the grid, if you wrap your header in another div you'll see they swap rows for columns, because each group will use one cell.
If you are going to display tabular data, then you should stick with tables as they are the semantically correct element for that purpose.
However if you are trying to build responsive designs or you really want to use grid I suggest you to read this incredible article about CSS grids.
Take a look in display: subgrid; maybe it is what you are looking for in this scenario.
Actually we should use auto-fit property of css-grid to create table-like layout with css gridNote: here because of auto-fit we do not need to specify the number of columns
#mixin table-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
align-items: center;
}
.tr{
#include table-row();
}
.thead{
#include table-row();
}
<HTML>
<div>
<div class="thead"></div>
<div class="tr"></div>
</div>
</html>