Flexbox/Float anchor items to top [duplicate] - html

This question already has answers here:
Create a Masonry grid with flexbox (or other CSS)
(3 answers)
Closed 5 years ago.
Consider this example:
Notice that that 4th item is pushed to top instead of aligning with the 3rd item. I can't achieve this using flexbox's align-items: flex-end, neither with floats.
I am aware of achieving this by using masonry/isotope, but I would like to avoid using javascript just for this layout.
Is it possible to achieve using only CSS?

Yes, it's possible via CSS Grid Layout:
.grid {
display: grid;
grid-gap: 10px 30px;
grid-template-rows: auto 1fr auto;
}
/* styles just for demo */
.grid__item {
background-color: #e0e0e0;
font-size: 30px;
padding: 10px;
}
.b, .d {
align-self: flex-start;
}
.a {
grid-row: 1 / span 2;
/* setting height just for demo */
height: 200px;
}
.b {
grid-column: 2;
}
.c {
grid-row: 3;
}
.d {
grid-column: 2;
}
<div class="grid">
<div class="grid__item a">1</div>
<div class="grid__item b">2</div>
<div class="grid__item c">3</div>
<div class="grid__item d">4</div>
</div>
If you need IE\Edge support you should use old grid syntax. You can fake grid-gap using additional grid columns and rows. Demo:
.grid {
display: -ms-grid;
display: grid;
-ms-grid-columns: 1fr 30px 1fr;
grid-template-columns: 1fr 30px 1fr;
-ms-grid-rows: auto 10px 1fr 10px auto;
grid-template-rows: auto 10px 1fr 10px auto;
}
/* styles just for demo */
.grid__item {
background-color: #e0e0e0;
font-size: 30px;
padding: 10px;
}
.b, .d {
-ms-grid-row-align: start;
align-self: flex-start;
}
.a {
-ms-grid-row-span: 3;
grid-row: 1 / span 3;
/* setting height just for demo */
height: 200px;
}
.b {
-ms-grid-column: 3;
grid-column: 3;
}
.c {
-ms-grid-row: 5;
grid-row: 5;
}
.d {
-ms-grid-column: 3;
grid-column: 3;
-ms-grid-row: 3;
grid-row: 3;
}
<div class="grid">
<div class="grid__item a">1</div>
<div class="grid__item b">2</div>
<div class="grid__item c">3</div>
<div class="grid__item d">4</div>
</div>

Related

CSS layout - grid or flex [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I'm trying to create this layout.
https://pasteboard.co/K1C5o3k.jpg
I tried to use display: grid but the spacing was strange. What would be the best solution? Use grid or flexbox? How do I achieve this spacing using grid or flexbox?
<div class="wrap">
<div class="test-grid">
<div class="card box1">some text</div>
<div class="card box2">some text</div>
<div class="card">some text</div>
<div class="card box4">some text</div>
</div>
</div>
.wrap {
max-width: 600px;
}
.test-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 1em;
}
.card {
background-color: tomato;
width: 160px;
min-height: 220px;
}
.box1 {
margin-top: 40px;
}
.box4 {
grid-column-start: 2;
grid-column-end: 4;
grid-row-start: 2;
grid-row-end: 3;
}
On your grid layout, I use grid-template-row/columns to define the fraction amount and then grid-template-areas to layout the elements, for each child element you want to define the unique class as its grid-area. You can use gap to control the spacing between the elements. Once you define a height and width for the parent element, the children will fill in their respective fraction, along with any defined gap.
Then use a media query with flex for your mobile layout. You may need to tweek the CSS a bit to get it to look just as you want, but the following example should do the trick.
.test-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
gap: 20px 20px;
grid-template-areas:
". two ."
"one two four"
"one three four"
". three .";
width: 100vw;
height: 100vh;
}
.one {
grid-area: one;
background-color: tomato;
}
.two {
grid-area: two;
background-color: tomato;
}
.three {
grid-area: three;
background-color: tomato;
}
.four {
grid-area: four;
background-color: tomato;
}
.box {
display: flex;
justify-content: center;
align-items: center;
}
#media only screen and (max-width: 600px) {
.test-grid {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
}
.box {
width: 100%;
height: 100%;
}
}
<div class="test-grid">
<div class="one box">some text</div>
<div class="two box">some text</div>
<div class="three box">some text</div>
<div class="four box">some text</div>
</div>
Both Grid and flex will do the work, it just based on your preferences.
Snippet below will do the trick and when the screen became small (less than 500px). The grid will show as a list.
.wrap {
max-width: 600px;
}
.test-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 1em;
}
.card {
background-color: tomato;
width: 160px;
min-height: 220px;
}
.box1 {
grid-column: 1/span 1;
grid-row: 2/span 2;
}
.box2 {
grid-column: 2/span 2;
grid-row: 1/span 1;
}
.box3 {
grid-column: 3/span 2;
grid-row: 2/span 2;
}
.box4 {
grid-column: 2/span 2;
grid-row: 3/span 3;
}
#media (max-width: 500px) {
.test-grid {
display: flex;
flex-direction: column;
justify-content: space-between;
}
}
<div class="wrap">
<div class="container">
<div class="test-grid">
<div class="card box1">box1</div>
<div class="card box2">box2</div>
<div class="card box3">box3</div>
<div class="card box4">box4</div>
</div>
</div>
Here's an option using only grid. In this example we create many small grid rows (10px each) which then allows you to start each element at a specific row and adjust the boxes by 10 pixel increments.
.test-grid {
display: grid;
grid-template-columns: repeat(3, 160px);
grid-template-rows: repeat(45, 10px);
column-gap: 10px;
}
.card {
background-color: tomato;
width: 160px;
min-height: 220px;
}
.box1 {
grid-row-start: 10;
}
.box2 {
grid-row-start: 0;
grid-column-start: 2;
}
.box3 {
grid-row-start: 24;
grid-column-start: 2;
}
.box4 {
grid-row-start: 8;
grid-column-start: 3;
}
<div class="wrap">
<div class="test-grid">
<div class="card box1">some text</div>
<div class="card box2">some text</div>
<div class="card box3">some text</div>
<div class="card box4">some text</div>
</div>
</div>

