I want to use percentages in my css for my react app but it's causing such a headache. Width % work fantastic all the time but the height % is always an issue. It seems almost like I HAVE to specify a height in pixels for it to work work unless the element contains children.
Am I missing something fundamental here. Will a div not set itself to 100% of the remaining height without child elements. The below code doesn't work despite me setting the align-items property to stretch.
.search-container{
display: grid;
grid-template-columns: auto 900px 300px auto;
grid-template-rows: 30% auto auto;
grid-gap: 20px;
}
.promo-container {
background-color:blue;
grid-column-start: 2;
grid-column-end: 3;
align-items: stretch;
}
.form-container {
background-color:blue;
grid-column-start: 3;
grid-column-end: 4;
align-items: stretch;
}
.results-header {
background-color:rgb(255, 94, 0);
grid-column-start: 2;
grid-column-end: 4;
height: 90px;
}
.refine-search {
background-color:blue;
grid-column-start: 2;
grid-column-end: 3;
height: 100%;
}
.results-container{
background-color:rgb(0, 255, 42);
grid-column-start: 2;
grid-column-end: 3;
}
<div className="search-container">
<div className="promo-container">
</div>
<div className="form-container">
</div>
<div className="results-header">
</div>
<div className="refine-search">
</div>
<div className="results-container">
</div>
</div>
You need to set the height of your parent elements.
html, body, div {
height: 100%;
width: 100%;
}
The problem with height is that you need to have some childrens in order to work. So if you want to see the blank space where is supposed to be the childrens ( the rest of the elements) you indeed have to set pixels, rem, fr, etc. Otherwise The grid won't allow the blank space to be there if there's nothing in there. For example if I want to see my remaining space I can say:
`.someClass {
display: grid;
/* I'm setting the rows to be 3 row with a given space of 1 fr
each row will be placed with given space unit */
grid-templates-rows: repeat(3, 1fr);
grid-template-columns: repeat(5, 1fr);
}`
Otherwise if you want to create the grid depending automatically on the availaible space you can set everything to auto like so:
.someotherClass {
display: grid;
/* grid template areas is the combination of the template rows and columns */
grid-templates-areas: auto;
}
Of course with the auto I can still order my items on the rows and columns that I want but the space will be adjusted accordingly with each element
To give you some idea how the grid works check out this page: https://cssgridgarden.com/
Hope helps :)
Related
I have a <section> element which must not be larger than 100vh and no wider than 100vw. Ideally it should follow its parent containers dimensions.
The <section> should have a grid layout using css variables; var(--cols, 56) and var(--rows, 32)
Each cell in the grid must be 1:1 ratio, meaning that the cell width must always === cell height.
The <section> element should grow if the viewport (parent element) grows, unless this makes the cells not square. If this is the case, the <section> element should be centered. So if the viewport width becomes larger and viewport height becomes smaller, the <section> is centered horizontally. But if the viewport height becomes larger and viewport width becomes smaller, the <section> element is centered vertically.
This is what I have so far:
<section #widgets>
<ng-container *ngFor="let widget of widgetConfig">
<ng-container [libTileContainer]="widget"></ng-container>
</ng-container>
</section>
section {
display: grid;
gap: 5px;
grid-template-columns: repeat(
var(--cols, 56),
calc(((100vw - (var(--cols, 56) * 5px) - 2rem) / (var(--cols, 56))))
);
grid-template-rows: repeat(
var(--rows, 32),
calc(((100vw - (var(--cols, 56) * 5px) - 2rem) / (var(--cols, 56))))
);
max-width: 100%;
max-height: 100%;
}
This respects the cells squareness, but it bleeds out of it's parent.
The calculations will also only respect viewport width and not height.
How can I achieve what I want?
To set the height and width of grid items you might use a strategy that calculates both the height and width according to how many columns and rows are supposed to be fit inside the available space and then just use the lesser of the two on both the properties.
https://developer.mozilla.org/en-US/docs/Web/CSS/min
The min() CSS function lets you set the smallest (most negative) value
from a list of comma-separated expressions as the value of a CSS
property value.
In this demo I slightly refactored some choices:
I removed the default value for the number of columns to simplify the
code.. anyway it could defined as an other custom property
I use the function min to determine which one is lower between the
candidates height and width
I used place-content to center the items by default
I used grid-auto-rows to determine the size of rows because it's not
important here to tell also how many
I told the div to take the whole width and height of their container
const items = 20;
const cols = 5;
const rows = 4;
initSection(items, cols, rows);
function initSection(items, cols, rows){
const parent = document.querySelector('section');
for(i=0;i<items;i++){
const item = document.createElement('div');
item.innerText = i+1;
parent.append(item);
}
parent.dataset.col = cols;
parent.dataset.col = rows;
}
:root{
--cols: 56;
--rows: 32;
}
*{
box-sizing: border-box;
}
html, body{
margin: 0;
overflow: hidden; /*just to make sure the content doesn't overflow the viewport*/
}
section::before{
/*this to show that the same dynamic strategy here worked instead*/
--cols: attr(data-cols);
--rows: attr(data-rows);
position: absolute;
content: var(--cols) 'x' var(--rows);
border: dashed 4px gray;
padding: 0 .2em;
font-size: 1.5rem;
top: .2em;
left: .4em;
}
section {
/*!this didn't work :(*/
/*
--cols: attr(data-cols number, 56);
--row: attr(data-rows number, 32);
*/
--cols: 5;
--rows: 4;
--gap: 5px;
--col-size: calc(((100vw - (var(--cols) * var(--gap))) / (var(--cols))));
--row-size: calc(((100vh - (var(--rows) * var(--gap))) / (var(--rows))));
--size: min(var(--col-size), var(--row-size));
display: grid;
place-content: center;
gap: var(--gap);
grid-template-columns: repeat( var(--cols), var(--size));
/*grid-template-rows: repeat( var(--rows), var(--size));*/
grid-auto-rows: var(--size);
width: 100vw;
height: 100vh;
}
section{
border: solid red;
}
section div {
border: solid;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 2rem;
}
<section data-cols="5" data-rows="4">
<!--
<div>1</div>
...
-->
</section>
This question already has answers here:
Make a div span two rows in a grid
(2 answers)
Closed 1 year ago.
I have a little problem. I'm trying to program such a layout with HTML and CSS:
Here's the picture of what i want
I looked at this question:
Flexbox 3 divs, two columns, one with two rows . The only problem is that you can't give the divs a margin without them destroying the layout.
If the left image is higher, then the two right images should use the remaining space. (There are only a few boxes that I tried to place correctly first. I wanted to do the styling privately, so do not wonder.)
Here is my code what I have tried so far (Press full page. In this little window you can only see the mobile version):
* {
margin: 0;
padding: 0;
}
#showroom {
height: 500px;
width: 100%;
background: red; /* To see showroom Background */
padding: 1em;
display: flex;
}
#boxOne {
height: 100%;
width: 50%;
background: grey;
margin: 10px;
float: left;
}
#showroom #boxTwo {
width: 50%;
height: 50%;
background: grey;
margin: 10px;
}
#showroom #boxThree {
width: 50%;
height: 50%;
background: grey;
margin: 10px;
}
#media only screen and (max-width: 750px) {
#showroom {
display: flex;
align-items: center;
flex-direction: column;
}
#showroom #boxOne, #showroom #boxTwo, #showroom #boxThree {
height: 33.3%;
width: 100%;
}
}
<div id="showroom">
<div id="boxOne"></div>
<div id="boxTwo"></div>
<div id="boxThree"></div>
</div>
Update
To make the #boxOne wider, we should look at the grid parent, which we are saying is 3 columns wide, with each column representing 120px.
Now let's look at #boxOne for a second, and catch/fix an error I introduced.
#boxOne {
grid-column: 1; /* Oops—this is wrong */
grid-row: 1 / 3;
}
We declared the grid to be 3 columns, yet #boxOne is only spanning a single column. The other boxes are also spanning a single column. Here's what our grid looks like now.
You can see that we're not even using that third column. Let's adjust #boxOne to span twice as wide as the other boxes. One really important detail is to count from the first vertical line. Think of the column like this:
Now it should be clear what we need to do.
#boxOne {
grid-column: 1 / 3;
…
}
The other boxes we'll place at the span place where #boxOne left off.
#boxTwo {
grid-column: 3;
…
}
#boxThree {
grid-column: 3;
…
}
Now things are looking the way we want.
I would approach this using CSS Grid. In your example, the images would implicitly take up the necessary space, and you wouldn't need to use px values in the line declaring grid-template-columns. In your case, you could replace 120px with 1fr which is a fractional unit utilized by CSS Grid.
Another advantage of using CSS Grid is that you can avoid a lot of additional width and height settings, as well as using margins for the gaps between items.
#showroom {
display: grid;
grid-template-columns: repeat(3, 120px);
gap: 1rem;
}
#boxOne {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
#boxTwo {
grid-column: 3;
grid-row: 1 / 2;
}
#boxThree {
grid-column: 3;
grid-row: 2 / 3;
}
#showroom > * {
background-color: #444;
padding: 20px;
border-radius: 5px;
}
<div id="showroom">
<div id="boxOne"></div>
<div id="boxTwo"></div>
<div id="boxThree"></div>
</div>
In the below snippet, I can not understand how .cell1(orange) height has been computed. Why it is so high? Why it is higher than right column content? How left cells height depends on right column and it's contains height?
header {
display: grid;
grid-template-columns: 70% 30%;
grid-template-rows: 62px auto;
background: beige;
}
.cell1 {
grid-column: 1/2;
grid-row: 1/2;
background: salmon;
}
.cell2 {
grid-column: 1/2;
grid-row: 2/3;
background: MediumSpringGreen;
}
.cell3 {
grid-row: 1/3;
grid-column: 2/3;
background: PeachPuff;
}
.cell3-1 {
background: MediumPurple;
height: 5px;
}
.cell3-2 {
background: LightSkyBlue;
height: 10px;
}
.cell3-3 {
background: Navy;
height: 30px;
}
<header>
<div class="cell1">1</div>
<div class="cell2">2</div>
<div class="cell3">
<div class="cell3-1"></div>
<div class="cell3-2"></div>
<div class="cell3-3"></div>
</div>
</header>
Let's start with your title.
How css grid computes row auto height?
auto just means it adapts to the height of the content within it. If the content in an auto row, is 100px tall, the row will be 100px tall.
I can not understand how .cell1(orange) height has been computed. Why it is so high?
Because you have told the first row to be 62px tall here:
grid-template-rows: 62px auto;
Why it is higher than right column content?
It isn't...but I can see that you might think that.
How left cells height depends on right column and it's contains height?
The right content in the context of the grid is only the .cell-3 div but you have told div to span 2 rows. So it assumes the combined height of .cell- and .cell-2.
The content inside cell-3 does not inherit any of the grid properties and so flows as normal.
One of the main selling points of the CSS grid is that it eliminates container DIVs.
But I found a very common layout in which this doesn't appear to be true.
This page is supposed to have 4 areas: header, side, main and footer. But notice that side and main have a different background, so how is this possible to achieve with CSS grid without creating a container element for side and main, and turning the grid into header, side+main, footer?
You need to think of this in terms of a 4-column grid...then assign your divs to the appropriate rows & columns.
The background can be managed by a pseudo-element on the body although I prefer a page containing div. Same effect.
Codepen Demo
Nore info: Breaking Out With CSS Grid Layout
.page {
display: grid;
min-height: 100vh;
grid-template-columns: 1fr 100px 300px 1fr;
grid-template-rows: min-content 1fr min-content;
grid-gap: .5em;
}
.page::before {
content: "";
grid-column: 1 / 5;
grid-row: 2 / 3;
z-index: -2;
background: pink;
}
header {
background: red;
padding: 1em 0
}
footer {
background: blue;
padding: 1em 0;
}
aside {
background: green;
}
main {
background: rebeccapurple;
}
header,
footer {
grid-column: 2 / 4;
}
aside {
grid-column: 2 / 3;
grid-row: 2;
}
main {
grid-column: 3 / 4;
grid-row: 2;
}
<div class="page">
<header>HEADER-CONTENT</header>
<aside></aside>
<main></main>
<footer>FOOTER CONTENT</footer>
</div>
In this case I substituted different widths for demo purposes...
grid-template-columns: 1fr 100px 300px 1fr;
for say
grid-template-columns: 1fr 300px 640px 1fr;
Where the total of 300px + 640px equates to your 940px "container" width. These can be adjusted as you prefer.
I'm trying to make a grid column span every row, including implicit rows.
I came across this question asking how to span all grid rows. The second answer has a correction stating a better solution. This seems like it would work, but my own example, and the comments on the second answer, indicate that it doesn't work.
The W3 spec gives this a very close example as well.
Is there something wrong with my code, or is this possibly a bug in Firefox, Chrome, and Safari?
I also have this example in a CodePen here.
* {
box-sizing: border-box;
}
.container {
border: 1px solid #666;
max-width: 1000px;
padding: 10px;
display: grid;
grid-template-columns: 150px 1fr 300px;
/* grid-template-rows: repeat(auto) [rows-end]; Doesn't seem to help */
/* grid-template-rows: [rows-start] repeat(auto) [rows-end]; Doesn't seem to help */
grid-template-rows: repeat(auto);
grid-gap: 10px;
margin: 10px auto;
grid-auto-flow: row dense;
/* justify-items: stretch; */
/* align-items: stretch; */
}
.container>* {
grid-column: 2 / 3;
padding: 10px;
outline: 1px solid #666;
}
.pop {
grid-column: 1 / 2;
/* grid-column: 1 / -1; If I switch to this, this div will span the full width of the grid, which is exactly what I'm trying to do with rows*/
}
.tertiary {
grid-column: 1 / 2;
}
.secondary {
grid-column: 3 / 3;
grid-row: 1 / -1;
/* Doesn't work */
/* grid-row: rows-start / rows-end; Doesn't work */
/* grid-row: 1 / rows-end; Also doesn't work */
/* grid-row: 1 / span 7; This works, but I need to span an unknown number of rows*/
/* grid-row: 1 / span 99; This is gross and creates 99 rows */
}
<div class="container">
<div class="secondary">Secondary - why doesn't this span all the way to the bottom of the grid?</div>
<div class="tertiary">Tertiary</div>
<div class="tertiary">Tertiary</div>
<div class="tertiary">Tertiary</div>
<div>Primary</div>
<div>Primary</div>
<div>Primary</div>
<div class="pop">Span tertiary and primary</div>
<div>Primary</div>
<div class="tertiary">Tertiary</div>
<div>Primary</div>
<div>Primary</div>
</div>
There are two obstacles in your way.
First, this line of CSS code in your .container rule:
grid-template-rows: repeat(auto);
This code is invalid. The argument in the repeat() notation must begin with a positive integer, which specifies the number of repetitions. You don't have that, so the code doesn't work. More details in the spec.
Second, even if the code above was correct, let's say:
grid-auto-rows: auto; (which happens to be the default setting anyway)
Your column would still not span all rows.
This is because, as you may have seen in the other answer you cited, a track definition can be set to cover all perpendicular tracks only in the explicit grid.
So this would work:
grid-template-rows: repeat(6, auto);
revised demo
The rest of the problem is covered in detail in the other answer you cited.