带柔性盒的正方形网格

我正在尝试创建一个响应网格的方块。正方形应该调整大小以适应视窗的宽度。当改变视图窗口的高度时,正方形不应该调整大小。

我知道如何调整每个正方形的宽度,但是我不知道如何使元素成为正方形,以及如何在视窗宽度变化时调整它们的高度。

在小提琴下面的例子中,七个正方形应该总是水平合适,并且它们应该按照正方形缩放。我不在乎有多少行可见。

拨弄这里 http://jsfiddle.net/gonyhvz8/11/

<body>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>

.flex-container {
padding: 0;
margin: 0;
list-style: none;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row;
justify-content: space-around;
height: 50px;
line-height:30px;
}


.flex-item {
background: tomato;
margin: 5px;
color: white;
font-weight: bold;
font-size: 1.5em;
text-align: center;
flex: 1 0 0px;
height: auto;
}
98119 次浏览

The usual trick for maintaining aspect ratio is to use the fact that percentage values of margin and/or padding top & bottom are calculated based on the width of the containing element, and not the height.

You can see a non-flex version of this question HERE

However, you would like to have flex deal with the width of your elements, not set percentage based widths. For that, I have come up with a variation of that approach that will work with flex:

.flex-item:before {
content: "";
display: block;
padding-top: 100%;
float: left;
}

The trick here is to use the :before pseudo-element to insert a 0 width element with a padding-top of 100%. That 100% is 100% of the width, meaning this element with no content will be equally as tall as its container. This will stretch the flex-item to the same height as its width:

Additionally, you will need to remove the defined height from your flex-container or the height can't grow. You also may want to add min-width: 1.5em so that your elements don't shrink below the height of the character you have in each square.

http://jsfiddle.net/gonyhvz8/14/

.flex-container {
padding: 0;
margin: 0;
list-style: none;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row;
justify-content: space-around;
line-height:30px;
}


.flex-item {
background: tomato;
margin: 5px;
color: white;
font-weight: bold;
font-size: 1.5em;
text-align: center;
flex: 1 0 0px;
min-width: 1.5em;
}
.flex-item:before {
content: "";
display: block;
padding-top: 100%;
float: left;
}
<body>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
</body>


edit 2022 Nowdays, aspect-ratio becomes widely avalaible. set a width or an height then for a square use the 1/1 ratio : aspect-ratio: 1 / 1 ;

ressources:

snippets becomes (note: no width nor height set, since we are in flex layout and flex-grow is set to 1 flex: 1 0 auto; , doing the sizing job ):

.flex-container {
padding: 0;
margin: 0;
list-style: none;
display: flex;
justify-content: space-around;
}
.flex-item {
background: tomato;
margin: 5px;
color: white;
font-weight: bold;
font-size: 1.5em;
text-align: center;
flex: 1 0 auto;
aspect-ratio: 1 / 1 ;
}


/* Item can be any kind of box from here . flex/grid/block */
.flex-item {display:grid;align-items:center;justify-content:center;}
<body>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
</body>


original answer

you should not set any size. you may use an extra element or a pseudo elemnt with vertical padding in %. this will allow you to use width as reference : a snippet to show:

.flex-container {
padding: 0;
margin: 0;
list-style: none;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row;
justify-content: space-around;
   

line-height:30px;
}
.flex-item {
background: tomato;
margin: 5px;
color: white;
font-weight: bold;
font-size: 1.5em;
text-align: center;
flex: 1 0 auto;
height:auto;
}
.flex-item::before {
content:'';
float:left;
padding-top:100%;
}
<body>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
</body>

an inline-block element could do too, just adapt the display/behavior of the box and it's content. the magic here comes from padding:50% 0; (100% vertical padding equals width of parent). see w3c about vertical margin and padding

[edit 07/2021]about centering the content inside that square for who ever needs this too (make the square itself a flex boxe too):

.flex-container {
padding: 0;
margin: 0;
list-style: none;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row;
justify-content: space-around;
   

line-height:30px;
}
.flex-item {
background: tomato;
margin: 5px;
color: white;
font-weight: bold;
font-size: 1.5em;
text-align: center;
flex: 1 0 auto;
height:auto;
    

display:flex;
align-items:center;
justify-content:center;
}
.flex-item::before {
content:'';
padding-top:100%;
}
<body>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
</body>

You may also think interesting : Responsive grid of squares within a responsive grid of squares & 4x4 grid of squares that scale up to a maximum width if this answer do not fully suits your square needs ;)

