I’m trying to understand tailwind grids better - could someone help me understand what each of the parameters 1fr, 700px and 2fr do in
<!-- Complex grids -->
<div class="grid-cols-[1fr,700px,2fr]">
<!-- ... -->
</div>
To understand this, first you need to understand grid columns in general in CSS.
The code that you wrote translates to grid-template-columns: 1fr 700px 2fr; in pure CSS.
The grid-template-columns property specifies the number (and the widths) of columns in a grid layout.
CSS Syntax for grid-template-columns is this:
grid-template-columns: none|auto|max-content|min-content|length|initial|inherit;
You can read here more about grid-template-columns and order of parameters:
https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
https://www.w3schools.com/cssref/pr_grid-template-columns.asp
But in short, first parameter 1fr means 1 fractional unit.
By definition Fr unit is a fractional unit and 1fr is for 1 part of the available space.
The same goes for 2fr.
700px just means 700 pixels.
That further means that code above produces 3 columns grid container, with the size for each column of 1fr, 700px & 2fr.
How tailwind is doing that, you can read here:
https://tailwindcss.com/docs/grid-template-columns#arbitrary-values
https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values
In short, tailwind uses arbitrary values to allow you to specify something that doesn’t make sense to include in your theme so you can use square brackets to generate a property on the fly using any arbitrary value.
Result of your code is something like this:
You can play with this:
.grid-container {
display: grid;
grid-template-columns: 1fr 700px 2fr;
grid-gap: 10px;
background-color: #2196F3;
padding: 10px;
}
.grid-container>div {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 20px 0;
font-size: 30px;
}
<!DOCTYPE html>
<html>
<head></head>
<body>
<div class="grid-container">
<div class="item1">1fr</div>
<div class="item2">700px</div>
<div class="item3">2fr</div>
<div class="item1">1fr</div>
<div class="item2">700px</div>
<div class="item3">2fr</div>
<div class="item1">1fr</div>
<div class="item2">700px</div>
<div class="item3">2fr</div>
</div>
</body>
</html>
Related
I was trying to make the 2 items (box1 and box2) responsive on small screen, but I couldn't seem to figure it out. Please help. Thanks!
<html lang="en">
<head>
<style>
body{
background: lightblue;
}
.container{
padding:10px;
display: grid;
background: lightyellow;
width:100%;
grid-gap:5px;
justify-content:center;
grid-auto-flow: column;
grid-auto-columns: 300px 100px;
}
.box1{
background: lightgray;
min-height:150px;
}
.box2{
background: lightgreen;
min-height:150px;
}
</style>
</head>
<body>
<div class="container">
<div class="box box1">BOX 1</div>
<div class="box box2">BOX 2</div>
</div>
</body>
</html>
You've told the columns to be a fixed width...so they're naturally not responsive.
Use percentage or fractional values instead.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
::before,
::after {
box-sizing: inherit;
}
body {
background: lightblue;
}
.container {
padding: 10px;
display: grid;
background: lightyellow;
width: 100%;
grid-gap: 5px;
justify-content: center;
grid-auto-flow: column;
grid-auto-columns: 3fr 1fr;
}
.box1 {
background: lightgray;
min-height: 150px;
}
.box2 {
background: lightgreen;
min-height: 150px;
}
<div class="container">
<div class="box box1">BOX 1</div>
<div class="box box2">BOX 2</div>
</div>
grid-auto-columns: 300px 100px;
in that line above you use ABSOLUTE sizes. If you want them to be responsive use % instead of px.
something like
grid-auto-columns: 30% 10%;
Any time you use fixed pixel widths, your elements will remain at that size and not be responsive.
The quick and easy solution to this is to switch to percentage widths, which tells the element to be a proportion of its container's size. Assuming the container is itself responsive, then this will make your elements change size according to the width of the screens. You need to do this all the way through your CSS, as any fixed sizes further up the element tree could stop everything inside from responding.
However, a naive percentage figure is often not a perfect solution, because things may not look right with the same proportions at lower screen sizes. For example, a three-column layout may shrink down, but it will look very squashed on a small mobile phone screen.
There are a bunch of solutions to this, and the exact answer will depend on your page design and your preferences.
First up, consider using min-width and max-width with pixel sizes to limit the sizes of your elements. These CSS values will override the percentage if the percentage figure causes them to go above or below the max or min width that you specify. This can be helpful for preventing things from getting exessively squashed or stretched out while still responding appropriately within the desired range.
Next, you need to know about Media Queries. This is a CSS feature that allows you to specify CSS that is only applied when the browser size is within a specified range. (Media queries can do a lot more than this, but I'll leave it to you to investigate them further)
An example might help here:
#media(max-width:600px) {
.container {
grid-auto-flow: unset;
grid-auto-columns: unset;
}
}
The example above uses a media query to switch off your columns if the browser width is 600 pixels or less. For narrow browsers, a column-based layout may not be appropriate, so switching away from it at low resolutions is often a good idea.
I have 4 columns. The actual content for columns 1 and 4 is 150px, column 2 is 250px and column 3 is 370px. I want to wrap the columns when the browser width changes. When I decrease the width of the browser, I want each column to shrink down to their lowest width before wrapping. So I imagine the 4th column would fall to the next row with a 100% width after it fell below 150px width.
Here's what I thought should've done the trick:
repeat(auto-fit, minmax(max-content, 1fr))
Is there a way to achieve this without passing a fixed width where 'max-content' is?
Here's my solution using media queries and hard widths
https://jsfiddle.net/9hjb5qv8/
Here's the html/css I used in the fiddle above:
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(370px, 1fr));
grid-gap: 8px;
}
#media (max-width: 799px) {
.container {
grid-template-columns: minmax(max-content, 1fr);
}
}
#media (min-width: 800px) {
.container .p2,
.container .p3 {
grid-column: auto / span 2;
}
}
.container > div {
background-color: gray;
text-align: center;
}
<div class="container">
<div class="p1">
<img src="https://via.placeholder.com/150x150">
</div>
<div class="p2">
<img src="https://via.placeholder.com/250x150">
</div>
<div class="p3">
<img src="https://via.placeholder.com/370x150">
</div>
<div class="p4">
<img src="https://via.placeholder.com/150x150">
</div>
</div>
I had a similar question when playing around with grid:
grid-template-columns: repeat(auto-fit, minmax(max-content, 1fr))
If we take a look at the documentation we can see that minmax command is valid:
https://developer.mozilla.org/en-US/docs/Web/CSS/minmax
But in a repeat documentation on csswg, it states one simple rule that disallows all of this from happening;
https://drafts.csswg.org/css-grid/#funcdef-repeat
The generic form of the repeat() syntax is, approximately,
repeat( [ <positive-integer> | auto-fill | auto-fit ] , <track-list> )
The first argument specifies the number of repetitions. The second
argument is a track list, which is repeated that number of times.
However, there are some restrictions:
The repeat() notation can’t be nested.
Automatic repetitions (auto-fill or auto-fit) cannot be combined with
intrinsic or flexible sizes.
Whats an intrinsic or flexible sizes ?
An intrinsic sizing function (min-content, max-content, auto, fit-content()).
So the command wont work in grid because each column/row will be different sizes and wrapping cannot take place. See bellow picture as example.
This behavior should be executed using flex-box instead.
#kivylius has a great answer to why max-content, min-content or other intrinsic sizing wouldn't work with auto-fit. He also suggested using flexbox to achieve what you are after. So, I am just extending on his answer leaving the flexbox way of doing it.
.flex-auto-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
}
.flex-auto-wrap > * {
flex: 1; /* this is to make elements/columns in each row have equal width and fill up all available space in the row, similar to auto-fit in grid */
/* flex-grow: 1; this can be used to make elements/columns in each row maintain their individual width but stretch to fill up all available space in the row */
}
div {
color: #ddd;
background-color: #222;
padding: 5px;
text-align: center;
}
<section class="flex-auto-wrap">
<div>1</div>
<div>11</div>
<div>111</div>
<div>1111</div>
<div>11111</div>
</section>
PS: I used to think grid came as an alternative to flexbox so I would try to do everything using the newer grid technology. But as it turned out, even though you can do most things with grid, it still doesn't replace flexbox. In fact, flexbox is one dimensional whereas grid is two dimensional. So, they were meant to do things differently. That's why there are some things like this one that can only be done with flexbox but not grid and there are many things that can only be done with grid but not flexbox.
Currently I try to create an "image gallery" with flex box.
This is what I currently have: https://jsfiddle.net/neu28Lnc/2/
The width of the images are always 50% - meaning I will always have 2 images next to each other.
Height of the page is not fixed - you should be able to scroll / add more images.
The problem I have, is that I want to remove the gaps between those images.
Like this: https://jsfiddle.net/neu28Lnc/1/ (hard coded with margins).
Usually I would use flex-direction: column; but since I have a no height, it will never wrap to a 2nd column.
Maybe some of you can help me with my issue / have a better solution.
Thanks in advance.
Syllz
You can do something with css Grid, but after all, css grid is more for grids, of course.
A grid is made of lines which supports each other. Each rectangular form drawn by those lines inevitably share a common horizontal and vertical line.
Flexbox is another option, but you have to set a height to your container so that columns wrap with the flex-direction: column.
If you have a lot of elements, and they exceed the space given by the height we have established, the container will break, with the remaining elements showing up on one side.
The best option here is Multi-column. Example
Cons:
- We can't have an item span more than 1 column.
- The items aren`t listed horizontally.
For me is the best "css only" solution.
W3C - CSS Multiple Columns
You can use masonary using grid layout. Hope this is helpful to you.
.container {
display: grid;
grid-gap: 10px;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-rows: 20px;
}
.image {
height: 50px;
background: #ddd;
}
.image2 {
height: 150px;
background: #abc;
}
.image3 {
height: 180px;
background: #def;
}
.image4 {
height: 30px;
background: #fad;
}
.image5 {
height: 150px;
background: #ddd;
}
<div class="container">
<div class="image img">img1</div>
<div class="image2 img">img2</div>
<div class="image3 img">img3</div>
<div class="image4 img">img4</div>
<div class="image5 img">img5</div>
<div class="image img">img1</div>
<div class="image2 img">img2</div>
<div class="image3 img">img3</div>
<div class="image4 img">img4</div>
<div class="image5 img">img5</div>
</div>
Why do I have an overflow on the X axis in the following snippet?
The overflow is generated once I apply grid-gap: 10px on my .body grid container.
div:not(.header):not(.body):not(.row) {
border: 1px solid grey;
}
.header {
margin-top: 20px;
display: grid;
grid-gap: 10px;
grid-template-areas: "header-left header-right-up" "header-left header-right-down";
grid-template-rows: 40px 40px;
grid-template-columns: minmax(50px, 200px) auto;
}
.header-left {
grid-area: header-left;
}
.header-right-up {
grid-area: header-right-up;
}
.header-right-down {
grid-area: header-right-down;
}
.body {
margin-top: 20px;
display: grid;
grid-template-columns: 25% 50% 25%;
grid-auto-rows: 80px;
grid-gap: 10px;
}
.row-left {
}
.row-center {
}
.row-right {
}
<div class="header">
<div class="header-left">image</div>
<div class="header-right-up">content</div>
<div class="header-right-down">long content</div>
</div>
<div class="body">
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
</div>
</div>
https://codepen.io/anon/pen/WdJExz?editors=1100
Short Answer
Because the width of the columns plus the width of the gaps is greater than 100%.
Explanation
You have a 3-column grid container (.body):
grid-template-columns: 25% 50% 25%
The total width of those columns is 100%.
You're then adding gutters between the columns (and rows):
grid-gap: 10px
which is shorthand for:
grid-column-gap: 10px;
grid-row-gap: 10px;
So this becomes the width calculation:
25% + 50% + 25% + 10px + 10px
Hence,
100% + 20px > 100%, which results in an overflow condition
Note that the grid-*-gap properties apply only between grid items – never between items and the container. That's why we calculate two grid gaps, not four.
As a solution, instead of percentage units, try using fr units, which apply only to free space. This means that fr lengths are calculated after any grid-gap lengths are applied.
grid-template-columns: 1fr 2fr 1fr
div:not(.header):not(.body):not(.row) {
border: 1px solid grey;
}
.header {
margin-top: 20px;
display: grid;
grid-gap: 10px;
grid-template-areas: "header-left header-right-up" "header-left header-right-down";
grid-template-rows: 40px 40px;
grid-template-columns: minmax(50px, 200px) auto;
}
.header-left {
grid-area: header-left;
}
.header-right-up {
grid-area: header-right-up;
}
.header-right-down {
grid-area: header-right-down;
}
.body {
margin-top: 20px;
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* ADJUSTMENT */
grid-auto-rows: 80px;
grid-gap: 10px;
}
.row-left {}
.row-center {}
.row-right {}
<div class="header">
<div class="header-left">image</div>
<div class="header-right-up">content</div>
<div class="header-right-down">long content</div>
</div>
<div class="body">
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
</div>
revised codepen demo
More details here: The difference between percentage and fr units
If you want to use percentages or some other unit, there is one more solution. The use of the minmax() function will allow the columns to shrink to fit the parent container and not cause overflow.
The solution would look like this:
grid-template-columns: minmax(auto, 25%) minmax(auto, 50%) minmax(auto, 25%);
gap: 10px;
More on the minmax() function here.
If you have a fixed number of grid columns that should be the same width and use grid-gap, there's a way to do it:
display: grid;
grid-template-columns: repeat(4, calc(25% - 0.75em));
grid-gap: 1em;
In this case, each row would have 4 grid columns, and the total space occupied by grid-gap would be 3em. In order to distribute the overflowing space evenly, divide the space by the number of grid columns.
3em / 4 = 0.75em
This makes all the grid columns have the same width.
Codepen demo
Late reply but 100% worth it.
Summary from many resources.
Usage with %
Grid columns calculated with % are not taking into accounts gutters (aka gaps). Therefore you need to add the pixels of the added gaps to the calculation. so totalGridWidth = SUM(...%) + gutters = ~100% + gutters
Usage with fr
The previous issue does not happen (exception on number 3.) as it includes to calculate the free space as well with the gaps. so calculation is as follow: (free space - gutters) / 12 = 1fr therefore here you could get ratios as fractions instead of portions as percentages.
Or in other words with the Least Common Divisor (1fr = 25%):
grid-template-columns: 1fr 2fr 1fr;
Usage with minmax(0,Xfr)
By default the browser layout engine uses to calculate Xfr this formula minmax(auto,Xfr) which relies on the minimum size of your items, and when any of those items or inner elements are expected to grow in size indefinitely with things like width:100% the auto parameter will make still case 2. to run sometimes with overflown grids. To prevent this, we need to force the browser to use a method that can shrink the elements until its real minimum, which is 0px to do this you need to use minmax(0,Xfr) with X as the desired fraction.
Or in other words, for your previous case:
grid-template-columns: minmax(0,1fr) minmax(0,2fr) minmax(0,1fr);
I know this might look too verbose, but given your such edge case we cannot use repeat() here, and in any case, this will be a bulletproof for your overflowing issues.
You can read more in this article I have found:
https://css-tricks.com/preventing-a-grid-blowout/
I stumbled into this problem too, and what it worked for me was to replace grid-template-column: 50% 50%; with grid-template-column: auto 50%;.
I'm doing some testing with the css-grid spec and am encountering an issue on my first test. I wanted to create a centered grid with 3 columns and have divs inside the grid fill the width of the columns. This works but i was not expecting the 1px margin on the right see:
.wrapper {
max-width: 400px;
margin: 0 auto;
background-color: red;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
.cell {
background-color: grey;
}
<div class="wrapper">
<div class="grid">
<div class="cell">a</div>
<div class="cell">b</div>
<div class="cell">c</div>
</div>
</div>
I expect this has to do with a percentage rounding issue. If you scale the browser you see that the margin sometimes disappears.
I know i can fix this with flexbox and let the cell grow, but i'd rather know how to handle this with css-grid.
It's a math and could not be fixed. For example, if you divide 100 to 3, you will get something like 33.33333333333333..........
By the way, you could use
grid-template-columns: repeat(3, 1fr);
Instead of
grid-template-columns: 1fr, 1fr, 1fr;