Making grid responsive

Any idea of how to make this grid responsive?
This is my CSS:
body {
margin: 40px;
}
.wrapper {
display: grid;
grid-gap: 10px;
grid-template-columns: 100px 100px 100px;
background-color: #fff;
color: #444;
}
.box {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 20px;
font-size: 150%;
}
.a {
grid-column: 1 / 3;
grid-row: 1;
}
.b {
grid-column: 3 ;
grid-row: 1 / 3;
}
.c {
grid-column: 1 ;
grid-row: 2 ;
}
.d {
grid-column: 2;
grid-row: 2;
}
HTML
<div class="wrapper">
<div class="box a">A</div>
<div class="box b">B</div>
<div class="box c">C</div>
<div class="box d">D</div>
</div>
I tried this code:
#media only screen and (max-width:500px) {
.box {
width: 100%;
margin-right: 0;
float: none;
margin-bottom: 20px !important;
}
What's the best way to accomplish this?
I agree with #Petra that you need to use fr, but use a media query if you want to display them stacked on a mobile device. You could also just change the display to block. Make sure you add these after the initial CSS so that it isn't overridden.
#media screen and (max-width: 512px) {
.wrapper {
grid-template-columns: 1fr;
}
}
.wrapper {
display: grid;
grid-gap: 10px;
grid-template-columns: 1fr 1fr 1fr;
background-color: #fff;
color: #444;
}
ith CSS Grid Layout, we get a new flexible unit: the Fr unit. Fr is a fractional unit and 1fr is for 1 part of the available space.

CSS Grid - auto column height

The cart form is stretching vertically and the thumbs are positioning in the bottom left corner, when I'd like them to sit directly under the cart form like so:
.product-page--main-content {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: auto 1fr auto;
}
.product-page--main-content>* {
padding: 50px 100px;
border: 1px solid #ccc;
}
.product-page--cart-form-block {
grid-row: 2;
}
.product-page--thumbs {
grid-row: 3;
}
.product-page--images {
grid-column: span 2;
grid-row: span 3;
height: 400px;
}
.product-page--description {
grid-row: span 3;
}
<div class="product-page--main-content">
<div class="product-page--title-n-vendor">Title</div>
<div class="product-page--cart-form-block">Cart form</div>
<div class="product-page--thumbs">Thumbs</div>
<div class="product-page--images">Images</div>
<div class="product-page--description">Description</div>
</div>
Codepen: https://codepen.io/paulmason/pen/rYXyYW
The code you have is working perfectly, as written.
Your image grid item is set to height: 400px.
.product-page--images {
grid-column: span 2;
grid-row: span 3;
height: 400px;
}
Then you have 50px in top and bottom padding.
.product-page--main-content > * {
padding: 50px 100px;
border: 1px solid #ccc;
}
So the image grid item is 500px tall, in a row set to 1fr, in a grid with three rows. It all works perfectly, as specified.
Maybe what you want is four rows:
.product-page--main-content {
display: grid;
grid-template-columns: repeat(4, 1fr);
/* grid-template-rows: auto 1fr auto; */ /* now defaults to grid-auto-rows: auto */
}
.product-page--main-content > * {
padding: 50px 100px;
border: 1px solid #ccc;
}
.product-page--cart-form-block {
grid-row: 2;
}
.product-page--thumbs {
grid-row: 3;
}
.product-page--images {
grid-column: span 2;
grid-row: span 4; /* changed from 3 */
height: 400px;
}
.product-page--description {
grid-row: span 4; /* changed from 3 */
}
<div class="product-page--main-content">
<div class="product-page--title-n-vendor">Title</div>
<div class="product-page--cart-form-block">Cart form</div>
<div class="product-page--thumbs">Thumbs</div>
<div class="product-page--images">Images</div>
<div class="product-page--description">Description</div>
</div>
I'm not sure this is what you're asking but this seems to fit: change
grid-template-rows: auto 1fr auto;
to
grid-template-rows: 3;

