Prevent grid items from expanding when content is added - html

I'm trying to create a layout where the screen is divided into some number of equally-sized cells. When I fill one of the cells with content, it stretches to be larger than the other cells, even though the content is much smaller than the cell itself.
Why is the cell stretching despite it being plenty big to hold its content? How can I prevent it from resizing?
html, body {
margin: 0px;
padding: 0px;
width: 100%;
height: 100%;
background-color: #880022;
}
#content {
display: grid;
width: 100%;
height: 100%;
grid-template-rows: 20px auto 20px;
grid-template-columns: 20px auto 20px;
}
#content2 {
display: grid;
grid-template-rows: auto;
grid-template-columns: auto;
height: 100%;
background-color: #ff00ff;
}
#grid {
grid-row-start: 2;
grid-column-start: 2;
display: grid;
grid-template-rows: auto auto;
grid-template-columns: auto auto;
grid-gap: 2px 2px;
}
.tile {
background-color: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.tile span {
font-size: 2em;
}
.tile:hover {
background-color: rgba(255, 255, 255, 0.3);
}
<div id="content">
<div id="grid">
<div class="tile"><span>test</span></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
</div>
</div>

You're setting the column and row sizes to auto. This means they will be sized based on their content. Instead, use fr units, which use the free space in the container.
#content {
display: grid;
grid-template-rows: 20px auto 20px;
grid-template-columns: 20px auto 20px;
height: 100vh;
background-color: #880022;
}
#grid {
grid-row-start: 2;
grid-column-start: 2;
display: grid;
grid-template-rows: 1fr 1fr; /* adjustment */
grid-template-columns: 1fr 1fr; /* adjustment */
grid-gap: 2px;
}
.tile {
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.2);
}
.tile:hover {
background-color: rgba(255, 255, 255, 0.3);
}
.tile span {
font-size: 2em;
}
body {
margin: 0;
}
<div id="content">
<div id="grid">
<div class="tile"><span>test</span></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
</div>
</div>
jsFiddle demo

You have a lot of extra markup, here is a simplified version, the trick is using fr unit instead of auto and you can use repeat()
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background-color: #802;
}
#grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, minmax(80px, 1fr));
grid-gap: 2px;
padding: 20px;
box-sizing: border-box;
height: 100vh
}
.tile {
background-color: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.tile span {
font-size: 2em;
}
.tile:hover {
background-color: rgba(255, 255, 255, 0.3);
}
<div id="grid">
<div class="tile"><span>test</span></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
</div>

One solution would be to give line-height: 0 to your .tile elements. This will ensure that the text doesn't take up any space, though will limit you to only having one line of text per square:
html,
body {
margin: 0px;
padding: 0px;
width: 100%;
height: 100%;
background-color: #880022;
}
#content {
display: grid;
width: 100%;
height: 100%;
grid-template-rows: 20px auto 20px;
grid-template-columns: 20px auto 20px;
}
#content2 {
display: grid;
grid-template-rows: auto;
grid-template-columns: auto;
height: 100%;
background-color: #ff00ff;
}
#grid {
grid-row-start: 2;
grid-column-start: 2;
display: grid;
grid-template-rows: auto auto;
grid-template-columns: auto auto;
grid-gap: 2px 2px;
}
.tile {
background-color: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
line-height: 0;
}
.tile span {
font-size: 2em;
}
.tile:hover {
background-color: rgba(255, 255, 255, 0.3);
}
<!DOCTYPE html>
<html>
<body>
<div id="content">
<div id="grid">
<div class="tile"><span>test</span></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
</div>
</div>
</body>
</html>
However, in my opinion, the better solution would be to set grid-auto-rows: 1fr on #grid, which instructs each of the rows to take up as much height as the tallest row:
html,
body {
margin: 0px;
padding: 0px;
width: 100%;
height: 100%;
background-color: #880022;
}
#content {
display: grid;
width: 100%;
height: 100%;
grid-template-rows: 20px auto 20px;
grid-template-columns: 20px auto 20px;
}
#content2 {
display: grid;
grid-template-rows: auto;
grid-template-columns: auto;
height: 100%;
background-color: #ff00ff;
}
#grid {
grid-row-start: 2;
grid-column-start: 2;
display: grid;
grid-template-rows: auto auto;
grid-template-columns: auto auto;
grid-gap: 2px 2px;
grid-auto-rows: 1fr;
}
.tile {
background-color: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
line-height: 0;
}
.tile span {
font-size: 2em;
}
.tile:hover {
background-color: rgba(255, 255, 255, 0.3);
}
<!DOCTYPE html>
<html>
<body>
<div id="content">
<div id="grid">
<div class="tile"><span>test</span></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
</div>
</div>
</body>
</html>

