CSS Grid container with dynamic amount of columns - html

I have a grid container with those settings -
display: grid;
grid-template-columns: 1fr 1fr 2fr repeat(4, 1fr) 2rem;
grid-auto-flow: column;
grid-auto-columns: 1fr;
height: 100%;
width: 100%;
I initially set the container for 8 columns. The issue is that in some cases will be 9 columns. The extra column will be added to be the 3rd and not at the end, so after the insertion of the extra column the grid should be -
grid-template-columns: 1fr 1fr 1fr 2fr repeat(4, 1fr) 2rem;
Here is the code
function addColumn(){
var g = document.querySelector(".my_grid");
var div = document.createElement("div");
div.setAttribute("id", "column9");
g.appendChild(div);
}
body{
margin:0;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.my_grid {
display: grid;
grid-template-columns: 1fr 1fr 2fr repeat(4, 1fr) 2rem;
grid-auto-flow: column;
grid-auto-columns: 1fr;
height: 100%;
width: 100%;
}
.my_grid div{
box-sizing: border-box;
transition: .5s linear all;
}
#column1 { background: #0000 }
#column2 { background: #0001 }
#column3 { background: #0002 }
#column4 { background: #0003 }
#column5 { background: #0004 }
#column6 { background: #0005 }
#column7 { background: #0006 }
#column8 { background: #0007 }
#column9 { background: #0008; border:1px solid red; }
button {
position: fixed;
top: 0;
left: 0;
height: 40px;
width: 100px;
}
<div class="my_grid">
<div id="column1"></div>
<div id="column2"></div>
<div id="column3"></div>
<div id="column4"></div>
<div id="column5"></div>
<div id="column6"></div>
<div id="column7"></div>
<div id="column8">
2rem
</div>
</div>
<button onclick="addColumn()">Add Column</button>
So the question is how to handle this situation? I tried to set it dynamically with auto-fill but it doesn't work.

If I get this right you want to add a dynamic div or there is a div that is added to the end. Here is how you can make it be in the third place.
body {
margin: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.my_grid {
display: grid;
grid-template-columns: 1fr 1fr 2fr repeat(4, 1fr) 2rem;
grid-auto-flow: column;
grid-auto-columns: 1fr;
height: 100%;
width: 100%;
}
.my_grid div {
box-sizing: border-box;
transition: 0.5s linear all;
}
#column1 {
background: #0000;
}
#column2 {
background: #0001;
}
#column3 {
background: #0002;
}
#column4 {
background: #0003;
}
#column5 {
background: #0004;
}
#column6 {
background: #0005;
}
#column7 {
background: #0006;
}
#column8 {
background: #0007;
}
#column9 {
background: red;
border: 1px solid red;
grid-column: 3 / 4;
}
<div class="my_grid">
<div id="column1"></div>
<div id="column2"></div>
<div id="column3"></div>
<div id="column4"></div>
<div id="column5"></div>
<div id="column6"></div>
<div id="column7"></div>
<div id="column8"></div>
<div id="column9"></div>
</div>

You can rely on order property and the creation of implicit extra column at the start. The trick is to use nth-child to consider the case where there is 9 items in order to:
Place the first item outside the explicit grid. It will use the implicit one (1fr will be added at the start)
Place the last item column9 at the beginning.
Force the item column2 to be before column9
function addColumn(){
var g = document.querySelector(".my_grid");
var div = document.createElement("div");
div.setAttribute("id", "column9");
g.appendChild(div);
document.querySelector("button").style.display="none";
}
body{
margin:0;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.my_grid {
display: grid;
grid-template-columns: 1fr 1fr 2fr repeat(4, 1fr) 2rem;
grid-auto-flow: column;
grid-auto-columns: 1fr; /* our implicit column */
height: 100%;
width: 100%;
}
.my_grid div{
box-sizing: border-box;
transition: .5s linear all;
}
#column1 { background: #0000 }
#column2 { background: #0001 }
#column3 { background: #0002 }
#column4 { background: #0003 }
#column5 { background: #0004 }
#column6 { background: #0005 }
#column7 { background: #0006 }
#column8 { background: #0007 }
#column9 {
background: #0008;
border:1px solid red;
order:-1; /* place at the start */
}
/* The below will trigger only with 9 columns */
#column1:first-child:nth-last-child(9) {
background:green;
grid-column:-10; /* place before everything outisde the explicit grid */
}
#column2:nth-child(2):nth-last-child(8) {
background:blue;
order:-1; /* place before column9*/
}
button {
position: fixed;
top: 0;
left: 0;
height: 40px;
width: 100px;
}
<div class="my_grid">
<div id="column1"></div>
<div id="column2"></div>
<div id="column3"></div>
<div id="column4"></div>
<div id="column5"></div>
<div id="column6"></div>
<div id="column7"></div>
<div id="column8">
2rem
</div>
</div>
<button onclick="addColumn()">Add Column</button>

