I am trying to create a CSS grid with unequal rows and I cannot make .feature-block-header take ONLY as much space as it actually needs. I don't want it to be equal height with .feature-block-text. Is there a way of having a flex-grow sort of way on .feature-block-text so that it takes whatever space header did not use?
I think I have tried almost every grid row property...
.feature-block {
display: grid;
grid-template-columns: 320px auto;
grid-column-gap: 10px;
grid-template-areas:
"feature-block-image feature-block-header"
"feature-block-image feature-block-text";
}
.feature-block-header {
grid-area: feature-block-header;
background: yellow;
margin-top: 0;
}
.feature-block-image {
grid-area: feature-block-image;
width: 320px;
height: 320px;
background: lightblue;
}
.feature-block-text {
grid-area: feature-block-text;
background: lightgreen;
}
<div class="feature-block">
<h2 class="feature-block-header">Header</h2>
<div class="feature-block-image"></div>
<div class="feature-block-text">
<p>Some text within text block</p>
</div>
</div>
By adjusting the grid-template-rowsproperty, you can adjust the row heights. I just added this property to your code to demonstrate the result.
EDIT: I changed 50px to auto to make it flexible to adjust row content height.
grid-template-rows: auto 1fr;
.feature-block {
display: grid;
grid-template-columns: 320px auto;
grid-column-gap: 10px;
grid-template-areas:
"feature-block-image feature-block-header"
"feature-block-image feature-block-text";
grid-template-rows: auto 1fr;
}
.feature-block-header {
grid-area: feature-block-header;
background: yellow;
margin-top: 0;
}
.feature-block-image {
grid-area: feature-block-image;
width: 320px;
height: 320px;
background: lightblue;
}
.feature-block-text {
grid-area: feature-block-text;
background: lightgreen;
}
<div class="feature-block">
<h2 class="feature-block-header">Header</h2>
<div class="feature-block-image"></div>
<div class="feature-block-text">
<p>Some text within text block</p>
</div>
</div>
You can set align-self: start; to .feature-block-header.
https://developer.mozilla.org/en-US/docs/Web/CSS/align-self
Related
Considering this HMTL:
/* Desired styiling: */
.container {
display: grid;
grid-template-columns: 250px 250px 250px /* this is the part to automate */
grid-template-rows: 50px;
}
.child {
width: 100%;
height: 100%;
background: red;
}
<div class="container">
<div class="child">x</div>
<div class="child">y</div>
<div class="child">z</div>
</div>
And the fact that the number of .child element can change.
How can I make .container have display grid and a column of size 250px for every .child el?
I know this can be done in JS but I was looking for a css solution.
Update your code like below:
.container {
display: grid;
grid-auto-columns: 250px; /* size of each column */
grid-auto-flow: column; /* column flow */
grid-template-rows: 50px;
}
.child {
background: red;
}
<div class="container">
<div class="child">x</div>
<div class="child">y</div>
<div class="child">z</div>
</div>
I have the following grid layout:
<div class="main-page">
<div class="side-bar"></div>
<div class="nav-bar"></div>
<div class="index-view"></div>
</div>
and I am trying to insert a new div between sidebar and index such that the resulting layout will be like:
<div class="main-page">
<div class="side-bar"></div>
<div class="nav-bar"></div>
<div class="profile-pane"></div>
<div class="index-view"></div>
</div>
My attempt so far has been:
.main-page {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: 72px 1fr;
height: 100%;
}
.main-page > .side-bar {
display: grid;
grid-row: 1/4;
width: 80px;
}
.main-page > .profile-pane {
width: 260px;
position: relative;
grid-row: 2/4;
}
.main-page > .index-view {
grid-row: 2/4;
}
This renders a huge space between profile and index and compresses index to the right. I've been trying different values for the grid-row property but to no avail. However, if I remove either one of profile and index, the remaining div will render nicely and right beside the sidebar. How do I achieve the second layout?
You can consider different values based on the existance of the profile element:
.main-page {
display: grid;
grid-template-columns: 80px 1fr 4fr;
grid-template-rows: 72px 1fr;
height: 200px;
margin:20px;
}
.side-bar {
grid-row: span 2;
}
.nav-bar,
.index-view {
grid-column:span 2;
}
/* Take only one clumn if profile exist*/
.profile-pane + .index-view {
grid-column:span 1;
}
/* Irrelevant code */
.main-page > * {
border:1px solid;
}
.main-page > *:before {
content:attr(class);
}
<div class="main-page">
<div class="side-bar"></div>
<div class="nav-bar"></div>
<!--<div class="profile-pane"></div>-->
<div class="index-view"></div>
</div>
<div class="main-page">
<div class="side-bar"></div>
<div class="nav-bar"></div>
<div class="profile-pane"></div>
<div class="index-view"></div>
</div>
You can achieve the desired result by setting the "grid-row: span 2" property in the sidebar to increase its height by two lines. And for the navigation bar, the "grid-column: span 2" property is to expand it into two columns
Oh yes, and do not forget to set the columns of the required width for the grid container grid-template-columns: 10% 15% 70%;
Result:
.main-page {
display: grid;
grid-template-columns: 10% 15% 70%;
}
.main-page>* {
padding: 20px;
border: 1px solid #000;
}
.side-bar {
grid-row: span 2;
}
.nav-bar {
grid-column: span 2;
}
.index-view {
min-height: 500px;
}
<div class="main-page">
<div class="side-bar">side-bar</div>
<div class="nav-bar">nav-bar</div>
<div class="profile-pane">profile-pane</div>
<div class="index-view">index-view</div>
</div>
I'm trying to display two columns with the CSS Grid stretched to the bottom of the screen. I used flexbox to achieve it:
html, body {
height: 100%;
}
#root {
display: flex;
flex-direction: column;
min-height: 100%;
color: #fff;
}
#wrapper {
flex: 1;
display: grid;
grid:
"title title" min-content
"divider divider" min-content
"part1 part2" 1fr
/ calc(50% - 5px) calc(50% - 5px);
background-color: #003300;
grid-gap: 10px;
}
#title {
grid-area: title;
}
#divider {
grid-area: divider;
}
#part1 {
grid-area: part1;
}
#part2 {
grid-area: part2;
}
#part1, #part2 {
background-color: #ff0000;
}
<section id="root">
<section id="wrapper">
<div id="title">Title</div>
<div id="divider"><hr></div>
<div id="part1">Part 1</div>
<div id="part2">Part 2</div>
</section>
</section>
If you run this code in Firefox, you can see properly stretching red columns that reach the bottom of the screen. But in the Chrome they do not stretch properly and leave as small as possible. Is there some way to avoid this issue? I would like to save the flexbox-direction: column.
Maybe there is also a link to the chromium bug?
Looks like a bug in Chrome.
Flex and Grid properties don't play nice in this particular scenario.
I know you said you would like to keep flex-direction: column.
But you can get the same behavior with flex-direction: row when you add wrap to the container and make each item width: 100%.
And in this case, that switch in flex-direction solves your problem.
#root {
display: flex;
min-height: 100vh;
color: #fff;
}
#wrapper {
flex: 1;
display: grid;
grid:
"title title" min-content
"divider divider" min-content
"part1 part2" 1fr
/ 1fr 1fr ; /* calc(50% - 5px) calc(50% - 5px) why the added complexity? */
background-color: #003300;
grid-gap: 10px;
}
#title { grid-area: title; }
#divider { grid-area: divider; }
#part1 { grid-area: part1; }
#part2 { grid-area: part2; }
#part1,
#part2 { background-color: #ff0000; }
body { margin: 0; }
<section id="root">
<section id="wrapper">
<div id="title">Title</div>
<div id="divider"><hr></div>
<div id="part1">Part 1</div>
<div id="part2">Part 2</div>
</section>
</section>
jsFiddle demo
More information: Force flex item to span full row width
If you really can't switch from flex-direction: column, here are two options you can try:
move the min-height from #root to #wrapper (jsfiddle demo)
make the overall parent (body, in this case) a flex container (jsfiddle demo)
I have made a blog design using CSS grid, having used inline-block to pack DIVs together.
In my blog I have 2 picture-DIVS of height 60 that I want to show next to a text-DIV of height 120. Only the first picture is shown next to the text.
Why is the second picture shown below the text, and please get some pointers on how I can fix this.
.GridCont {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: auto auto auto;
grid-template-areas: "content content content content" "content content content content" "content content content content";
}
.PostContent {
grid-area: content;
background: #B8E986;
}
.Content {
background: #000000;
width: 35%;
color: white;
display: inline-block;
}
.box1 {
height: 120vh;
}
.PicContent {
background: blue;
color: white;
display: inline-block;
}
.pic1 {
height: 60vh;
width: 50%;
}
.pic2 {
height: 60vh;
width: 45%;
}
.cTextP {
padding: 20px;
}
<div class="GridCont">
<div class="PostContent">
<div class="PicContent pic1">
<div class="cTextP">Picture #1</div>
</div>
<div class="Content box1">
<div class="cTextP">Content #1</div>
</div>
<div class="PicContent pic2">
<div class="cTextP">Picture #2</div>
</div>
</div>
</div>
Code is at this JS-fiddle
Why would the second image show right beneath the first? There is no reason for that.
The second image is on the second row.
The second row goes right beneath the first row.
More specifically, the first row is occupied by two elements: image #1 and the content box. The height of the first row is defined by the tallest element. In this case, that would the content box.
So, because image #1 doesn't extend the full height of row #1, there will be a gap between images.
Here's an even more detailed explanation of the problem:
Is it possible for flex items to align tightly to the items above them?
(It's a flexbox-related post, but the logic applies here, as well.)
Instead of inline-block, use Grid properties to get the content box to span both rows:
.PostContent {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 60vh 60vh;
grid-gap: 1em;
grid-template-areas: " pic1 box1 "
" pic2 box1 ";
}
.box1 {
grid-area: box1;
}
.pic1 {
grid-area: pic1;
}
.pic2 {
grid-area: pic2;
}
.PostContent { background: #B8E986; }
.PicContent { background: blue; color: white; }
.Content { background: #000000; color: white; }
.cTextP { padding: 20px;}
<div class="GridCont">
<div class="PostContent">
<div class="PicContent pic1">
<div class="cTextP">Picture #1</div>
</div>
<div class="Content box1">
<div class="cTextP">Content #1</div>
</div>
<div class="PicContent pic2">
<div class="cTextP">Picture #2</div>
</div>
</div>
</div>
revised jsfiddle
Also note that grid properties work only between parent and child elements.
This will fix your problem:
<div class="grid-container">
<div class="image1"></div>
<div class="image2"></div>
<div class="text"></div>
</div>
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-template-areas: "image1 image1 text text" "image2 image2 text text";
}
.image1 { grid-area: image1; }
.image2 { grid-area: image2; }
.text { grid-area: text; }
You can see the working example over here:
https://codepen.io/dennisperremans/pen/NeqNJp
I have a card built with CSS Grid layout. There might be an image to the left, some text to the right top and maybe a button or a link at the right bottom.
In the code below, how can I make the green area take up as much space as possible and at the same time make the blue area take up as little space as possible?
The green should push the blue area down as far as possible.
https://jsfiddle.net/9nxpvs5m/
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas:
"one two"
"one three"
}
.one {
background: red;
grid-area: one;
padding: 50px 0;
}
.two {
background: green;
grid-area: two;
}
.three {
background: blue;
grid-area: three;
}
<div class="grid">
<div class="one">
One
</div>
<div class="two">
Two
</div>
<div class="three">
Three
</div>
</div>
Adding grid-template-rows: 1fr min-content; to your .grid will get you exactly what you're after :).
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-rows: 1fr min-content;
grid-template-areas:
"one two"
"one three"
}
.one {
background: red;
grid-area: one;
padding: 50px 0;
}
.two {
background: green;
grid-area: two;
}
.three {
background: blue;
grid-area: three;
}
<div class="grid">
<div class="one">
One
</div>
<div class="two">
Two
</div>
<div class="three">
Three
</div>
</div>
Jens edits: For better browser support this can be used instead: grid-template-rows: 1fr auto;, at least in this exact case.
A grid is a series of intersecting rows and columns.
You want the two items in the second column to automatically adjust their row height based on their content height.
That's not how a grid works. Such changes to the row height in the second column would also affect the first column.
If you must use CSS Grid, then what I would do is give the container, let's say, 12 rows, then have items span rows as necessary.
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-rows: repeat(12, 15px);
}
.one {
grid-row: 1 / -1;
background: red;
}
.two {
grid-row: span 10;
background: lightgreen;
}
.three {
grid-row: span 2;
background: aqua;
}
.grid > div {
display: flex;
align-items: center;
justify-content: center;
}
<div class="grid">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
Otherwise, you can try a flexbox solution.
.grid {
display: flex;
flex-flow: column wrap;
height: 200px;
}
.one {
flex: 0 0 100%;
width: 30%;
background: red;
}
.two {
flex: 1 0 1px;
width: 70%;
background: lightgreen;
}
.three {
background: aqua;
}
.grid>div {
display: flex;
align-items: center;
justify-content: center;
}
<div class="grid">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
When using grid, and you have grid template area used, and by chance you gave a particular area a width, you are left with a space grid does automatically.
In this situation, let grid-template-columns be either min-content or max-content, so that it adjusts its position automatically.
A possible approach might be grouping two and three together, and using flexbox:
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas: "one two"
}
.one {
background: red;
grid-area: one;
padding: 50px 0;
}
.wrap {
grid-area: two;
display: flex;
flex-direction: column;
}
.two {
background: green;
flex: 1;
}
.three {
background: blue;
}
<div class="grid">
<div class="one">
One
</div>
<div class="wrap">
<div class="two">
Two
</div>
<div class="three">
Three
</div>
</div>
</div>
Definitely not the most elegant solution and probably not best practice, but you could always add more lines of
"one two"
before the part where you have
"one three"
so it ends up looking like
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas:
"one two"
"one two"
"one two"
"one three"
}
Again, pretty sure this is just a work around and there's better solutions out there... But this does work, to be fair.
Just use width: 100% and height: 100% in the CSS class of the item you want to fill the grid. Join a max-width property and a max-height property if you don't want a grid item inside a grid container to grow more than some size.