Try
max-width:something px;
max-height:something px;
inside #grid.

Related

How to center the elements of specific CSS grid's row without horizontal gap and additional wrappers?

Below image has been created by the graphics editor. The target is get the same view by CSS grid.
Currently, the middle row fills the viewport's width:
html, body {
height: 100%;
}
.TwoColumnsLayout {
display: grid;
grid-template-areas:
"UPPER_FIXED_CONTENT UPPER_FIXED_CONTENT"
"SIDEBAR SPECIFIC_CONTENT"
"BOTTOM_FIXED_CONTENT BOTTOM_FIXED_CONTENT";
grid-template-columns: 100px 1fr;
grid-template-rows: auto 1fr auto;
height: 100%;
}
.TwoColumnsLayout-UpperFixedContent {
height: 30px;
grid-area: UPPER_FIXED_CONTENT;
background-color: lightpink;
}
.TwoColumnsLayout-Sidebar {
overflow-y: auto;
grid-area: SIDEBAR;
background-color: gold;
width: 100px;
}
.TwoColumnsLayout-SpecificContent {
overflow-y: auto;
grid-area: SPECIFIC_CONTENT;
background-color: aquamarine;
}
.TwoColumnsLayout-BottomFixedContent {
height: 30px;
grid-area: BOTTOM_FIXED_CONTENT;
background: deepskyblue;
}
<div class="TwoColumnsLayout">
<div class="TwoColumnsLayout-UpperFixedContent"></div>
<div class="TwoColumnsLayout-Sidebar"></div>
<main class="TwoColumnsLayout-SpecificContent"></main>
<div class="TwoColumnsLayout-BottomFixedContent"></div>
</div>
In this case, justify-content: center; will change nothing.
If to apply justify-items: center; to grid container and also justify-self: stretch; to first and last element, we'll get:
html, body {
height: 100%;
}
.TwoColumnsLayout {
display: grid;
grid-template-areas:
"UPPER_FIXED_CONTENT UPPER_FIXED_CONTENT"
"SIDEBAR SPECIFIC_CONTENT"
"BOTTOM_FIXED_CONTENT BOTTOM_FIXED_CONTENT";
grid-template-columns: 100px 1fr;
grid-template-rows: auto 1fr auto;
justify-items: center;
height: 100%;
}
.TwoColumnsLayout-UpperFixedContent {
height: 30px;
grid-area: UPPER_FIXED_CONTENT;
background-color: lightpink;
justify-self: stretch;
}
.TwoColumnsLayout-Sidebar {
overflow-y: auto;
grid-area: SIDEBAR;
background-color: gold;
width: 100px;
}
.TwoColumnsLayout-SpecificContent {
overflow-y: auto;
grid-area: SPECIFIC_CONTENT;
background-color: aquamarine;
}
.TwoColumnsLayout-BottomFixedContent {
height: 30px;
grid-area: BOTTOM_FIXED_CONTENT;
background: deepskyblue;
justify-self: stretch;
}
<div class="TwoColumnsLayout">
<div class="TwoColumnsLayout-UpperFixedContent"></div>
<div class="TwoColumnsLayout-Sidebar"></div>
<main class="TwoColumnsLayout-SpecificContent"></main>
<div class="TwoColumnsLayout-BottomFixedContent"></div>
</div>
I expected it will be simple with CSS grid...
It there the solutions without adding of extra HTML elements?
You can do it like below. The 600px will simulate the max-width which is the area for the sidebar and content
body {
margin:0;
}
.TwoColumnsLayout {
--max: 600px; /* your max-width */
min-height: 100vh;
display: grid;
grid-template-columns:
calc((100% - var(--max))/2) 100px 1fr calc((100% - var(--max))/2);
grid-template-rows: auto 1fr auto;
}
.TwoColumnsLayout-UpperFixedContent,
.TwoColumnsLayout-BottomFixedContent{
height: 30px;
grid-column:1/-1;
background-color: lightpink;
}
.TwoColumnsLayout-Sidebar {
overflow-y: auto;
grid-column: 2;
background-color: gold;
}
.TwoColumnsLayout-SpecificContent {
overflow-y: auto;
background-color: aquamarine;
}
.TwoColumnsLayout-BottomFixedContent {
background: deepskyblue;
}
<div class="TwoColumnsLayout">
<div class="TwoColumnsLayout-UpperFixedContent"></div>
<div class="TwoColumnsLayout-Sidebar"></div>
<main class="TwoColumnsLayout-SpecificContent"></main>
<div class="TwoColumnsLayout-BottomFixedContent"></div>
</div>

