Reputation: 1141
I am trying to create a responsive grid of squares. The squares should resize to fit the viewport's width. The squares should not resize when changing the viewport's height.
I got how to adjust the width of each square, but I don't know how to make the elements square and how to scale their height when the viewport width changes.
In the example at the fiddle below the seven squares should always fit horizontally, and they should scale as squares. I do not care how many rows are visible.
Fiddle here 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;
}
Upvotes: 90
Views: 112939
Reputation: 105873
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 ;)
Upvotes: 141
Reputation: 141462
.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>
Upvotes: 4
Reputation: 305
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>
Upvotes: 3
Reputation: 1518
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>
Upvotes: 32
Reputation: 3457
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
Upvotes: 4
Reputation: 78630
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>
Upvotes: 23