问题
I am trying to create grid/layout consists of squares. Four squares in each row. Squares can't distort on screen resize. Width and height must be the same all the time (I don't want fixed values). I must use CSS grid. Can anyone help me ?
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-gap: 5px;
}
.container div {
background-color: red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
回答1:
With CSS only you could use a pseudoelement to keep always the aspect ratio to 1:1
, e.g.
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-gap: 5px;
}
.container div {
background-color: red;
}
.container div::before {
content: "";
padding-bottom: 100%;
display: inline-block;
vertical-align: top;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
回答2:
For the fun, curiosity of grid
behavior and to avoid a pseudo element,
You may also set an height equal to the width of your grid container, the grid system will automaticly stretch the rows.
A good reminder to mind :
https://css-tricks.com/snippets/css/complete-guide-grid/
and examples https://gridbyexample.com/
working example if your grid uses entire browser's width
* {
margin: 0;
padding: 0;
}
.container {
display: grid;
height: calc(50vw - 5px); /*instead playing around with grid gap gap */
grid-template-columns: 1fr 1fr 1fr 1fr;
}
.container div {
/* bg to show i'm squarred or not ? */
background-image: linear-gradient( 45deg, transparent 50%, rgba(0, 0, 0, 0.5) 50%);
margin: 0 5px 5px 0; /*instead playing around with grid gap gap */
background-color: red;
}
/* extra for demo, not needed */
.container {
counter-reset: test;
}
.container div {
display: flex; /* or grid */
}
.container div:before {
counter-increment: test;
content: 'Div N°:'counter(test)' -';
margin: auto;/* center me */
color: yellow;
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
A codepen to fork or play with
回答3:
Another trick where you can put any content inside without breaking the ratio. The idea is to have the grid inside a big square that you divide into small squares:
.container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
grid-gap: 5px;
}
.container div {
background-color: red;
}
body:before {
content: "";
display: block;
padding-top: 100%;
}
body {
position: relative;
margin: 0;
}
img {
max-width: 100%;
max-height: 100%;
}
<div class="container">
<div>any contet here</div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/300?image=1069"></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
<div>any contet here any contet here</div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
<div></div>
</div>
Another syntax without position:absolute
where you can rely on the stretch feature of flexbox:
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
grid-gap: 5px;
flex-grow:1;
}
.container div {
background-color: red;
}
body:before {
content: "";
padding-top: 100%;
}
body {
display:flex;
}
img {
max-width: 100%;
max-height: 100%;
}
<div class="container">
<div>any contet here</div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/300?image=1069"></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
<div>any contet here any contet here</div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
<div></div>
</div>
You can control the limit of rows. In the above I made them 4, we can have only 2 by making the padding 50%
instead of 100%
. We will have a big rectangle inside where will have 8 squares (4 in each row).
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-gap: 5px;
flex-grow:1;
}
.container div {
background-color: red;
}
body:before {
content: "";
padding-top: 50%;
}
body {
display:flex;
margin: 0;
}
img {
max-width: 100%;
max-height: 100%;
}
<div class="container">
<div>any contet here</div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/300?image=1069"></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
</div>
You can control the number of rows using CSS variables:
:root {
--n:6;
}
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: repeat(var(--n),1fr);
grid-gap: 5px;
flex-grow:1;
}
.container div {
background-color: red;
}
body:before {
content: "";
padding-top: calc(var(--n) * 25%);
}
body {
display:flex;
}
img {
max-width: 100%;
max-height: 100%;
display:block;
}
<div class="container">
<div>any contet here</div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/300?image=1069"></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
<div>any contet here</div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/300?image=1069"></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/300?image=1069"></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
</div>
We can also add a control on the number of columns by adding another variable to have something more generic:
:root {
--n:6;
--m:6;
}
.container {
display: grid;
grid-template-columns: repeat(var(--m),1fr);
grid-template-rows: repeat(var(--n),1fr);
grid-gap: 5px;
flex-grow:1;
}
.container div {
background-color: red;
}
body:before {
content: "";
padding-top: calc(var(--n)/var(--m) * 100%);
}
body {
display:flex;
}
img {
max-width: 100%;
max-height: 100%;
}
<div class="container">
<div>any contet here</div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/300?image=1069"></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
<div>any contet here</div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/300?image=1069"></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
<div></div>
<div></div>
<div><img src="https://picsum.photos/200/300?image=1069"></div>
<div></div>
<div><img src="https://picsum.photos/200/200?image=1062"></div>
<div>any contet here any contet here</div>
<div></div>
<div></div>
</div>
回答4:
** @fcalderan's answer solves the issue and all credit reserved. **
This obviously breaks the square shape, but if you would be using any text a small adjustment will work in your favor. You could rather use the ::after
pseudo element to not push down or split potential content. Changing to display: block
also removes the necessity of vertical-aling: top
as far as I know.
To further preserve the aspect ratio when using text, I'd make the text position: absolute
.
See the snippet below when using ::before
vs. ::after
to illustrate my point.
.container,
.container2 {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-gap: 5px;
}
.container div {
background-color: red;
}
.container div::before {
content: "";
padding-bottom: 100%;
display: inline-block;
vertical-align: top;
}
.container2 div::after {
content: "";
padding-bottom: 100%;
display: block;
}
.container2 .text {
position: absolute;
}
.container2 div {
background-color: green;
position: relative;
overflow: hidden;
}
<div class="container">
<div>
<div class="text">Here is some text.</div>
</div>
<div>
<div class="text">Here is some more text.</div>
</div>
<div>
<div class="text">Here is some longer text that will break how this looks.</div>
</div>
</div>
<hr>
<div class="container2">
<div>
<div class="text">Here is some text.</div>
</div>
<div>
<div class="text">Here is some more text.</div>
</div>
<div>
<div class="text">Here is some longer text that will break how this looks.</div>
</div>
</div>
来源:https://stackoverflow.com/questions/54927180/css-grid-square-layout