make grid child scrollable when it's content is overflown

I'm trying to make the div with the class side-panel-content scrollable when it's content is big, overflow-y: scroll; doesn't work in this case.
The idea here, is to make the full page take the viewport, which works when the .long-content div has no height, but if it has a long height this shouldn't make it's container to grow more, and should be scrollable instead.
Here is a full example:
html, body {
height: 100%;
}
.main {
height: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
header, footer {
height: 80px;
background-color: yellow;
}
.content-wrapper {
height: 100%;
width: 100%;
display: grid;
grid-template-rows: auto 1fr;
}
.title {
padding: 24px;
width: 100%;
}
.main-content {
width: 100%;
display: grid;
gap: 24px;
grid-template-columns: 1fr 350px;
justify-content: space-around;
}
.main-panel {
display: grid;
grid-template-rows: auto 1fr;
border: 2px solid red;
}
.side-panel {
height: 100%;
width: 100%;
}
.side-panel-wrapper {
height: 100%;
background: #f8f9fa;
box-shadow: 0px 4px 10px rgb(0 0 0 / 10%);
display: grid;
grid-template-rows: auto 1fr;
}
.side-panel-header {
background-color: #ffffff;
padding: 24px;
border-bottom: 2px solid #e6e9f0;
}
.side-panel-content {
overflow-y: scroll;
}
.long-content {
height: 3000px;
}
<html>
<body>
<div class="main">
<header><h1>Header</h1></header>
<div class="content">
<div class="content-wrapper">
<div class="title">
<h1>Title</h1>
</div>
<div class="main-content">
<div class="main-panel">
<div>
<h2>
Main panel title
</h2>
<p>
Main panel content
</p>
</div>
</div>
<div class="side-panel">
<div class="side-panel-wrapper">
<div class="side-panel-header">
Side panel header
</div>
<div class="side-panel-content">
<div class="long-content">
long content
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer><h1>Footer</h1></footer>
</div>
</body>
</html>
The solution for this is to use an absolute positioning for the child div that has a long height.
html, body {
height: 100%;
}
.main {
height: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
header, footer {
height: 80px;
background-color: yellow;
}
.content-wrapper {
height: 100%;
width: 100%;
display: grid;
grid-template-rows: auto 1fr;
}
.title {
padding: 24px;
width: 100%;
}
.main-content {
width: 100%;
display: grid;
gap: 24px;
grid-template-columns: 1fr 350px;
justify-content: space-around;
}
.main-panel {
display: grid;
grid-template-rows: auto 1fr;
border: 2px solid red;
}
.side-panel {
height: 100%;
width: 100%;
}
.side-panel-wrapper {
height: 100%;
background: #f8f9fa;
box-shadow: 0px 4px 10px rgb(0 0 0 / 10%);
display: grid;
grid-template-rows: auto 1fr;
}
.side-panel-header {
background-color: #ffffff;
padding: 24px;
border-bottom: 2px solid #e6e9f0;
}
.side-panel-content {
overflow: auto;
position: relative;
height: 100%;
}
.long-content {
position: absolute;
top: 0;
height: 3000px;
}
<html>
<body>
<div class="main">
<header><h1>Header</h1></header>
<div class="content">
<div class="content-wrapper">
<div class="title">
<h1>Title</h1>
</div>
<div class="main-content">
<div class="main-panel">
<div>
<h2>
Main panel title
</h2>
<p>
Main panel content
</p>
</div>
</div>
<div class="side-panel">
<div class="side-panel-wrapper">
<div class="side-panel-header">
Side panel header
</div>
<div class="side-panel-content">
<div class="long-content">
long content
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer><h1>Footer</h1></footer>
</div>
</body>
</html>

Align a div container at the bottom of an image

I can't align a div container at the bottom of an image.
What I've tried is editing the attribute position of the image and set it's value to "relative".
Explaining this is a little bit difficult, but I got html and css code snippets with a little preview:
codepen.io/Proudyy/pen/PoOjYpK
(it's not 84 lines long, so not too much in my opinion)
This is how it should look like:
https://imgur.com/a/LShx2cM
set position: absolute for .skin-item-footer and position: relative on it's parent div. Check below code
.skin-item-splashart {
width: 100%;
border-radius: 12px;
position: relative;
}
.skin-item-footer-left-container {
grid-column: 1;
display: grid;
grid-template-rows: repeat(2, auto);
align-self: start;
height: 100%;
}
.skin-item-footer-right-container {
grid-column: 2;
display: grid;
align-items: center;
justify-content: end;
align-self: end;
height: 100%;
}
.skin-item-default-name {
font-size: 24px;
font-weight: bold;
margin-left: 3vh;
}
.skin-item-name {
font-size: 18px;
color: gainsboro;
margin: 0;
margin-left: 3vh;
grid-row: 1;
}
.skin-item-cost {
display: grid;
grid-row: 2;
grid-template-columns: repeat(2, auto);
grid-template-rows: 1fr;
}
.skin-item-cost-value {
color: gainsboro;
grid-column: 1;
margin: 0;
}
.skin-item-cost-icon {
grid-column: 2;
margin: 0;
}
.skin-item-save-icon {
cursor: pointer;
margin-right: 2vh;
}
.skin-item {
background-color: rgb(0, 40, 75);
margin: 15px;
border-radius: 12px;
height: auto;
width: 50%;
position: relative;
}
img{
max-width: 100%;
}
.skin-item-footer {
background-color: rgba(0, 0, 0, 0.4);
border-radius: 0 0 12px 12px;
position: absolute;
bottom: 0;
height: auto;
width: 100%;
}
<div class="skin-item">
<img class="skin-item-splashart" src="https://cdn.communitydragon.org/latest/champion/1/splash-art/skin/1"/>
<div class="skin-item-footer">
<div class="skin-item-footer-left-container">
<p class="skin-item-name">SkinName</p>
<div class="skin-item-cost">
<img class="skin-item-cost-icon" src="https://raw.communitydragon.org/latest/plugins/rcp-fe-lol-static-assets/global/default/images/icon-rp-24.png"/>
<p class="skin-item-cost-value">Spaceholder</p>
</div>
</div>
<div class="skin-item-footer-right-container">
<img class="skin-item-save-icon" src="https://img.icons8.com/color/32/000000/save--v1.png"/>
</div>
</div>
</div>

Shrink grid container to number of rows

I have a flexbox with a grid and a div in it, and I'd like to collapse the grid container's height to the height of the rows, so that the buttons below it are just below the grid items. The number of rows is also dynamic, because I'm using grid-template-columns: repeat(auto-fit, minmax(250px, 1fr). I can set a max-height of the grid items, like in this image, but that only makes the items smaller and doesn't make the grid container any shorter.
I've tried changing the flexbox they're in so the flex-direction is row, and set flex-wrap to wrap, but that causes other problems and overlapping text when the window size changes. Setting the height or max-height of the grid container to fit-content seems to do nothing as well.
Here is what I have:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Boardgame Database</title>
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
aside {
background-color: red;
flex: 1;
min-width: 250px;
}
.grid-container {
flex: 4;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.grid-item {
border: 1px solid rgba(0, 0, 0, 0.8);
padding: 20px;
font-size: 24px;
text-align: center;
overflow: hidden;
min-height: 100px;
}
#main-container {
display: flex;
flex-direction: row;
min-height: 100vh;
}
#section-container {
display: flex;
flex-direction: column;
width: 100%;
}
#page-buttons {
height: 50px;
text-align: center;
font-size: 20px;
}
</style>
</head>
<body>
<div id="main-container">
<aside class="sidebar">
</aside>
<div id="section-container">
<section class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
</section>
<div id="page-buttons">
first
prev
page
next
last
</div>
</div>
</div>
</body>
</html>
The style
.grid-container {
flex: 4;
}
is equivalent to flex-grow: 4;
so it makes the container grow. Just remove it and it will keep its dimension
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
aside {
background-color: red;
flex: 1;
min-width: 250px;
}
.grid-container {
/* flex: 4; */
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.grid-item {
border: 1px solid rgba(0, 0, 0, 0.8);
padding: 20px;
font-size: 24px;
text-align: center;
overflow: hidden;
min-height: 100px;
}
#main-container {
display: flex;
flex-direction: row;
min-height: 100vh;
}
#section-container {
display: flex;
flex-direction: column;
width: 100%;
}
#page-buttons {
height: 50px;
text-align: center;
font-size: 20px;
}
<body>
<div id="main-container">
<aside class="sidebar">
</aside>
<div id="section-container">
<section class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
</section>
<div id="page-buttons">
first
prev
page
next
last
</div>
</div>
</div>
</body>

