Issue
I am coding a React app in which I have to display a grid to my user. The grid definition is an object that I receive from backend. I want the page to take the whole available space, there is a header and a footer and the grid should take the remaining space in between.
In my case, it needs to be a 50 columns by 50 rows grid.
I need to display some boxes inside the grid that are defined by their position (x and y) on the grid and the number of rows and columns that it needs to take in the grid.
I managed to do that just fine, but the boxes also need to display some images inside each box. I don't really know why, but as soon as I add the image inside the boxes they get bigger and the grid resize and overflows its parent. I don't want that, I want the images to be contained by the box with its initial size.
It is my first time using the display: grid
CSS property, so I probably don't fully understand how it is supposed to work.
Does someone have an idea of why it does that, and how can I change it so it does what I want ?
Here is a a minimal reproducible example where I reproduced my issue, you just have to uncomment the <img/>
to see the overflow :
const elements = [{
x: 36,
y: 2,
rows: 7,
cols: 7,
},
{
x: 43,
y: 14,
rows: 7,
cols: 7,
},
{
x: 36,
y: 26,
rows: 7,
cols: 7,
},
];
const App = () => {
return (
<div className="App">
<div className="header">
<h2>Header</h2>
</div>
<div className="grid">
{elements.map((elt) => (
<div
className="grid-elt"
style={{
gridColumn: `${elt.x} / ${elt.x + elt.cols}`,
gridRow: `${elt.y} / ${elt.y + elt.rows}`,
}}
>
{/* uncomment the img to see the overflow */}
{/* <img
className="img"
src="https://cdn-icons-png.flaticon.com/512/13371/13371271.png"
/> */}
</div>
))}
</div>
<div className="footer">
<h3>Footer</h3>
</div>
</div>
);
};
// Render it
ReactDOM.render(
<App/>,
document.getElementById("root")
);
html {
display: flex;
width: 100%;
height: 100%;
flex: 1;
}
body {
display: flex;
flex: 1;
height: 100%;
margin: 0;
}
#root {
display: contents;
}
.App {
font-family: sans-serif;
text-align: center;
background-color: cadetblue;
display: flex;
flex: 1;
flex-direction: column;
width: 100%;
height: 100%;
margin: 0;
}
.header {
height: 100px;
background-color: bisque;
}
.footer {
background-color: blueviolet;
height: 50px;
}
.grid {
display: grid;
grid-template-columns: repeat(50, 1fr);
grid-template-rows: repeat(50, 1fr);
height: 100%;
width: 100%;
}
.grid-elt {
border: 1px solid red;
}
.grid-elt1 {
grid-com
}
.img {
width: 100%;
height: 100%;
object-fit: contain;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I looked at the display: grid
documentation but couldn't find anything that explains my problem. I believe that it could be because i define my grid cells and row with repeat(50, 1fr)
but I'm not realy sure.
Solution
A way to ensure that the size of the containers won't be affected by their content is using position: absolute
on your pictures so that they won't alter the document flow.
This is the essential thing I changed in your code:
.grid-elt {
border: 1px solid red;
position: relative;
}
.img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
As you can see, I take for granted that the container size must be ruling ignoring the size of the actual picture. The side effect is having a wrong aspect ratio most of the time.
This is the full demo including a button in the header that will show/hide the picture to give evidence that the box sizes won't be affected:
const elements = [{
x: 36,
y: 2,
rows: 7,
cols: 7,
},
{
x: 43,
y: 14,
rows: 7,
cols: 7,
},
{
x: 36,
y: 26,
rows: 7,
cols: 7,
},
];
const App = () => {
const toggle = () => {
const images = document.querySelectorAll('.grid-elt img');
images.forEach(img => {
img.style.display = img.style.display === 'none' ? 'block' : 'none';
});
};
return (
<div className="App">
<div className="header">
<h2>Header</h2>
<button onClick={toggle}>show/hide pictures</button>
</div>
<div className="grid">
{elements.map((elt) => (
<div
className="grid-elt"
style={{
gridColumn: `${elt.x} / ${elt.x + elt.cols}`,
gridRow: `${elt.y} / ${elt.y + elt.rows}`,
}}
>
{ <img
className="img"
src="https://cdn-icons-png.flaticon.com/512/13371/13371271.png"
/>}
</div>
))}
</div>
<div className="footer">
<h3>Footer</h3>
</div>
</div>
);
};
// Render it
ReactDOM.render(
<App/>,
document.getElementById("root")
);
html {
display: flex;
width: 100%;
height: 100%;
flex: 1;
}
body {
display: flex;
flex: 1;
height: 100%;
margin: 0;
}
#root {
display: contents;
}
.App {
font-family: sans-serif;
text-align: center;
background-color: cadetblue;
display: flex;
flex: 1;
flex-direction: column;
width: 100%;
height: 100%;
margin: 0;
}
.header {
height: 100px;
background-color: bisque;
}
.footer {
background-color: blueviolet;
height: 50px;
}
.grid {
display: grid;
grid-template-columns: repeat(50, 1fr);
grid-template-rows: repeat(50, 1fr);
height: 100%;
width: 100%;
}
.grid-elt {
border: 1px solid red;
position: relative;
}
.img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Answered By - Diego D
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.