Related

How to center the elements of specific CSS grid's row without horizontal gap and additional wrappers?

Below image has been created by the graphics editor. The target is get the same view by CSS grid.
Currently, the middle row fills the viewport's width:
html, body {
height: 100%;
}
.TwoColumnsLayout {
display: grid;
grid-template-areas:
"UPPER_FIXED_CONTENT UPPER_FIXED_CONTENT"
"SIDEBAR SPECIFIC_CONTENT"
"BOTTOM_FIXED_CONTENT BOTTOM_FIXED_CONTENT";
grid-template-columns: 100px 1fr;
grid-template-rows: auto 1fr auto;
height: 100%;
}
.TwoColumnsLayout-UpperFixedContent {
height: 30px;
grid-area: UPPER_FIXED_CONTENT;
background-color: lightpink;
}
.TwoColumnsLayout-Sidebar {
overflow-y: auto;
grid-area: SIDEBAR;
background-color: gold;
width: 100px;
}
.TwoColumnsLayout-SpecificContent {
overflow-y: auto;
grid-area: SPECIFIC_CONTENT;
background-color: aquamarine;
}
.TwoColumnsLayout-BottomFixedContent {
height: 30px;
grid-area: BOTTOM_FIXED_CONTENT;
background: deepskyblue;
}
<div class="TwoColumnsLayout">
<div class="TwoColumnsLayout-UpperFixedContent"></div>
<div class="TwoColumnsLayout-Sidebar"></div>
<main class="TwoColumnsLayout-SpecificContent"></main>
<div class="TwoColumnsLayout-BottomFixedContent"></div>
</div>
In this case, justify-content: center; will change nothing.
If to apply justify-items: center; to grid container and also justify-self: stretch; to first and last element, we'll get:
html, body {
height: 100%;
}
.TwoColumnsLayout {
display: grid;
grid-template-areas:
"UPPER_FIXED_CONTENT UPPER_FIXED_CONTENT"
"SIDEBAR SPECIFIC_CONTENT"
"BOTTOM_FIXED_CONTENT BOTTOM_FIXED_CONTENT";
grid-template-columns: 100px 1fr;
grid-template-rows: auto 1fr auto;
justify-items: center;
height: 100%;
}
.TwoColumnsLayout-UpperFixedContent {
height: 30px;
grid-area: UPPER_FIXED_CONTENT;
background-color: lightpink;
justify-self: stretch;
}
.TwoColumnsLayout-Sidebar {
overflow-y: auto;
grid-area: SIDEBAR;
background-color: gold;
width: 100px;
}
.TwoColumnsLayout-SpecificContent {
overflow-y: auto;
grid-area: SPECIFIC_CONTENT;
background-color: aquamarine;
}
.TwoColumnsLayout-BottomFixedContent {
height: 30px;
grid-area: BOTTOM_FIXED_CONTENT;
background: deepskyblue;
justify-self: stretch;
}
<div class="TwoColumnsLayout">
<div class="TwoColumnsLayout-UpperFixedContent"></div>
<div class="TwoColumnsLayout-Sidebar"></div>
<main class="TwoColumnsLayout-SpecificContent"></main>
<div class="TwoColumnsLayout-BottomFixedContent"></div>
</div>
I expected it will be simple with CSS grid...
It there the solutions without adding of extra HTML elements?
You can do it like below. The 600px will simulate the max-width which is the area for the sidebar and content
body {
margin:0;
}
.TwoColumnsLayout {
--max: 600px; /* your max-width */
min-height: 100vh;
display: grid;
grid-template-columns:
calc((100% - var(--max))/2) 100px 1fr calc((100% - var(--max))/2);
grid-template-rows: auto 1fr auto;
}
.TwoColumnsLayout-UpperFixedContent,
.TwoColumnsLayout-BottomFixedContent{
height: 30px;
grid-column:1/-1;
background-color: lightpink;
}
.TwoColumnsLayout-Sidebar {
overflow-y: auto;
grid-column: 2;
background-color: gold;
}
.TwoColumnsLayout-SpecificContent {
overflow-y: auto;
background-color: aquamarine;
}
.TwoColumnsLayout-BottomFixedContent {
background: deepskyblue;
}
<div class="TwoColumnsLayout">
<div class="TwoColumnsLayout-UpperFixedContent"></div>
<div class="TwoColumnsLayout-Sidebar"></div>
<main class="TwoColumnsLayout-SpecificContent"></main>
<div class="TwoColumnsLayout-BottomFixedContent"></div>
</div>