css - nested div in grid does not respect grid sizes

So I'm trying to display cards within a grid. I would like the card size to be based on the grid size and then to overlay text on top of it that correctly matches the width.
Here's my implementation so far but it seems like the div/img no longer respects the grid's sizes
for (let i = 0; i < 15; i++)
{
$("#grid").append(`
<div class="item">
<div>
<img src="http://via.placeholder.com/250x350" />
<div class="text">
sadfsd
</div>
</div>
</div>
`);
}
.flex {
border: 1px solid black;
display: flex;
flex-direction: column;
height: 100vh;
}
.footer {
height: 20%;
}
.upper {
flex: 1;
overflow: auto;
}
#grid {
border: 1px solid black;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
height: 100%;
position: relative;
max-width: 100%;
box-sizing: border-box;
}
.item {
display: inline-block;
text-align: center;
position: relative;
}
.inner {
border: 1px solid red;
max-height: 100%;
max-width: 100%;
}
.text {
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
height: 30%;
border: 1px solid black;
width: 90%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex">
<div class='upper'>
<div id="grid">
</div>
</div>
<div class="footer">
footer
</div>
</div>
What I want is it to look something like this (of course with the text matching the width of the image)
for (let i = 0; i < 15; i++)
{
$("#grid").append(`
<div class="item">
<img src="http://via.placeholder.com/150x350" />
<div class="text">
text
</div>
</div>
`);
}
.flex {
border: 1px solid black;
display: flex;
flex-direction: column;
height: 100vh;
}
.footer {
height: 20%;
}
.upper {
flex: 1;
overflow: auto;
}
#grid {
border: 1px solid black;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
height: 100%;
position: relative;
max-width: 100%;
box-sizing: border-box; /* added */
}
.item {
position: relative;
}
.text {
border: 1px solid black;
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
width: 90%;
height: 30%;
}
img {
display: block;
margin: 0 auto;
max-height: 100%;
max-width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div class="flex">
<div class='upper'>
<div id="grid">
</div>
</div>
<div class="footer">
footer
</div>
</div>