Is there a way to fill a grid from the center?
I have a CSS grid container which has a dynamic content(it gets updated so the number of children is not fixed) that looks like this:
#container {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
}
and if I had all 4 columns filled it would look like this :
1 2 3 4 //Numbers that represent containers children
Which is okay for me, but the problem comes when I have, for instance, only two divs inside my main container and then it looks like this:
1 2 0 0
And what I would like to achieve is this:
0 1 2 0
NEW ANSWER:
If you want to stick to just grid and assuming you only have four columns and the possible configurations are 0 1 0 0, 0 1 1 0, 0 1 1 1, 1 1 1 1 then following CSS works:
.container {
display: grid;
grid-template-columns: 25% 25% 25% 25%;
}
.col {
height: 50px;
background: green;
}
.col:first-child {
grid-column-start: 2;
}
.col:first-child:nth-last-child(4) {
grid-column-start: 1;
}
Assuming the HTML you have:
<div class="container">
<div class="col">
Col
</div>
<!-- Other Cols Here -->
</div>
Working Fiddle
ORIGINAL ANSWER:
For grids, it's not possible to center a dynamic number of elements. Grid layout is suitable for layouts with a fixed number of elements.
Refer to the use of grid vs flex layouts. Your problem is more suitable to be solved by flex where you use justify-content: center on flex containers to achieve centered children.
To achieve centered children, modify your styles on #container div:
#container {
display: flex;
justify-content: center;
}
Scenario where you want 0 1 0 0, 0 1 1 0, 0 1 1 1, 1 1 1 1 and assuming there are only four columns:
.container {
display: flex;
justify-content: center;
}
.col {
width: 25%;
height: 50px;
background: green;
}
.col:last-child:not(:nth-child(even)):first-child {
margin-left: -25%;
}
.col:last-child:not(:nth-child(even)):not(:first-child) {
margin-right: -25%;
}
I assume your markup will be something like this:
<div class="container">
<div class="col">
Col
</div>
<!-- Other Columns Go Here -->
</div>
Working Fiddle
As everyone already stated Flexbox is much suited for this, However (if i'm not missing anything)
A combination of the following properties should do the trick
grid-auto-flow: column;
grid-auto-columns: 25%; // assumes 4 columns
justify-content: center;
document.querySelectorAll('input')[0].onclick = () => { document.querySelector('[container]').append(document.createElement('div'))}
document.querySelectorAll('input')[1].onclick = () => {document.querySelector('[container]').innerHTML = '<div></div>';}
body * {
padding: 10px;
border: 1px solid;
}
[container] {
display: grid;
grid-auto-flow: column;
grid-auto-columns: 25%;
justify-content: center;
}
[container]>div {
height: 50px;
background: orange;
}
<input type="button" value="Add Column" />
<input type="button" value="reset" />
<div container>
<div></div>
</div>
Related
This question already has answers here:
Fill the remaining height or width in a flex container
(2 answers)
Closed 2 years ago.
I have a flex-container(row), where Im looking for the first object to be left justified at a static width, and then for the next object to be centered and fill the remainder of the container.
[ (obj1) | <----------(obj2)---------> ]
I know that I could accomplish this easier with the grid styling below, but my goal here is to educate myself in flex.
display:grid;
grid-template-columns: 100px 1fr;
Thanks!
Please see the code snippets for the flex implementation.
.wrapper {
display: flex;
}
.obj-a {
background: lime;
flex-basis: 100px;
}
.obj-b {
background: skyblue;
flex-grow: 1;
display: flex;
justify-content: center;
}
<div class="wrapper">
<div class="obj-a">obj-a</div>
<div class="obj-b">obj-b</div>
</div>
yes this can be done in flex
best read is here
you need to use
flex-shrink, flex-grow, flex-basis the short form as below
flex: shrink grow basis ie. flex: 1 1 auto
below is the example I use flex short-form and added a border for representation purposes.
* {
borx-sizing: border-box;
}
.flex-container {
display: flex;
flex-direction: row;
border: 1px solid black;
height: 200px;
padding: 1em;
}
.flex-container .left {
width: 100px;
border: 2px solid red;
height: 200px;
}
.flex-container .main {
flex: 1 1 auto;
border: 2px solid green;
height: 200px;
}
<div class="flex-container">
<div class="left"></div>
<div class="main"></div>
</div>
I want to arrange 3 divs, according to the screen width as follows:
For screen-width of < 500px arrangement should be as follows :
For screen-width of > 500px arrangement should be as follows :
I have tried achieving this in screen size of > 500px but i don't know how to use the same code to achieve arrangement for <500px.
My doubt is, can I use the same piece of code to get both the arrangements or is there any other approach ? Can flexbox be used to solve the issue?
Here is the snippet:
.container {
display: flex;
}
.divA {
flex: 0 0 40%;
align-self: flex-end;
}
.container-2 {
display: flex;
flex: 0 0 60%;
flex-direction: column;
}
<div class="container">
<div class="divA">
A
</div>
<div class="container-2">
<div class="divB">
B
</div>
<div class="divC">
C
</div>
</div>
</div>
edit
after seeing your question update , mediaquerie, flex, order , and a pseudo to create that empty gap , should be enough. Still with each 3 boxes direct child of .container.
run the code snippet in fullpage mode and resize your browser , break point set at 700px for the demo.
* {
box-sizing: border-box;
margin: 0;
}
.container {
display: flex;
flex-wrap: wrap;
}
.divA {
background: lightgreen;
}
.divB {
background: lightblue;
}
.divC {
background: rgb(255, 255, 0);
}
.container>div,
.container:before {
flex: 1;
min-width: 40%;
padding: 1em 0;
text-align: center;
}
#media (min-width: 700px) {
/* upadte here the px value where you swhitch to happen . 500px */
.divA,
.divC {
order: 1;
flex: 0 1 40%;
}
.container .divB,
.container .divC {
flex: 0 1 60%;
}
.container:before {
content: "";
flex: 0 1 40%;
}
}
<div class="container">
<div class="divA">
A
</div>
<div class="divB">
B
</div>
<div class="divC">
C
</div>
</div>
original answer left here for infos
you may switch from a flex layout to a table or grid layout with each elelemnts as sibblings, no need of extra markup here.
exemple : flex/table , it would be for browser still having issues with grid
.container {
display: flex;
flex-wrap: wrap;
}
.container>div {
flex: 1;
border: solid;
min-width: 40%;
}
/* set here the width where you want switching layout */
#media screen and (max-width: 600px) {
.container {
display: table;
width: 100%;
table-layout: fixed;
;
}
.divA {
display: table-cell;
width: 50%;
}
<div class="container">
<div class="divA">
A
</div>
<div class="divB">
B
</div>
<div class="divC">
C
</div>
</div>
or grid (mind version of IE which supports grid partially and requires to set grid-row/grid-column or grid-area for each children)
.container {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
.container>div {
border: solid;
}
.divC {
grid-row: 2;
grid-column:1 / span 2;
}
/* set here the width where you want switching layout */
#media screen and (max-width: 600px) {
.divC {
grid-row: 1 / span 2;
grid-column: 1;
}
<div class="container">
<div class="divA">
A
</div>
<div class="divB">
B
</div>
<div class="divC">
C
</div>
</div>
How:
This can be achieved with css grid
If you are open to grid solution, You need to change your html structure a bit. With flex that's impossible.
Solution:
Here is what I would do:
.container {
display: grid;
grid-template-columns: 50% 50%;
grid-template-rows: 200px 200px;
grid-gap: 0;
}
.divA {
background-color: lightgreen;
}
.divB {
background-color: lightblue;
}
.divC {
grid-column: 1 / span 2;
background-color: yellow;
}
#media screen and (min-width: 500px) {
.divA {
grid-column: 2 / 1;
grid-row: 2 / 2
}
.divB {
grid-column: 2 / 2;
grid-row: 1 / 1;
}
.divC {
grid-column: 2 / 2;
grid-row: 2 / 2;
}
}
<div class="container">
<div class="divA">
A
</div>
<div class="divB">
B
</div>
<div class="divC">
C
</div>
</div>
Explanation:
grid-template-columns lets you define the column widths of your
grid elements, and same does the grid-template-rows for rows
heights.
For each grid element, you can specify how many elements they should
span ( such as table cell can span columns or rows ) with
grid-column. Learn more
here or google
this property. Your divC has spanned 2 elements in a column.
Now for your responsiveness, write a media query to define your
styles for screen-width more than 500px, and reset your .divCs
grid-column and grid-row and add the same for your .divA. (Since this element now spans 2 elements in a row)
I have two columns. The first column contains several items. I want the last item to be vertically centered in the remaining empty space.
For example, if the left column was 4 inches high, contained 3 items, and the first two items were taking up the top 2 inches, then the last item would be vertically centered in the bottom two inches.
To do this, I am trying to use FlexBox for the first time and failing miserably. I am able to vertically center the whole left column (if I put align-items: center; under .row), but I cannot get it to work by putting align-items: center; under .lastitem.
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}
.column {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
}
.lastitem{
align-items: center;
}
Any help is much appreciated.
Added: I'm sorry, I'm not sure how to just share the relevant code. Here is a link to the test page in question: njfilmschool.com/homenew4.php All I'm trying to do it make it so the "Laurel Image" is centered vertically below the Instagram feed and above the footer line. But because the page is generated dynamically that empty space changes size. It seems like FlexBox should let me do this, but what I'm doing is having no effect on the image.
I can suggest you a flexbox solution if you are ready to show the whole code. Probably you are missing display: flex on the .lastitem and hence the align-items: center is not being rendered by the DOM.
At this moment, I have a nested CSS Grid solution below:
.container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr) 2fr; /* One inch - One Inch - Two Inch Inches are fractions here*/
grid-column-gap: 10px;
grid-row-gap: 10px;
background: #6A67CE;
padding: 15px;
}
.div1 {
grid-area: 1 / 1 / 2 / 2; /* Start at Row1, end at Row2, Start at Col1. end at Col2 */
}
.div2 {
grid-area: 2 / 1 / 3 / 2;
}
.div3 {
grid-area: 3 / 1 / 4 / 2;
display: grid;
/* Nested Grid */
align-items: center;
}
/* Snippet styling */
.container > div {
background: #5548B0;
text-align: center;
color: #fff;
font-size: 36px;
padding: 15px;
}
<div class="container">
<div class="div1"> 1 </div>
<div class="div2"> 2 </div>
<div class="div3"> 3 </div>
</div>
If I have a 3 column grid and I want the content to appear in the 2 column: am I understanding correctly that the content HAS to go in the 2nd column in the HTML, and I have to create an empty div in the HTML?
In the grid below I want the title to appear in the middle column so I've created an empty div before this.
There's no way of getting the title to appear in the middle one of the 3 columns whilst only using one div is there?
** Note I haven't included a div for the 3rd column because I don't need to.
Codepen: https://codepen.io/emilychews/pen/rEoKPg
Code snippet also included below.
body {
margin: 0;
padding: 0;
display: flex;
height: 100vh;
width: 100%;
justify-content: center;
align-items: center;
}
.row {
width: 50%;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 1rem;
}
.grid {
background: #f1f1f1;
padding: 1rem;
}
<div class="row">
<div class="grid grid-item-1"></div>
<div class="grid grid-item-2">The Title</div>
</div>
You don't have to create an empty div if you use grid-column-start, but you will need to specify the column number.
<div class="row">
<div class="grid grid-item-2">The Title</div>
</div>
body {
margin: 0;
padding: 0;
display: flex;
height: 100vh;
width: 100%;
justify-content: center;
align-items: center;
}
.row {
width: 50%;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 1rem;
}
.grid {
background: #f1f1f1;
padding: 1rem;
}
.grid-item-2 {
grid-column-start: 2;
}
Yes, you can. Remove the first div then add this to your css code:
.grid-item-2 {
grid-column-start: 2;
}
Check this article on CSS Tricks with a quick cheatsheet on CSS Grids: A Complete Guide to Grid | CSS Tricks
The MDN reference is very good also: CSS Grid Layout | MDN
I'm using the grid layout in CSS and my aim is to have an image, text, an input field and a button next to each other, spanning over two rows as illustrated here:
I've given the image the grid-column property of 1 / 1 so that it is only in the first column, and all the other elements have 2 / 2 so that they are in the second column.
The problem I'm facing is that the second column is overlapping the first column, as seen in this snippet:
.profile {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: 20px;
}
img {
border-radius: 50%;
height: 100%;
margin-right: 2%;
grid-column: 1 / 2;
grid-row: 1 / 2;
}
.profile>*:not(img) {
grid-column: 2 / 3;
}
.sameline {
display: flex;
align-items: center;
justify-content: space-between;
}
<div class="profile">
<img src="https://image.ibb.co/nr3C7T/pic.png">
<div class="sameline">
<h2>Title</h2>
<button>Click</button>
</div>
<form method="post">
<input type="text">
</form>
</div>
All you had to do was increase grid-column-gap. This makes them non overlapping. Change the styling to suit your needs.
.profile {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: 100px;
}
img {
border-radius: 50%;
height: 100%;
margin-right: 2%;
grid-column: 1 / 1;
grid-row: 1 / 2;
}
.profile>*:not(img) {
grid-column: 2 / 2;
}
.sameline {
display: flex;
align-items: center;
justify-content: space-between;
}
<div class="profile">
<img src="https://image.ibb.co/nr3C7T/pic.png">
<div class="sameline">
<h2>Title</h2>
<button>Click</button>
</div>
<form method="post">
<input type="text" style="width:100%;">
</form>
</div>
Hope this helps.
I'm not sure if I understand your problem correctly, but I think what you mean is that the second column in the second row is overlapping.
The grid-row property is not correctly used in this case. This property works with grid lines. So the first value is used to specify from which grid line the item starts, and the second one specifies the grid line where it should end. So in your case, you say that it should start from grid line 1 (so essentially the top border of the grid) and that it should end at grid line 2 (which is the grid line between the two columns).
What you actually want is for the image to start at grid line 1 and end at grid line 3, so that it covers both of rows. The same rule applies to the grid-column property.
.profile {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: 100px;
}
img {
border-radius: 50%;
height: 100%;
margin-right: 2%;
grid-column: 1 / 2;
grid-row: 1 / 3;
}
.profile>*:not(img) {
grid-column: 2 / 3;
}
.sameline {
display: flex;
align-items: center;
justify-content: space-between;
}
<div class="profile">
<img src="https://image.ibb.co/nr3C7T/pic.png">
<div class="sameline">
<h2>Title</h2>
<button>Click</button>
</div>
<form method="post">
<input type="text">
</form>
</div>