I am trying to use CSS grid to setup a form that has three columns: the first column is used to display the label for the input that will be listed in the second column. The third column is used to get the correct spacing of the form on the page and allow the form to scale to the page size.
I am able to separate the form labels and form inputs into columns one and two respectively, however when I cannot make a new section of the form that is centered between these two columns, it will either be in column one labels or column two data.
.formContainer {
display: grid;
grid-template-columns: [labels] auto [data] auto 1fr;
grid-auto-rows: auto;
grid-row-gap: 5px;
margin-top: 3%;
margin-left: 12%;
margin-right: 3%;
}
.formContainer>label {
grid-column: labels;
}
.formContainer>div {
grid-column: data;
}
.matches {
grid-column-start: labels !important;
grid-column-end: data !important;
}
<div class='formContainer'>
<label>
<span>Name</span>
</label>
<div>
<input type="text" />
</div>
<div class='matches'>
<div>No matches yet!</div>
</div>
</div>
I have also tried making the matches div a different HTML element such as article or span which did not work either. Any help with trying to figure out how to make the matches class span between both of these columns would be greatly appreciated.
As per my comments above, you can use grid-column: span 2 to the matches element to allow it to occupy two columns and then add text-align: center to center in that space.
Also note I've used .formContainer > .matches instead of .matches for specificity of styles (grid-column definition in .formContainer > div was overriding the grid-column in .matches as it is more specific) - see demo below:
.formContainer {
display: grid;
grid-template-columns: [labels] auto [data] auto 1fr;
grid-auto-rows: auto;
grid-row-gap: 5px;
grid-column-gap: 10px; /* added */
margin-top: 3%;
margin-left: 12%;
margin-right: 3%;
}
.formContainer > label {
grid-column: labels;
}
.formContainer > div {
grid-column: data;
}
/* changed below */
.formContainer > .matches{
grid-column: span 2;
text-align: center;
}
<div class='formContainer'>
<label>
<span>Name</span>
</label>
<div>
<input type="text" />
</div>
<div class='matches'>
<div>No matches yet!</div>
</div>
</div>
Related
I am trying to understand how CSS grids work. I've tried to make an example of a store item as practice, but I am at a loss.
Here's my how my CSS currently looks. Cut off at the top, weird spacing, and the right side is not coming together at all.
How's how it would ideally look
Here is my current CSS, I hope someone can help explain where I am misunderstanding the use of
CSS grids.
.store-currency {
height: 3vh;
}
.item {
display: flex;
align-items: center;
grid-row: 1 / span 2;
}
.currency {
display: flex;
align-items: center;
}
#num-bought-item0 {
display: flex;
align-items: center;
justify-content: right;
margin-right: 10px;
grid-column: 1 / span 2;
}
.store-item {
height: 15vh;
width: 100%;
display: grid;
grid-template-columns: 2fr;
grid-template-rows: 1fr 1fr;
font-size: 24px;
color: white;
border: 5px white solid;
justify-content: left;
align-items: center;
}
.store-item img {
margin: 10px;
height: 8vh;
}
.store-container {
display: flex;
height: 100%;
width: 30vw;
z-index: 0;
background-color: saddlebrown;
left: 0;
position: absolute;
text-align: center;
}
HTML:
<div class="store-container">
<div class="store-item" id="item0">
<div class ="item">
<img src="dumbell.png" alt="">
<span>Dumbbell</span>
</div>
<div id="num-bought-item0">
<span>Owned</span>
<span id="count-item0">0</span>
</div>
<div class="currency">
<img class="store-currency" src="coin.png" alt="">
<span>100000</span>
</div>
</div>
you did the first steps.
To get started you have to define a container element as a grid with display: grid, set the column and row sizes with grid-template-columns and grid-template-rows, and then place its child elements into the grid with grid-column and grid-row.
.store-container {
display: grid | inline-grid;
}
grid – generates a block-level grid
inline-grid – generates an inline-level grid
With grid-template-columns you can define how many columns will appear in your layout.
P.S Fr unit is a fractional unit and 1fr is for 1 part of the available space. In this example each column would take ~ 25% from the available space.
.container {
grid-template-columns: 1fr 1fr 1fr 1fr;
}
For your task, you can use grid-template-areas feature.
The grid-template-areas CSS property specifies named grid areas,
establishing the cells in the grid and assigning them names.
For example:
.item-a {
grid-area: header;
}
.item-b {
grid-area: main;
}
.item-c {
grid-area: sidebar;
}
.item-d {
grid-area: footer;
}
.container {
display: grid;
grid-template-columns: 50px 50px 50px 50px;
grid-template-rows: auto;
grid-template-areas:
"header header header header"
"main main . sidebar"
"footer footer footer footer";
}
This will generates something like that in modern browsers:
If you need more examples, take a look here:
https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas
https://css-tricks.com/snippets/css/complete-guide-grid/
Some of the examples are taken from the second site.
It looks like you are mixing flex and grid properties. grid-row and grid-column are only avalaible for a grid display (2D), not a flex display (1D).
You can try to play around with flex (worse choice since it is drawing a 1D layout) , you can use grid , which is made for this kind of layout.
Here a couple example with flex and grid
/* GRID make it simple*/
.grid {display:grid;}
#num-bought-item2 {grid-row:1/3;grid-column:2;}
#num-bought-item2 {display:grid;margin:auto;text-align:center}
/* layout done */
/* some reset for the demo*/
*{box-sizing:border-box;}
.store-container {display:grid;justify-content:center;}
.store-item {border:solid;}
.store-item>div {padding:0.5em;}
img{vertical-align:middle;}
[src="https://dummyimage.com/25/ff0"]{border-radius:50%}
big{color:darkgreen;background:lightyellow;}
/* FLEX make it a mess */
.flex {display:flex}
.column {flex-flow:column wrap;height:120px;}/* here an height is to be set so it wraps*/
/* since it is not made for this, we need to mess around */
.flex #num-bought-item1{order:2}/* reorder item */
.flex .item {height:0;min-height:60%;}/* hide it, then show it */
.flex .currency {height:0;min-height:40%;}/* hide it, then show it */
.flex #num-bought-item1{display:flex;flex-direction:column;justify-content:center;text-align:center;margin:auto;}
/* and flex did not do it */
<p>Let's try via flex</p>
<div class="store-container">
<div class="store-item flex column" id="item1">
<div class="item">
<img src="https://dummyimage.com/50" alt="">
<span>Dumbbell</span>
</div>
<div id="num-bought-item1" >
<span>Owned</span>
<span id="count-item1">0</span>
</div>
<div class="currency">
<img class="store-currency" src="https://dummyimage.com/25/ff0" alt="">
<span>100000</span>
</div>
</div>
</div>
<p>And via <big>grid</big> </p>
<div class="store-container">
<div class="store-item grid" id="item2">
<div class="item">
<img src="https://dummyimage.com/50" alt="">
<span>Dumbbell</span>
</div>
<div id="num-bought-item2" >
<span>Owned</span>
<span id="count-item1">0</span>
</div>
<div class="currency">
<img class="store-currency" src="https://dummyimage.com/25/ff0" alt="">
<span>100000</span>
</div>
</div>
</div>
I used a CSS Grid Layout to display data in a table-like manner with the last column spanning multiple rows. While this basically works now , I absolutely cannot get the vertical alignment right. See the following snippet:
div {
border: 1px solid black;
padding: 3px;
}
.table {
display: grid;
grid-template-columns: min-content min-content min-content;
white-space: nowrap;
grid-auto-rows: auto;
grid-gap: 3px;
width: min-content;
grid-auto-flow: row dense;
}
.col1 {
grid-column-start: 1;
height: min-content;
}
.col2 {
grid-column-start: 2;
height: min-content;
}
.col3 {
grid-column-start: 3;
grid-row-end: span 2;
}
<div class="table">
<div class="col1">A1</div>
<div class="col2">B1</div>
<div class="col1">A2</div>
<div class="col2">B2</div>
<div class="col3">this<br>is<br>the first<br>very<br>very<br>long<br>cell</div>
<div class="col1">A3</div>
<div class="col2">B3</div>
<div class="col1">A4</div>
<div class="col2">B4</div>
<div class="col3">second cell</div>
</div>
I want the left two columns to always the minimum height and be aligned with the top of each multi-row cell. In this simplified example, that means that A2 and B2 should move up and be shown right under A1 and B1.
I also tried adding a dummy <div> before each col3 and make it take all extra height. But no matter what I tried, the height is always distributed equally among all rows.
Is there a way to make the cells top-aligned with the multi-row cell?
I'm having a problem with vertical alignment with my text lines. I have two text lines, <p>, and I want to put the second one in the bottom of my <div> so I tried to do vertical-align: bottom and text-bottom and the top and bottom ones in my <p> and that didn't work.
.header {
grid-area: header;
background-color: red;
display: grid;
grid-template-areas: 'headerLeft rest headerRight';
grid-template-columns: 10% 1fr 30%;
padding: 5px;
}
.header p {
margin: 0px;
}
.headerRight {
grid-area: headerRight;
}
.headerRight p {
float: right;
}
<div class="layout">
<div class="header">
<div class="headerRight">
<p style="margin: 0px 0px 0px 1px;"><img src="https://i.imgur.com/V2aWxOK.png" style="height: 13vh" /></p>
<p><img src="https://i.imgur.com/V2aWxOK.png" style="height: 13vh" /></p>
<p style="margin: 0px 5px 0px 0px">Ola</p>
<br />
<p style="margin: 0px 5px 0px 0px">Ola</p>
</div>
</div>
</div>
I'd suggest the following, which involves some minor updates to your HTML; explanations are in the comments to the code itself:
.header {
grid-area: header;
background-color: red;
display: grid;
grid-template-areas: 'headerLeft rest headerRight';
grid-template-columns: 10% 1fr 30%;
padding: 5px;
}
.header p {
margin: 0px;
}
.headerRight {
grid-area: headerRight;
/* here we specify the use of CSS Grid layout: */
display: grid;
/* define the top-and-bottom (0) and left-and-right (5px) grid
gap gutters: */
grid-gap: 0 5px;
/* define the named areas of the grid: */
grid-template-areas:
". paragraphAreaOne imageOne imageTwo"
". . imageOne imageTwo"
". paragraphAreaTwo imageOne imageTwo";
/* define the sizing of the columns; here we have the first column
taking up one fractional unit (1fr), with the other columns sized,
using the repeat() function, at min-content in order to have those
grid-columns sized to the minimum necessary to contain their content: */
grid-template-columns: 1fr repeat(3, min-content);
/* here we have three rows each sized, using the repeat() function,
to size each row to min-content: */
grid-template-rows: repeat(3, min-content);
}
/* positioning the various elements into the appropriate grid areas: */
.headerRight p:first-of-type {
grid-area: paragraphAreaOne;
}
.headerRight p:nth-of-type(2) {
grid-area: paragraphAreaTwo;
}
.headerRight img:first-of-type {
grid-area: imageOne;
}
.headerRight img:nth-of-type(2) {
grid-area: imageTwo;
}
<div class="layout">
<div class="header">
<div class="headerRight">
<!-- your img elements were wrapped in <p> elements, which were removed,
partially for semantic reasons, and partially because they were
simply unnecessary -->
<img src="https://i.imgur.com/V2aWxOK.png" style="height: 13vh" />
<img src="https://i.imgur.com/V2aWxOK.png" style="height: 13vh" />
<p>Ola</p>
<!-- there was a <br> element here which, when using a Grid layout
serves no purpose, so was removed -->
<p>Ola</p>
</div>
</div>
</div>
JS Fiddle demo.
References:
gap/ grid-gap
grid-template-areas.
grid-template-columns.
grid-template-rows.
min-content.
repeat().
you are using grid so u can use align-items:end to the header and it will align your elements to the bottom here take a look at it https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
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>
I was hoping to use CSS Grid to reverse the apparent order of two side-by-side divs, where one of the divs grows arbitrarily (I don't want to use floats).
I've created a plunkr here: http://plnkr.co/edit/6WZBnHbwhD7Sjx2ovCO7?p=preview
#container {
grid-template-columns: 240px 1fr;
display: grid;
}
.a {
background: yellow;
}
.b {
background: blue;
color: white;
}
#container>.a {
grid-column: 1;
}
#container>.b {
grid-column: 2;
}
#container.reverse>.a {
grid-column: 2;
}
#container.reverse>.b {
grid-column: 1;
}
<div id="container" class="reverse" style="width: 800px;">
<div class="a">A</div>
<div class="b">B</div>
</div>
The crux of it is that when I have the .reverse class applied (so that you should see B | A), B is offset to a new line so it looks more like:
| A
B
If I invert the document ordering of .a with .b, this goes back to normal (but of course, if I drop the .reverse class, I get the same problem).
Why is this, and how can I address?
As the Grid auto-placement algorithm lays out items in the container, it uses next available empty cells (source).
In your source code the A element comes before the B element:
<div id="container" class="reverse" style="width: 800px;">
<div class="a">A</div>
<div class="b">B</div>
</div>
Therefore, the grid container first places A, then uses the next available space to place B.
By default, the auto-placement algorithm looks linearly through the grid without backtracking; if it has to skip some empty spaces to place a larger item, it will not return to fill those spaces. To change this behavior, specify the dense keyword in grid-auto-flow.
http://www.w3.org/TR/css3-grid-layout/#common-uses-auto-placement
grid-auto-flow: dense
One solution to this problem (as you have noted) is to override the default grid-auto-flow: row with grid-auto-flow: dense.
With grid-auto-flow: dense, the Grid auto-placement algorithm will look to back-fill unoccupied cells with items that fit.
#container {
display: grid;
grid-template-columns: 240px 1fr;
grid-auto-flow: dense; /* NEW */
}
7.7. Automatic Placement: the grid-auto-flow
property
Grid items that aren’t explicitly placed are automatically placed into
an unoccupied space in the grid container by the auto-placement
algorithm.
grid-auto-flow controls how the auto-placement algorithm works,
specifying exactly how auto-placed items get flowed into the grid.
dense
If specified, the auto-placement algorithm uses a “dense” packing
algorithm, which attempts to fill in holes earlier in the grid if
smaller items come up later. This may cause items to appear
out-of-order, when doing so would fill in holes left by larger items.
#container {
display: grid;
grid-template-columns: 240px 1fr;
grid-auto-flow: dense; /* NEW */
}
.a {
background: yellow;
}
.b {
background: blue;
color: white;
}
#container>.a {
grid-column: 1;
}
#container>.b {
grid-column: 2;
}
#container.reverse>.a {
grid-column: 2;
}
#container.reverse>.b {
grid-row: 1;
grid-column: 1;
}
<div id="container" class="reverse" style="width: 800px;">
<div class="a">A</div>
<div class="b">B</div>
</div>
grid-row: 1
Another solution would be to simply define the row for the second item.
#container>.b {
grid-column: 2;
grid-row: 1; /* NEW */
}
#container {
display: grid;
grid-template-columns: 240px 1fr;
}
.a {
background: yellow;
}
.b {
background: blue;
color: white;
}
#container>.a {
grid-column: 1;
}
#container>.b {
grid-column: 2;
grid-row: 1; /* NEW */
}
#container.reverse>.a {
grid-column: 2;
}
#container.reverse>.b {
grid-row: 1;
grid-column: 1;
}
<div id="container" class="reverse" style="width: 800px;">
<div class="a">A</div>
<div class="b">B</div>
</div>
The simplest way is to add order: 1 to element B or order: -1 to element A in .reverse
It's also correct CSS rather than hack-y
I'm not sure how to reverse more grid items. But if you have 2 grid items in your grid, you can simply position 2nd grid item using below code.
#container > .b {
grid-column-start: 1;
grid-row-start: 1;
}
I had this same issue just now. I tried auto-row-dense and then set the direction of the container parent to rtl. It worked.
Just this, on the plunker link, seemed to do the trick.
.reverse{
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-flow: dense;
direction: rtl;
}
You can use direction property to reverse a grid x-axis order.
Nested elements will be reversed too so you have to make sure to add additional styles to fix this behavior.
<div class="grid">
<div class="grid-item"><div>
</div>
<style>
.grid { direction : rtl; }
.grid-item { direction : ltr; }
</style>
Edit: this may work but could cause accessibilty issues.
Round peg in square hole
Remember even if you're using fancy 'new' grid features the older flex layout will still work. You can combine them, nest them and sometime you have to admit that certain problems like this may just be better solved with good old
flex-direction: row-reverse
But I know some people will want to downvote me for that so here's another way with grid.
Use named template regions
You can use named template regions and reverse them in the definition.
#container
{
grid-template-areas: a b;
grid-template-rows: 240px 1fr;
display: grid;
}
#container.reverse
{
// note the order is flipped for both these properties
grid-template-areas: b a;
grid-template-rows: 1fr 240px;
}
.a {
grid-area: a;
background: yellow;
}
.b {
grid-area: b;
background: blue;
color: white;
}
Here's an more complex example that uses that technique with media queries
I found out: I need to apply grid-auto-flow: dense; on the container:
#container {
grid-template-columns: 240px 1fr;
display: grid;
grid-auto-flow: dense;
}
According to MDN, this algorithm attempts to fill in holes earlier in the grid.
I want to mention a solution which is also relevant to this question in some cases. When having a multi-row layout, and you want a reversed look of how you grid fills up.
You can play with grid-start combined with some :nth-child & :last-child selectors to achieve a reverse auto flow.
Reversed grid-auto-flow: column
.container{
display: grid;
width: 10rem;
gap: 0.5rem;
grid-template-rows: repeat(2, 1fr);
grid-auto-flow: column; /* => vertical grid*/
}
/* REMOVE THIS TO SEE THE DIFFERENCE */
.pixel:nth-child(odd):last-child { /* reversed auto-flow: column */
grid-row-start: 2;
}
.pixel{
width: 2rem;
height: 2rem;
background: red;
border: 1px solid black
}
<div class="container">
<!-- ADD/REMOVE SOME PIXELS to see the result -->
<div class="pixel"></div>
<div class="pixel"></div>
<div class="pixel"></div>
<div class="pixel"></div>
<div class="pixel"></div>
<div class="pixel"></div>
<div class="pixel"></div>
</div>
Reversed: horizontal & vertical
.container{
display: grid;
width: 10rem;
gap: 0.5rem;
grid-template-rows: repeat(2, 1fr);
grid-auto-flow: column;
direction: rtl; /* reversed horizontal */
}
/* REMOVE THIS TO SEE THE DIFFERENCE */
.pixel:nth-child(odd):last-child { /* reversed vertical */
grid-row-start: 2;
}
.pixel{
width: 2rem;
height: 2rem;
background: red;
border: 1px solid black
}
<div class="container">
<!-- ADD/REMOVE SOME PIXELS to see the result -->
<div class="pixel">1</div>
<div class="pixel">2</div>
<div class="pixel">3</div>
<div class="pixel">4</div>
<div class="pixel">5</div>
<div class="pixel">6</div>
<div class="pixel">7</div>
</div>
I found out: I need to apply grid-auto-flow: dense; on the container: