How to calc() the number of rows in a grid template?
When using division with calc
the result will be a number
and not an integer
thus it won't work because the repeat()
expect an interger
The generic form of the
repeat()
syntax is, approximately,
repeat( [ <positive-integer> | auto-fill | auto-fit ] , <track-list> )
ref
And
At
/
, check that the right side is<number>
. If the left side is<integer>
, resolve to<number>
. Otherwise, resolve to the type of the left side.ref
And
Number values are denoted by
<number>
, and represent real numbers, possibly with a fractional component.ref
Even if we both know that the result will be an integer the browser will still consider it as a number.
You can have the same issue with multiplication in case you have a number in one of the sides
.grid {
display: grid;
grid-gap: 10px;
grid-template-columns: 1fr;
margin-bottom: 10px;
background: rgba(0, 0, 0, 0.2);
}
.grid>div {
background: tomato;
width: 20px;
text-align: center;
margin: auto;
}
.grid.no-calc {
grid-template-columns: repeat(3, 30px);
border-bottom:3px solid red;
}
.grid.multiplication {
grid-template-columns: repeat(calc(3 * 1.0), 30px); /*will fail*/
border-bottom:calc(3px * 1.0) solid red;
}
.grid.division {
grid-template-columns: repeat(calc(6 / 2), 30px);
border-bottom:calc(6px / 2) solid red; /*this will work because border accept numbers*/
}
<div class="grid no-calc">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
<div class="grid multiplication">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
<div class="grid division">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
A way to count columns in a responsive grid
I think the easiest way without brute force is to consider a simple division. You can easily find the width of the container and each column is defined by minmax(300px,1fr)
and we know the gap
. Using all these information the calculation should be done like below:
If we will have N
columns then we will have N-1
gaps. We also know that W
should at least be 300px
and cannot be more than a value (we will call Wmax
).
Let's suppose the gap is equal to 10px
.
If N=2
and each column is equal to 300px
we will have the container width equal to 300px*2 + 10px*1 = 610px
.
If N=3
and each column is equal to 300px
we will have 300px*3 + 10px*2=920px
.
Now it's clear that if the container width is between 610px
and 920px
we will have 2 columns because there is no space to hold 3 columns but enough space to hold 2 columns that we expand to fill the remaining space (using 1fr
) so Wmax
in this case is (920px - 10px)/2 = 455px
. In other words, the width will vary from 300px
to 455px
when having 2 columns.
So if we take the formula 300px*N + 10px*(N-1) = Wc
with Wc
our container width you will see that N
is equal to 2
when Wc=610px
and 3
when Wc=920px
and between we will have a result in [2,3]
so we simply round the value to the smallest one (2 in this case) and we will have our column number.
Here is a basic example:
var gap = 10;var minW = 200;
var Wc = document.querySelector('.grid').offsetWidth;var N = Math.floor((Wc+gap)/(minW+gap));console.log(N);
window.addEventListener('resize', function(event){ Wc = document.querySelector('.grid').offsetWidth; N = Math.floor((Wc+gap)/(minW+gap)); console.log(N);});
.grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); grid-gap:10px;}span { min-height:50px; background:red;}
<div class="grid"> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span></div>
Defining the number of rows in CSS grids
Simply define grid-auto-rows
and you don't need to know the number of items
ul { display: grid; grid-auto-rows:1fr; margin:10px; padding:0;}ul li { border:1px solid; list-style-type:none;}
<ul> <li>item <br>one</li> <li>item two</li> <li>item three</li></ul>
<ul> <li>item <br>one</li> <li>item two</li> <li>item three</li> <li>item two</li> <li>item three</li></ul>
<ul> <li>item <br>one</li> <li>item two</li></ul>
Specify Number of Rows and Columns in Grid
You can use grid-template-columns
to specify the number of columns.
The number of columns is defined by the number of values in the list.
Below, I'm using repeat()
as shorthand to generate four values.
Based on your existing code, auto auto auto auto
would also work.
Also see CSS Grid Layout.
.grid-container { display: grid; grid-template-columns: repeat(4, 1fr); background-color: #2196F3; padding: 10px;}
.grid-item { background-color: rgba(255, 255, 255, 0.8); border: 1px solid rgba(0, 0, 0, 0.8); padding: 20px; font-size: 30px; text-align: center;}
<h1>Grid Elements</h1><div class="grid-container"> <div class="grid-item">1</div> <div class="grid-item">2</div> <div class="grid-item">3</div> <div class="grid-item">4</div> <div class="grid-item">5</div> <div class="grid-item">6</div> <div class="grid-item">7</div> <div class="grid-item">8</div> <div class="grid-item">9</div> <div class="grid-item">10</div> <div class="grid-item">11</div> <div class="grid-item">12</div></div>
Can I make a CSS grid with dynamic number of rows or columns?
Okay, after reading the MDN reference, I found the answer! The key to dynamic rows (or columns) is the repeat
property.
const COLORS = [ '#FE9', '#9AF', '#F9A', "#AFA", "#FA7"];
function addItem(container, template) { let color = COLORS[_.random(COLORS.length - 1)]; let num = _.random(10000); container.append(Mustache.render(template, { color, num }));}
$(() => { const tmpl = $('#item_template').html() const container = $('#app'); for(let i=0; i<5; i++) { addItem(container, tmpl); } $('#add_el').click(() => { addItem(container, tmpl); }) container.on('click', '.del_el', (e) => { $(e.target).closest('.item').remove(); });});
.container { width: 100%; display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(auto-fill, 120px); grid-row-gap: .5em; grid-column-gap: 1em;}
.container .item {}
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div id="app" class="container"></div>
<button id="add_el">Add element</button>
<template id="item_template"> <div class="item" style="background: {{color}}"> <p>{{ num }}</p> <p> <button class="del_el">Delete</button> </p> </div></template>
How can I get an array of values or rows from my grid layout?
You can grab all the items using querySelectorAll
and use getComputedStyle
to count the number of columns in each row. see this answer
var computedStyle = getComputedStyle(document.querySelector('.grid-table'))
var columnsCount = computedStyle.getPropertyValue("grid-template-columns").split(" ").length // in our case 5
var container = document.querySelector('.grid-table')
var columns = getComputedStyle(container).getPropertyValue("grid-template-columns").split(" ").length;
var items = document.querySelectorAll('.grid-table div');
var output = []
var row = 0;
items.forEach(function (item, i) {
if (i % columns === 0) {
if (output.length > 0) {
row++ ;
}
output.push([])
}
output[row].push(item.innerHTML)
});
console.log(output)
.grid-table {
display: grid;
grid-template-columns: repeat(5, 1fr);
}
<div class="grid-table">
<div>head1</div>
<div>head2</div>
<div>head3</div>
<div>head4</div>
<div>head5</div>
<div>item1</div>
<div>item2</div>
<div>item3</div>
<div>item4</div>
<div>item5</div>
<div>item6</div>
<div>item7</div>
<div>item8</div>
<div>item9</div>
</div>
Change the number of columns and rows in a grid as the number of items increase
Implicit columns creation can do this. You can consider nth-child()
/nth-last-child()
to create a new column when you reach a specific number of columns:
.container {
display: inline-grid;
width: 100px;
vertical-align: top;
border: 1px solid;
}
.container > :nth-child(2) {
grid-column: 2;
}
.container > :nth-last-child(n + 5) ~ :nth-child(3) {
grid-column: 3;
}
.container > :nth-last-child(n + 10) ~ :nth-child(4) {
grid-column: 4;
}
.container > :nth-last-child(n + 17) ~ :nth-child(5) {
grid-column: 5;
}
.container > * {
border: 1px solid red;
aspect-ratio: 1;
}
<div class="container">
<div></div>
</div>
<div class="container">
<div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="container">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
Can I use css-grid to display an unknown number of items, in left-to-right reading order, over two rows?
A CSS only solution where you need to write a bit of CSS to cover many cases. The below code covers up to 12 elements and the CSS isn't that big. You can keep adding more to cover more cases.
.box {
display: grid;
grid-auto-flow:columns;
grid-auto-columns:1fr;
counter-reset: divs;
margin: 5px;
border:1px solid;
}
.box div {
border:1px solid red;
}
.box div:before {
counter-increment: divs;
content: counter(divs);
}
.box div:nth-child(1):nth-last-child(2) ~ *,
.box div:nth-child(2):nth-last-child(3) ~ *,
.box div:nth-child(3):nth-last-child(4) ~ *,
.box div:nth-child(4):nth-last-child(5) ~ *,
.box div:nth-child(5):nth-last-child(6) ~ *,
.box div:nth-child(6):nth-last-child(7) ~ *
/*
.box div:nth-child(N):nth-last-child(N+1) ~ *
*/{
grid-row:2;
}
<div class="box">
<div></div>
</div>
<div class="box">
<div></div>
<div></div>
</div>
<div class="box">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="box">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="box">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="box">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="box">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
Related Topics
Overlap Border of Parent with H2 Margin Negative
Are Nested Span Tags Ok in Xhtml
Difference Between HTML and Dom
How to Combine Multiple CSS Rules
HTML Span Align Center Not Working
Textarea to Fill a Parent Container Exactly, with Padding
How to Force Horizontal Scrolling in an HTML List Using CSS
What Does "<HTML Xmlns="Http://Www.W3.Org/1999/Xhtml">" Do
Unwanted Border-Radius Corners Around Images in Brave/Chrome Browser
Cordova List All Files from Application Directory (Www)
How to Style Unordered Lists in CSS as Comma Separated Text
CSS Right Margin Does Not Work Inside a Div with Overflow Scroll
Are HTML Image Maps Still Used
Bootstrap Dropdown Clipped by Overflow:Hidden Container, How to Change The Container
Set Div to Remaining Height Using CSS with Unknown Height Divs Above and Below