Grid layout align-items doesn't respect grid row dimensions

Look at this codepen:
https://codepen.io/rachelandrew/pen/WQNqKy
body {
margin: 40px;
font: 80% Arial, Helvetica, sans-serif;
}
.wrapper {
display: grid;
align-items: center;
background: no-repeat url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/12005/grid.png);
grid-gap: 10px;
grid-template-columns: repeat(6, 150px);
grid-template-rows: repeat( 4, 150px);
background-color: #fff;
color: #444;
}
.box {
border: 1px solid #444;
padding: 20px;
font-size: 150%;
}
.a {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
.b {
grid-column: 3 / 5;
grid-row: 1 / 3;
}
.c {
grid-column: 1 / 3;
grid-row: 3 / 6;
}
.d {
grid-column: 3 / 5;
grid-row: 3 / 6;
}
.e {
grid-column: 5 / 7;
grid-row: 1 / 6;
align-self: stretch;
}
<div class="wrapper">
<div class="box a">
<p>This is box A. </p>
</div>
<div class="box b">
<p>This is box B.</p>
</div>
<div class="box c">
<p>This is box C.</p>
</div>
<div class="box d">
<p>This is box D.</p>
</div>
<div class="box e">
<p>Each of the boxes on the left has a grid area of 3 columns and 3 rows (we're counting the gutter col/row). </p>
<p>The align-items property is used to align the content inside each grid-area.</p>
<p>Other values of align-items are:</p>
<ul>
<li>stretch</li>
<li>start</li>
<li>end</li>
<li>center</li>
</ul>
</div>
</div>
from
https://gridbyexample.com/examples/example24/
Element a has these rules:
.a {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
without align-items: center;
it takes the first two square (x,y)
as the rule states, but if I apply the rule
align-items: center to the parent
the size becomes smaller.
Can anyone explain why, please ?
The HTML structure of a grid container consists of three levels:
the container
the item
the content
Each of these levels represents a separate element.
When you apply align-items: center to the container, it applies to the grid item. That is exactly what is happening in your code sample.
If you want the content of the grid item centered, then you don't target it from the primary container (2 levels up). You target it from the grid item (the parent).
You can center the text using a nested grid or even flex container.
.wrapper {
display: grid;
/* align-items: center; */
grid-gap: 10px;
grid-template-columns: repeat(6, 150px);
grid-template-rows: repeat( 4, 150px);
}
.box {
display: flex; /* new */
align-items: center; /* new; vertical alignment */
justify-content: center; /* new (and optional); horizontal alignment */
}
revised codepen
body {
margin: 40px;
font: 80% Arial, Helvetica, sans-serif;
}
.wrapper {
display: grid;
/* align-items: center; */
background: no-repeat url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/12005/grid.png);
grid-gap: 10px;
grid-template-columns: repeat(6, 150px);
grid-template-rows: repeat( 4, 150px);
background-color: #fff;
color: #444;
}
.box {
border: 1px solid #444;
padding: 20px;
font-size: 150%;
display: flex;
align-items: center;
justify-content: center;
/* optional */
}
.a {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
.b {
grid-column: 3 / 5;
grid-row: 1 / 3;
}
.c {
grid-column: 1 / 3;
grid-row: 3 / 6;
}
.d {
grid-column: 3 / 5;
grid-row: 3 / 6;
}
.e {
grid-column: 5 / 7;
grid-row: 1 / 6;
align-self: stretch;
}
<div class="wrapper">
<div class="box a">
<p>This is box A. </p>
</div>
<div class="box b">
<p>This is box B.</p>
</div>
<div class="box c">
<p>This is box C.</p>
</div>
<div class="box d">
<p>This is box D.</p>
</div>
</div>
More details here: Centering in CSS Grid

How can I use Flexbox to align two boxes in a column, next to a row?

What I would like to do is quite particular, so I've drawn a picture to illustrate it:
I can easily implement this:
but it doesn't look good on this site because the E element is much taller than C or D.
What I would like, is for C and D to stack when the browser window is wide, but not when it's medium width.
I'm trying to implement this with CSS and Flexbox, and I've tried grouping together C and D in a div, but this creates problems at the medium layout.
Flexbox is 1D layout. Of course you can add some nesting, some fixed heights, but it's 1D and isn't perfect solution here.
It's much much better to use CSS Grid Layout here, because it's 2D layout.
.grid {
display: grid;
}
/* just styles for demo */
.grid__item {
font-size: 3em;
padding: 20px;
background-color: orange;
color: white;
margin: 10px;
/* using flexbox for text centering */
display: flex;
align-items: center;
justify-content: center;
}
/* medium screen */
#media screen and (min-width: 700px) and (max-width: 999px) {
.a {
grid-column: 1 / span 2;
}
}
/* wide screen */
#media screen and (min-width: 1000px) {
.grid {
grid-template-columns: 1fr 1fr 1fr;
}
.a {
grid-column: 1 / span 2;
}
.d {
grid-row: 3;
}
.e {
grid-column: 2 / span 2;
grid-row: 2 / span 2;
}
}
<div class="grid">
<div class="grid__item a">A</div>
<div class="grid__item b">B</div>
<div class="grid__item c">C</div>
<div class="grid__item d">D</div>
<div class="grid__item e">E</div>
</div>
If you need IE/Edge support you'll have to use outdated syntax and specify place for every row manually. IE/Edge implementation doesn't have grid cell auto-placement. So if you don't specify grid-column/grid-row for every cell they will all stack in very first cell. So for IE/Edge -ms-grid-row and -ms-grid-column default value is 1. Demo:
.grid {
display: grid;
}
/* just styles for demo */
.grid__item {
font-size: 3em;
padding: 20px;
background-color: orange;
color: white;
margin: 10px;
/* using flexbox for text centering */
display: flex;
align-items: center;
justify-content: center;
}
/* medium screen */
#media screen and (min-width: 700px) and (max-width: 999px) {
.grid {
display: -ms-grid;
-ms-grid-columns: 1fr 1fr;
}
.a {
-ms-grid-column: 1;
-ms-grid-column-span: 2;
grid-column: 1 / span 2;
}
.b {
-ms-grid-row: 2;
}
.c {
-ms-grid-row: 2;
-ms-grid-column: 2;
}
.d {
-ms-grid-row: 3;
}
.e {
-ms-grid-row: 3;
-ms-grid-column: 2;
}
}
/* wide screen */
#media screen and (min-width: 1000px) {
.grid {
display: -ms-grid;
-ms-grid-columns: 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr;
}
.a {
-ms-grid-column: 1;
-ms-grid-column-span: 2;
grid-column: 1 / span 2;
}
.b {
-ms-grid-column: 3;
}
.c {
-ms-grid-row: 2;
}
.d {
-ms-grid-row: 3;
grid-row: 3;
}
.e {
-ms-grid-row: 2;
-ms-grid-row-span: 2;
grid-row: 2 / span 2;
-ms-grid-column: 2;
-ms-grid-column-span: 2;
grid-column: 2 / span 2;
}
}
<div class="grid">
<div class="grid__item a">A</div>
<div class="grid__item b">B</div>
<div class="grid__item c">C</div>
<div class="grid__item d">D</div>
<div class="grid__item e">E</div>
</div>
If you want to test resizing here is jsFiddle.
demo
change the flex value as you desired
.box {
background-color: green;
margin: 5px;
/* padding: 30px; */
}
.one {
display: flex;
}
.a {
flex: 3;
}
.b {
flex: 2;
}
.two {
display: flex;
}
.three {
flex: 2;
}
.four {
flex: 3;
}
<div class="main">
<div class="one">
<div class="a box">a</div>
<div class="b box">b</div>
</div>
<div class="two">
<div class="three">
<div class="c box">c</div>
<div class="d box">d</div>
</div>
<div class="four box">
<div class="e">e</div>
</div>
</div>
</div>