HTML button displays very differently on 2 pages with same CSS

I have two web pages - one is a Product Listings Page:
/*BUTTON STYLE*/
button {
background-color: #132257;
color: white;
border: 0.25em solid white;
cursor: pointer;
width: 100%;
height: 90%;
}
/*PRODUCT LISTINGS PAGE*/
.shoplayout {
grid-area: MC;
display: grid;
grid-template-columns: 1fr 4fr;
grid-template-areas: "filters listing";
}
.filters {
grid-area: filters;
}
.listing {
grid-area: listing;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.75em;
}
.product {
width: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: repeat(6, auto);
border: 0.125em solid #1b2493;
}
.product>* {
height: 8vh;
line-height: 8vh;
border-bottom: solid 0.02em #1b2493;
padding-left: 0.25em;
}
.product div:nth-child(even) {
/*Every second div within a product has the same background*/
background-color: lightsteelblue;
}
.productbuy {
display: grid;
grid-template-columns: repeat(4, 1fr);
text-align: center;
border: none;
}
.productpic {
grid-row: 1;
padding: 0;
border: none;
display: flex;
justify-items: center;
height: 20vh;
}
.productpic>img {
/*https: //stackoverflow.com/questions/3029422/how-do-i-auto-resize-an-image-to-fit-a-div-container*/
max-width: 100%;
max-height: 100%;
}
/*PRODUCT DETAILS PAGE*/
.productdetails {
grid-area: MC;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(6, auto);
gap: 1em;
}
.productdetails>* {
border-bottom: solid 0.02em #1b2493;
padding-left: 0.25em;
}
.picdetail {
grid-column: 1 / span 2;
grid-row: 1;
background-color: cornsilk;
justify-items: center;
border: none;
}
.picdetail img {
max-width: 100%;
max-height: 100%;
}
.productnumbers {
display: grid;
grid-template-columns: repeat(4, 1fr);
text-align: center;
}
<!-- CONTENT -->
<div class="content" id="elemToSlide">
<div class="shoplayout">
<div class="listing">
<!--ALL PRODUCTS IN HERE-->
<div class="product">
<div>Ch. BonPlonque, 2019</div>
<div>Bordeaux, France</div>
<div>Crisp fresh white</div>
<div>3.21/5, 3 reviews</div>
<!--DISPLAY AS A 4 COL INNER GRID-->
<div class="productbuy">
<div>€15.95</div>
<div>Stock: 5</div>
<div><button>Buy</button></div>
<div>Qty</div>
</div>
</div>
<!--END LISTING COLUMNS-->
</div>
<!--END SHOP CONTENT-->
</div>
One is a Products Details Page:
/*BUTTON STYLE*/
button {
background-color: #132257;
color: white;
border: 0.25em solid white;
cursor: pointer;
width: 100%;
height: 90%;
}
/*PRODUCT LISTINGS PAGE*/
.shoplayout {
grid-area: MC;
display: grid;
grid-template-columns: 1fr 4fr;
grid-template-areas: "filters listing";
}
.filters {
grid-area: filters;
}
.listing {
grid-area: listing;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.75em;
}
.product {
width: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: repeat(6, auto);
border: 0.125em solid #1b2493;
}
.product>* {
height: 8vh;
line-height: 8vh;
border-bottom: solid 0.02em #1b2493;
padding-left: 0.25em;
}
.product div:nth-child(even) {
/*Every second div within a product has the same background*/
background-color: lightsteelblue;
}
.productbuy {
display: grid;
grid-template-columns: repeat(4, 1fr);
text-align: center;
border: none;
}
.productpic {
grid-row: 1;
padding: 0;
border: none;
display: flex;
justify-items: center;
height: 20vh;
}
.productpic>img {
/*https: //stackoverflow.com/questions/3029422/how-do-i-auto-resize-an-image-to-fit-a-div-container*/
max-width: 100%;
max-height: 100%;
}
/*PRODUCT DETAILS PAGE*/
.productdetails {
grid-area: MC;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(6, auto);
gap: 1em;
}
.productdetails>* {
border-bottom: solid 0.02em #1b2493;
padding-left: 0.25em;
}
.picdetail {
grid-column: 1 / span 2;
grid-row: 1;
background-color: cornsilk;
justify-items: center;
border: none;
}
.picdetail img {
max-width: 100%;
max-height: 100%;
}
<!--,GRID CELL 5, 2 - DISPLAYS AS A 4 COL INNER GRID-->
<div class="productbuy">
<div>€15.95</div>
<div>Stock: 5</div>
<div><button>Buy</button></div>
<div>Qty</div>
</div>
Pretty much everything displays as I want with the exception of the button captioned BUY:
The HTML for the .productbuy element is identical in both cases, the CSS is identical in both cases 9with the exception of the nth child background-color), the button style applies across the entire website, so I am puzzled as to why this is happening.
Any and all suggestions gratefully received.
Thanks to both MD Code and Andrea who spotted that there must have been a problem with the parent containers. In the second case, the product details page, there was a div missing from the page structure, and the CSS for both pages was somewhat messy.
So I tidied things up and it works perfectly now.
Product Details Page HTML is now:
<!-- CONTENT -->
<div class="content" id="elemToSlide">
<!--DETAIL LAYOUT-->
<div class="detailslayout">
<!--A WINE-->
<div class="detailspic">
<img src="images/products/winehorizontallarge.png" />
</div>
<div>Name and vintage</div>
<div>Origin</div>
<div>Description</div>
<div>Reviews</div>
<div>Grapes</div>
<div>Producer</div>
<div class="detailsnumbers">
<div>TA</div>
<div>pH</div>
<div>RS</div>
<div>ABV</div>
</div>
<div class="productbuy">
<div>€15.95</div>
<div>Stock: 5</div>
<div><button>Buy</button></div>
<div>Qty</div>
</div>
<!--END WINE-->
</div>
<!--END DETAIL LAYOUT-->
</div>
<!--END CONTENT-->
Putting in the div "DetailsLayout" meant the page structure was correct; I then tidied up the CSS:
/*LAYOUT FOR THE PLP*/
.shoplayout {
grid-area: MC;
display: grid;
grid-template-columns: 1fr 4fr;
grid-template-areas: "filters listing";
}
/*LAYOUT FOR THE PDP - THIS WAS MISSING PREVIOUSLY*/
.detailslayout {
grid-area: MC;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(6, auto);
gap: 1em;
}
.detailslayout > * {
height: 8vh;
line-height: 8vh;
}
.products {
width: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: repeat(6, auto);
border: 0.125em solid #1b2493;
}
.products > * {
height: 8vh;
line-height: 8vh;
border-bottom: solid 0.02em #1b2493;
padding-left: 0.25em;
}
.products div:nth-child(even) {
background-color: lightsteelblue;
}
.productbuy {
display: grid;
grid-template-columns: repeat(4, 1fr);
text-align: center;
border: none;
background-color: lightsteelblue;
}
.productpic {
grid-row: 1;
padding: 0;
border: none;
display: flex;
justify-items: center;
height: 20vh;
}
.productpic img, .detailspic img {
max-width: 100%;
max-height: 100%;
}
.detailspic {
grid-column: 1 / span 2;
grid-row: 1 ;
background-color: cornsilk;
justify-items: center;
border: none;
height: 20vh;
}
.detailsnumbers {
display: grid;
grid-template-columns: repeat(4, 1fr);
text-align: center;
}
Now, on both pages the buttons render in the same way on the PLP:
And on the PDP:
Thanks to all for your help,
Dermot
The problem is not your style, button is working good but on details page your button's styles is according to the div parent change div parent style

