grid-template - why does this not fit into a single row? - css

Have got three items. Why would they not fit a in a single row with three columns
#grid {
border: 1px solid black;
display: grid;
grid-template:
"a a a" 100px
}
#grid > div {
background-color: red;
padding: 0px;
margin: 0px;
border: 1px solid black;
}
<div id="grid">
<div></div>
<div></div>
<div></div>
</div>
<div id="grid">
<div></div>
<div></div>
<div></div>
</div>
UPDATE: it runs as expected on SO built-in js/css/html environment.
It runs unexpectedly on both jsfiddle and codepen.
https://jsfiddle.net/97grq2pz/186/
https://codepen.io/matcheek/pen/EOgmzr
https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template

Related

CSS Grid Margin Top for entire columns

Is it possible to shift all 2nd/even grid colums as a whole like in the image using CSS grid?
My current css code situation is very simple, it looks like this:
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 24px;
I am trying to achive something that looks like the following image:
You can use the :nth-child() pseudo class to achieve this. This is how I approached it:
<div class="container">
<div class="cards">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</div>
</div>
.container{
max-width: 900px;
margin: 0 auto;
height: auto;
}
.cards{
display: grid;
place-items: center;
grid-template-columns: repeat(4,1fr);
gap: 5px;
}
.card{
width: 200px;
height: 250px;
border: 3px solid black;
}
.card:nth-child(2n-2){
position: relative;
top: 100px;
}
/* or use margin */
/*
.card:nth-child(2n-2){
margin-top: 100px;
}
*/
Here is the codepen link: https://codepen.io/glenhug/pen/QWrWXJY
Also this is post had a nice explanation: How to target a specific column or row in CSS Grid Layout?
This might do the trick.
.grid-container {
width: min-content;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 10px;
}
.grid-container > div {
width: 50px;
height: 50px;
border: 1px solid black;
}
.grid-container div:nth-child(2n) {
position: relative;
top: 15px;
}
<div class='grid-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>
Not with CSS grid but combining inline-block, float and shape-outside you can do it and it will be responsive and works with any element.
Find all the details in my article: https://css-tricks.com/hexagons-and-beyond-flexible-responsive-grid-patterns-sans-media-queries/
Here is a demo:
.main {
display:flex;
--s: 100px; /* size */
--r: 1; /* ratio */
--mv: 4px; /* margin */
--vc: calc(var(--s) * var(--r) * .5);
--mh: calc(var(--mv) + var(--s)/2);
--f: calc(2*var(--s)*var(--r) + 4*var(--mv) - 2*var(--vc) - 2px);
}
.container {
font-size: 0; /*disable white space between inline block element */
}
.container div {
width: var(--s);
margin: var(--mv) var(--mh);
height: calc(var(--s)*var(--r));
display: inline-block;
font-size: initial;
background: red;
margin-bottom: calc(var(--mv) - var(--vc));
}
.container div:nth-child(odd) {
background: green;
}
.container::before {
content: "";
width: calc(var(--s)/2 + var(--mh));
float: left;
height: 135%;
shape-outside: repeating-linear-gradient(
#0000 0 calc(var(--f) - 2px),
#000 0 var(--f));
}
<div class="main">
<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></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>

How to make a css grid grow to contain a flexbox when using grid-auto-rows?

In the following codepen you will see that there is a flexbox inside of a css grid. As you can see, the contents of the flexbox div are overflowing under other parts of the grid.
If I remove the CSS grid-auto-rows:100px; then the flexbox contents no longer overflow. However, I really want the other css grid items to be 100px tall, unless their contents are too tall to be contained within 100px.
How can I have all the css grid items default to 100px tall while having any items whose contents are taller than 100px grow to hold all of the contents?
* {box-sizing: border-box;}
.wrapper {
display: grid;
grid-auto-rows: 100px;
}
.wrapper > div {
border: 2px solid #ffa94d;
border-radius: 5px;
background-color: #ffd8a8;
padding: 1em;
color: #d9480f;
}
.box2 {
display:flex;
flex-direction: column;
}
.box2 > div{
border: 2px solid #ffa999;
border-radius: 5px;
background-color: #ffd899;
padding: 1em;
color: #d94899;
}
<div class="wrapper">
<div class="box1">Box 1</div>
<div class="box2">
Box 2
<div class="flex1">Flex One</div>
<div class="flex2">Flex One</div>
<div class="flex3">Flex One</div>
<div class="flex4">Flex One</div>
</div>
<div class="box3">Box 3</div>
</div>
Use the minmax(min, max) function.
* {box-sizing: border-box;}
.wrapper {
display: grid;
grid-auto-rows: minmax(100px, auto);
}
.wrapper > div {
border: 2px solid #ffa94d;
border-radius: 5px;
background-color: #ffd8a8;
padding: 1em;
color: #d9480f;
}
.box2 {
display:flex;
flex-direction: column;
}
.box2 > div{
border: 2px solid #ffa999;
border-radius: 5px;
background-color: #ffd899;
padding: 1em;
color: #d94899;
}
<div class="wrapper">
<div class="box1">Box 1</div>
<div class="box2">
Box 2
<div class="flex1">Flex One</div>
<div class="flex2">Flex One</div>
<div class="flex3">Flex One</div>
<div class="flex4">Flex One</div>
</div>
<div class="box3">Box 3</div>
</div>

Add an overlay div inside nested flex containers (3x3 grid) in a specific cell

I have a 3x3 grid with flex-box concept, inside of each cell it has another 3x3 grid.
I was trying to put an Overlay over the Inner grid in one cell, but I didn't find how to do it.
I found some examples like this one
Overlay / hover a div in flexbox container div
but it don't work in nested flex-box, or I don't know how to set them up.
here is the html, the grid has just two cell to take up less space, it actually is done with JQuery but for the example lets use only 2.
.Region{
position: absolute;
top: 10px;
left: 10px;
width: 500px;
height: 500px;
border: 5px double black;
display: flex;
}
.FlexContainer{
display: flex;
flex-direction: column;
flex-grow: 1;
}
.FlexContainer > div{
flex-grow: 1;
flex-basis: 0;
border: 3px solid blue;
display: flex;
flex-direction: row;
margin: 5px;
}
.FlexContainer > div > div{
flex-grow: 1;
flex-basis: 0;
border: 1px solid red;
margin: 3px;
display:flex;
flex-direction: row;
}
.Overlay{
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(013, 130, 230, 0.5);
cursor: not-allowed;
}
<div class="Region">
<div class="FlexContainer">
<div>
<div>
<div class="FlexContainer">
<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></div>
</div>
<div>
<div>
<div class="FlexContainer">
<div class="Overlay"></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>
I have tried with the Overlay inside and outside the Inner FlexContainer, but didn't work.
Finally got it to work, indeed the parent container must have relative position for it to work, so there is two change, one in the FlexContainer and other in the Overlay
.FlexContainer{
position:relative; <-- ADD THIS
display: flex;
flex-direction: column;
flex-grow: 1;
}
.FlexContainer .Overlay {
position: absolute;
top: 0px;
left: 0px;
margin: 0px;
border: 0px;
width: 100%;
height: 100%;
background-color: rgba(013, 130, 230, 0.5);
cursor: not-allowed;
}
Code Pen solution https://codepen.io/anon/pen/dKaXqg
Credits to user Pogany from the css-tricks web site
CSS-TRICKS thread: https://css-tricks.com/forums/topic/add-and-overlay-div-in-nested-flex-box-container/#post-273437

adjust width of inner / child elements

I have a parent DIV which may have 1,2 or 3 child elements. If the parent has only one element the child should have 100% width, if 2 then each element should have 50% of available width and in case of 3 elements each child should have 33.3333% of width.
If you want to avoid tables and are fine with flexbox (which is supported by all modern browsers), your solution would be simply
.container {
display: flex;
align-items: stretch;
}
.container > * {
display: block;
width: 100%;
}
with
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
(works fine for more elements as well).
/* solution */
.container {
display: flex;
align-items: stretch;
}
.container > * {
display: block;
width: 100%;
height: 100%;
}
/* for demo */
.container {
height: 30px;
}
.container > * {
height: 100%;
}
.container > :first-of-type {
background-color: red;
}
.container > :nth-of-type(2) {
background-color: green;
}
.container > :nth-of-type(3) {
background-color: blue;
}
<h3>one item</h3>
<div class="container">
<div></div>
</div>
<hr>
<h3>two items</h3>
<div class="container">
<div></div>
<div></div>
</div>
<hr>
<h3>three items</h3>
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
Use table layout
.wrap{
border: 1px solid green;
min-height: 100px;
display: table;
width: 100%;
}
.wrap > div{
border: 1px solid red;
display: table-cell;
}
<div class="wrap">
<div class="box">div 1</div>
<div class="box">div 2</div>
<div class="box">div 3</div>
</div>

Add border depending on last elements

I have a parent div#main that contains unknown number of divs in rows. Every row has 3 divs that are display: inline-block. Now, because of that, the last row can contain 1, 2 or 3 divs, depending on their number.
If the last row has only 1 div, then I want do add border-left and border-right to it.
If the last row has 2 divs, then I want do add border-right to the first div in that row, or border-left to the second div.
And if the last row has 3 divs, then I want to add border-left and border-right to to the second div (the middle one).
(You'll get the full picture when you look at the snipper, or the fiddle)
I managed to solve this issue by using JS, but I'm looking for a pure CSS solution, if there is one.
$('.main').each(function(){
var div_length = $(this).find('div').length;
if((div_length % 3) === 0){
div_last_items = div_length;
}
else if((div_length % 3) === 1){
div_last_items = div_length - 1;
$(this).find('div:nth-last-child(1)').addClass('active-borders');
}
else if((div_length % 3) === 2){
div_last_items = div_length - 2;
$(this).find('div:nth-last-child(2)').addClass('active-border');
}
$(this).find('div:lt('+div_last_items+')').each(function(i){
i=i+2;
if(i % 3 === 0){
$(this).addClass('active-borders')
}
});
});
.main {
width: 360px;
text-align: center;
}
.main>div {
display:inline-block;
vertical-align:top;
width: 100px;
height: 100px;
background:red;
margin-top: 10px;
margin-bottom: 10px;
}
.main>div:nth-child(3n+2) {
margin-left: 20px;
margin-right: 20px;
}
.active-borders{
border-left: 5px solid black;
border-right: 5px solid black;
}
.active-border{
border-right: 5px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<hr>
<div class="main">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<hr>
<div class="main">
<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>
JSFiddle
I never thought this would be possible with pure CSS but it is. All credits would go to this answer for showing an idea on how this could be achieved. This answer is based on that but I am drafting a separate answer because the selectors are a bit different here and I wanted to explain them.
Selector Additions:
div > div:nth-child(3n) + div:nth-last-child(1) {
border-left: 5px solid black;
border-right: 5px solid black;
}
div > div:nth-child(3n+1) + div:nth-last-child(1) {
border-left: 5px solid black;
}
div > div:nth-child(3n+1) + div:nth-last-child(2) {
border-left: 5px solid black;
border-right: 5px solid black;
}
Explanation:
div > div:nth-child(3n) + div:nth-last-child(1)
Select the last child of the parent div when it immediately follows the 3nth child. If the last child immediately follows the 3nth child then it would obviously be the only item in the last row.
div > div:nth-child(3n+1) + div:nth-last-child(1)
Select the last child of the parent div when it immediately follows the 3n+1th child. If the last child immediately follows the 3n+1th child then it means that the last row has 2 items.
div > div:nth-child(3n+1) + div:nth-last-child(2)
Select the second last child of the parent div when it immediately follows the 3n+1th child. If the second last child immediately follows the 3n+1th child then it means that the last row has 3 items.
We cannot use the selector div > div:nth-child(3n+2) + div:nth-last-child(1) for the case where the last row has 3 items because we need the middle element to be styled and not the last,
.main {
width: 360px;
text-align: center;
}
.main>div {
display: inline-block;
vertical-align: top;
width: 100px;
height: 100px;
background: red;
margin-top: 10px;
margin-bottom: 10px;
}
.main>div:nth-child(3n+2) {
margin-left: 20px;
margin-right: 20px;
}
div > div:nth-child(3n) + div:nth-last-child(1) {
border-left: 5px solid black;
border-right: 5px solid black;
}
div > div:nth-child(3n+1) + div:nth-last-child(1) {
border-left: 5px solid black;
}
div > div:nth-child(3n+1) + div:nth-last-child(2) {
border-left: 5px solid black;
border-right: 5px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<hr>
<div class="main">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<hr>
<div class="main">
<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>
The selectors in the above snippet adds a border-left to the second div in the last row if it has only 2 items. If you need to apply border-right to the first div in the last row when it has only 2 items, you can make use of the below selector:
div > div:nth-child(3n+1):nth-last-child(2)
This means, select the second last child of the parent div when it also happens to be the 3n+1th div. If this selector is matched, it implies that the last row has two items.
.main {
width: 360px;
text-align: center;
}
.main>div {
display: inline-block;
vertical-align: top;
width: 100px;
height: 100px;
background: red;
margin-top: 10px;
margin-bottom: 10px;
}
.main>div:nth-child(3n+2) {
margin-left: 20px;
margin-right: 20px;
}
div > div:nth-child(3n) + div:nth-last-child(1) {
border-left: 5px solid black;
border-right: 5px solid black;
}
/*div > div:nth-child(3n+1) + div:nth-last-child(1) {
border-left: 5px solid black;
}*/
div > div:nth-child(3n+1):nth-last-child(2){
border-right: 5px solid black;
}
div > div:nth-child(3n+1) + div:nth-last-child(2) {
border-left: 5px solid black;
border-right: 5px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<hr>
<div class="main">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<hr>
<div class="main">
<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>
In general adding border changes border-box dimension of the element. That change of geometry by itself may move element to the next row. Chicken-egg problem.
Thus you cannot do that by CSS means. And even with JS you should be careful - you may get not you want in some circumstances.

Resources