How to create a CSS GRID with 3 distinct head elements - html

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>

Related

How to insert div at the end of a grid?

I have the following code:
.my-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
grid-gap: 20px;
}
.item {
background-color: #ddd;
height: 300px;
}
<div class="my-grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="new-item">hello!</div>
Which looks like this in my testing:
Notice how the hello is on the next row.
Is there any way to instead have it inserted after the grid above? Such that it is the last grid item? Such that it is in line with it, instead of being on the next row.
The obvious solution is to just place the new-item div as a child of my-grid, but I cannot do that in my case, because my-grid is an external component from the internet, so I cannot insert something inside of it.
These two elements also have a common parent as well. Which can be anything.
You can consider display: contents if they share the same container:
/* transfer all the styles to container
in the near future you can do .container:has(.my-grid) {}
*/
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
grid-gap: 20px;
}
.item {
background-color: #ddd;
height: 300px;
}
/* we remove "my-grid" div*/
.my-grid {
display: contents;
}
<div class="container">
<div class="my-grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="new-item">hello!</div>
</div>
You can set absolute position on "new-item" and if you have a div container above "my-grid" do not forget to set "position: relative", on it. Then you can adjust the left and top of "new-item", relative to the main div container. Might course some problem in different resolutions of the screen, adress it with some media queries.

How do dynamically position and size div elements?

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%;
}
}

Fully responsive items with CSS grid and auto-fit minmax

The use of grid-template-columns: repeat(auto-fit, minmax(600px, 1fr)) makes it easy to build a responsive CSS grid. The container will be filled with as many elements fit into a row, without using a media query.
.container {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
}
.item {
height: 100px;
background: #ccc;
}
<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>
The problem is that the items are wider than the screen when the screen is smaller than the min-value specified in minmax(). You can fix this by adding a media query at 400px, but this only works when you know that there's no content around the container. And that's almost impossible when the container could be placed anywhere.
Is there a way or property to tell the items that they should never be wider than 100%?
Something like: Fill the container with as many 400px items as possible, but ensure that non of them gets wider than 100% of the width of the container.
CodePen Demo
You should change grid-template-columns to grid-template-columns: repeat(auto-fit, minmax(min-content, 400px)) because minmax works this way: it tries to apply max value and if fails it applies minimum. But in this you can get blank space in your grid to the right. Demo:
.container {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(auto-fit, minmax(min-content, 400px));
}
.item {
height: 100px;
background: #ccc;
}
<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>
Fill the container with as many 400px items as possible, but ensure that non of them gets wider than 100% of the width of the container.
For that you can use the "max-content" property, in your example this would be:
.unresponsive {
grid-template-columns: repeat(auto-fit, minmax(400px, auto));
grid-auto-columns: max-content;
}

Responsive Layout with same growing gaps in each row

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>

CSS - How to stack divs by columns of 2

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>