Surely it is nice to use flexboxes, but the solution mentioned has a lack of flexability even it uses flexboxes. You are not able to adjust a floating of boxes. You are bounded to set the number of boxes per row before.

In this solution you can adapt a dynamic width of tiles/square and float them how you like. If you try this with flexboxes, you will get a problem with padding-top because it does not orientate on the given width of the containing blocks.

Solution without flexboxes but more flexability:

.flex-container {
padding: 0;
margin: -5px;
font-size: 0;
font-family: Helvetica, Arial, sans-serif;
}


.flex-item {
position: relative;
display: inline-block;
height: 0;
width: 100%;
padding-top: 100%;
height: auto;
font-size: 20px;
color: white;
font-weight: bold;
text-align: center;
}
@media (min-width: 480px) {
.flex-item {
width: 33.3333%;
padding-top: 33.3333%;
}
}
@media (min-width: 768px) {
.flex-item {
width: 25%;
padding-top: 25%;
}
}
.flex-item-inner {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: 10px;
background: tomato;
}
<body>
<div class="flex-container">
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
1
</div>
</div>
</div>
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
2
</div>
</div>
</div>
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
3
</div>
</div>
</div>
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
4
</div>
</div>
</div>
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
5
</div>
</div>
</div>
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
6
</div>
</div>
</div>
</div>
</body>

Link to the codepen: http://codepen.io/dailysh-it/pen/xOVydO

For those that also want to use display: flex inside the square divs, you need to use display: table for the :before element, otherwise the square will work with Chrome but won't work with Firefox or Edge (as of Firefox 47 and Edge 13).

In the snippet bellow, which should work for all browsers, I also demonstrate how to wrap unlimited items with percentage columns (in this case 20%) and separate them with padding and inner divs, since margins with percentages do not work correctly in FF and of course Edge.

.flex-container {
display: flex;
justify-content: start;
flex-wrap: wrap;
}


.flex-cell {
flex: 0 0 20%;
display: flex;
justify-content: center;
align-items: stretch;
padding: 0.5rem;
box-sizing: border-box;
}


.flex-cell:before {
content: '';
display: table;
padding-top: 100%;
}


.flex-item {
flex-grow: 1;
border: 1px solid black;
background: tomato;
color: white;
  

display: flex;
justify-content: center;
align-items: center;
}
<body>
<div class="flex-container">
<div class="flex-cell">
<div class="flex-item">1</div>
</div>
<div class="flex-cell">
<div class="flex-item">2</div>
</div>
<div class="flex-cell">
<div class="flex-item">3</div>
</div>
<div class="flex-cell">
<div class="flex-item">4</div>
</div>
<div class="flex-cell">
<div class="flex-item">5</div>
</div>
<div class="flex-cell">
<div class="flex-item">6</div>
</div>
<div class="flex-cell">
<div class="flex-item">7</div>
</div>
<div class="flex-cell">
<div class="flex-item">8</div>
</div>
<div class="flex-cell">
<div class="flex-item">9</div>
</div>
<div class="flex-cell">
<div class="flex-item">10</div>
</div>
<div class="flex-cell">
<div class="flex-item">11</div>
</div>
<div class="flex-cell">
<div class="flex-item">12</div>
</div>
</div>
</body>

There is a way to made it with no extra html elements also. I created a fiddle with your codebase http://jsfiddle.net/octavioamu/kq97pm3L/ but the tick is to use after elemento with display table

flex-item:after {
content: ' ';
padding-top: 100%;
display: table;
}

You can use it in any grid, for example an square inside a column grid with bootstrap... Here is a sass mixin working inside a % grid column https://codepen.io/octavioamu/pen/xzeXGm

And here is with your code:

.flex-container {
display: flex;
}


.flex-item {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
background-color: red;
margin: 5px
}


.flex-item:after {
content: ' ';
padding-top: 100%;
display: table;
}
<body>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
</body>

Simplified Version of G-Cyr's Answer

.flex-container {
display: flex;
flex-flow: row;
justify-content: center;
}


.flex-item {
background: tomato;
margin: 10px;
max-width: 50px;
flex-grow: 1;
flex-shrink: 0;
flex-basis: 0;
height: auto;
}


.flex-item:before {
/* The psuedo-element's padding-top percentage is based on the element's width. */
padding-top: 100%;
content: '';
float: left;
}
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
</div>
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
</div>

Result

enter image description here