Need to make row-column-row using css flexbox

I want to make a row-column-row layout using css flexbox, here's the code:
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.container {
display: flex;
flex-wrap: wrap;
gap: 0.2%;
}
.box {
color: white;
background: royalblue;
min-height: 100px;
min-width: 100px;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid;
}
.b1 {
flex: 1 0 80%;
}
.b2 {
flex: 1 1 auto;
}
.b3 {
flex: 1 0 100%;
}
<div class="container">
<div class="box b1">1</div>
<div class="box b2">2</div>
<div class="box b3">3</div>
</div>
This is what I want:
And on mobile I want something like this:
But as you can see in the code, the column is not growing vertically and I cannot even use margins or gaps in between the divs.
Any suggestions will be appreciated. CSS-Grid solutions are also welcome.
A grid-based approach using a media query:
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.container {
display: grid;
grid-template-columns: 4fr 1fr;
grid-auto-rows: minmax(100px, auto);
grid-template-areas:
"b1 b2"
"b3 b2";
gap: 0.2%;
}
#media screen and (max-width: 480px) {
.container {
grid-template-columns: 1fr;
grid-template-areas:
"b1"
"b2"
"b3";
}
}
.box {
color: white;
background: royalblue;
min-height: 100px;
min-width: 100px;
border: 1px solid;
}
.b1 {
grid-area: b1;
}
.b2 {
grid-area: b2;
}
.b3 {
grid-area: b3;
}
<div class="container">
<div class="box b1">1</div>
<div class="box b2">2</div>
<div class="box b3">3</div>
</div>

