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.
Related
I'm building an app that needs a grid system, here's how far I've come:
I have a problem:
Each of the blocks should fill up the entire space of the grid
As you can see, the black block is not occupying the rest of the space. I want the boxes to occupy the rest white space(but all their widths should be the same).
I've read Expand a div to fill the remaining width and Make last element take remaining width with wrapping (and with IE9 support), but they don't answer the case of the dynamically wrapping grid that is here the important part since they are made for float and display: block.
Now let's look at the code:
HTML:
<div className='container'>
<div className="item"></div>
<div className="item"></div>
<div className="item"></div>
<div className="item"></div>
<div className="item"></div>
<div className="item"></div>
<div className="item"></div>
</div>
CSS:
container {
overflow: hidden;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
.item {
height: 300px;
min-width: 300px;
background-color: red;
border: 2px solid yellow;
}
.container is the grid parent and .items are the children. Keep in mind that the solution should work with any number of children(.item). Thank you in advance!
I think with plain css this is not possible using grid. You could use flexbox with flex-grow instead of grid but when two items wrap in the next line they both are expanded.
Working example (a bit smaller then your example):
I don't know what that className attribute in your divs is for, i presume you meant just "class" and used that, respectively an id in the container for simplicity.
#container {
overflow: hidden;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.item {
height: 120px;
min-width: 120px;
background-color: red;
border: 2px solid yellow;
flex-grow: 1;
}
#last {
flex-grow: 2;
}
<div id='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" id="last"></div>
</div>
If it is important to use grid it can be done with a small javascript function. Find out how many columns the grid has and in which column the item starts and set its gridColumnStart and gridColumnEnd so that it uses all the remaining grid areas. For beeing responsive you have to add an event listener that reacts on resize and calls the expand function.
Working example:
const container = document.querySelector('#container');
const last_item = document.querySelector('#last');
function expandLastItem() {
const container_style = window.getComputedStyle(container);
const item_style = window.getComputedStyle(last_item);
const offset_left = last_item.offsetLeft;
const grid_width = parseInt(container_style.width);
const item_width = parseInt(item_style.width);
const row_length = Math.floor(grid_width / item_width);
const grid_column = Math.floor(offset_left / item_width) + 1;
last_item.style.gridColumnStart = grid_column;
last_item.style.gridColumnEnd = row_length + 1;
}
window.addEventListener('resize', function() {
last_item.style.gridColumnStart = '';
last_item.style.gridColumnEnd = '';
expandLastItem();
});
expandLastItem();
#container {
overflow: hidden;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}
.item {
height: 120px;
min-width: 120px;
background-color: red;
border: 2px solid yellow;
}
<div id='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" id="last"></div>
</div>
If you are using jQuery the code gets a bit simpler.
Working example:
function expandLastItem() {
const offset_left = $('#last').offset().left;
const grid_width = parseInt($('#container').width());
const item_width = parseInt($('#last').width());
const row_length = Math.floor(grid_width / item_width);
const grid_column = Math.floor(offset_left / item_width) + 1;
$('#last')[0].style.gridColumnStart = grid_column;
$('#last')[0].style.gridColumnEnd = row_length + 1;
}
$(window).on('resize', function() {
$('#last')[0].style.gridColumnStart = '';
$('#last')[0].style.gridColumnEnd = '';
expandLastItem();
});
expandLastItem();
#container {
overflow: hidden;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}
.item {
height: 120px;
min-width: 120px;
background-color: red;
border: 2px solid yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='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" id="last"></div>
</div>
I'm using CSS grid to position a dynamic number of elements into rows using grid-auto-rows.
However the last element is always placed against the bottom of the page irrespective of any padding applied to the grid container (padding is applied to the top, left & right but not to bottom).
Does anyone know where I'm going wrong?
https://codepen.io/wrgt1/pen/XWjEwXX
#container {
position: relative;
width: 100%;
}
.grid {
width: 100%;
display: grid;
grid-auto-flow: row;
grid-auto-rows: 25%;
grid-template-columns: 1fr 1fr;
padding: 50px;
}
.item {
width: 250px;
height: 250px;
background: red;
}
<div id="container">
<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>
</div>
acutally, (just like #Shristi mentioned) the problem happens because the grid-container does not reach the bottom of the items. this happens because of the grid-auto-rows which is set to 25%. After the fourth row this fills the 100%, everything else just moves out of the container. So you should change your code as follows:
.grid {
// box-sizing: border-box;
width: 100%;
display: grid;
grid-auto-flow: row;
grid-auto-rows: 250px; // change this!
grid-template-columns: 1fr 1fr;
grid-gap: 50px; // use this for the spacing in between
padding: 50px; // use this for the spacing top, bottom, left and right of the grid
}
the working example: here
This is because the height of your grid is less than it's contents. Add height to your grid and margin-bottom instead of padding. Hope this might help
.grid {
width: 100%;
display: grid;
grid-auto-flow: row;
grid-auto-rows: 25%;
grid-template-columns: 1fr 1fr;
padding: 50px;
height: 100%;
margin-bottom: 50px;
overflow-y: scroll;
}
Sometimes padding does not work in HTML so in that case, you can either make div or use the br tag.
<div class="spacing" style="padding-bottom: 100px;">
// or do br where you want it.
<br>
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>
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;
}
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>