How do I use calc() with min-content?

I have a grid layout which can be simplified like this.
What I want to achieve is the .side should take whatever space the content needs to by default using min-content, but user can enlarge it by increasing the --size custom css property.
I tried calc(min-content + var(--size)) but it doesn't work. I can't assign a specific value like calc(100px + var(--size)) since the original size should be determined by its content.
What is the best approach to achieve such a feature?
* {
box-sizing: border-box;
}
body {
overflow: hidden;
margin: 0;
}
.container {
--size: 10px;
width: 100vw;
height: 100vh;
display: grid;
grid-template-areas:
"l t"
"l b";
/* doesn't work */
/* grid-template-columns: calc(min-content + var(--size)) 1fr; */
grid-template-columns: min-content 1fr;
grid-template-rows: 1fr 1fr;
}
.container > * {
border: solid 1px black;
}
.side {
grid-area: l;
}
.top {
grid-area: t;
}
.bottom {
grid-area: b;
}
<section class="container">
<div class="side">This should have a 10px gutter on the right</div>
<div class="top">Top</div>
<div class="bottom">Bottom</div>
</section>
Use width:calc(100% + var(--size)) for the grid item. This will create an overflow that you can rectify by adding a gap:
* {
box-sizing: border-box;
}
body {
overflow: hidden;
margin: 0;
}
.container {
--size: 20px;
height: 100vh;
display: grid;
grid-template-areas:
"l t"
"l b";
/* doesn't work */
/* grid-template-columns: calc(min-content + var(--size)) 1fr; */
grid-template-columns: min-content 1fr;
grid-template-rows: 1fr 1fr;
column-gap:var(--size);
}
.container > * {
border: solid 1px black;
}
.side {
grid-area: l;
width:calc(100% + var(--size));
}
.top {
grid-area: t;
}
.bottom {
grid-area: b;
}
<section class="container">
<div class="side">This should have a 10px gutter on the right</div>
<div class="top">Top</div>
<div class="bottom">Bottom</div>
</section>

css - nested div in grid does not respect grid sizes

So I'm trying to display cards within a grid. I would like the card size to be based on the grid size and then to overlay text on top of it that correctly matches the width.
Here's my implementation so far but it seems like the div/img no longer respects the grid's sizes
for (let i = 0; i < 15; i++)
{
$("#grid").append(`
<div class="item">
<div>
<img src="http://via.placeholder.com/250x350" />
<div class="text">
sadfsd
</div>
</div>
</div>
`);
}
.flex {
border: 1px solid black;
display: flex;
flex-direction: column;
height: 100vh;
}
.footer {
height: 20%;
}
.upper {
flex: 1;
overflow: auto;
}
#grid {
border: 1px solid black;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
height: 100%;
position: relative;
max-width: 100%;
box-sizing: border-box;
}
.item {
display: inline-block;
text-align: center;
position: relative;
}
.inner {
border: 1px solid red;
max-height: 100%;
max-width: 100%;
}
.text {
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
height: 30%;
border: 1px solid black;
width: 90%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex">
<div class='upper'>
<div id="grid">
</div>
</div>
<div class="footer">
footer
</div>
</div>
What I want is it to look something like this (of course with the text matching the width of the image)
for (let i = 0; i < 15; i++)
{
$("#grid").append(`
<div class="item">
<img src="http://via.placeholder.com/150x350" />
<div class="text">
text
</div>
</div>
`);
}
.flex {
border: 1px solid black;
display: flex;
flex-direction: column;
height: 100vh;
}
.footer {
height: 20%;
}
.upper {
flex: 1;
overflow: auto;
}
#grid {
border: 1px solid black;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
height: 100%;
position: relative;
max-width: 100%;
box-sizing: border-box; /* added */
}
.item {
position: relative;
}
.text {
border: 1px solid black;
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
width: 90%;
height: 30%;
}
img {
display: block;
margin: 0 auto;
max-height: 100%;
max-width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div class="flex">
<div class='upper'>
<div id="grid">
</div>
</div>
<div class="footer">
footer
</div>
</div>