CSS Grid - How to make items responsive - css

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.

Related

Equal column widths in CSS with container only as wide as children's combined width

I basically have the question as this one, except that every answer seems to think the OP wants the container .row element to grow to effectively have width: 100% (which they never state that they want, but nor have they corrected the assumption of any of the answers). This question also seems to be similar, if not the same, as mine, but has no accepted answer and the upvoted answer didn't work for me.
I'm trying to achieve sibling elements in a row where each sibling's width is the width of the widest sibling (auto-fit to its contents), but crucially where the parent row element itself does not grow to 100% of its own parent but rather grows only to the total combined width of its children.
I've tried dozens of suggestions without any success. Here's what I consider the closest I've managed:
.full-width-banner {
width: 100%;
background-color: #aaa;
padding: 5px;
margin-bottom: 5px;
}
.days-of-week {
display: grid;
grid-auto-columns: max-content;
}
.item {
padding: 2px;
border: 1px solid #ccc;
}
<div class="container">
<div class="full-width-banner">Hi there!</div>
<div class="days-of-week">
<div class="item">Monday</div>
<div class="item">Tuesday</div>
<div class="item">Wednesday</div>
<div class="item">Thurdsday</div>
<div class="item">Friday</div>
<div class="item">Saturday</div>
<div class="item">Sunday</div>
</div>
</div>
This does set all of the siblings - the days of the week - to have equal widths as required, but it stacks them rather than showing them inline. I thought adding grid-auto-flow: column; to the .days-of-week element might fix it, but whilst that does cause the days to be displayed inline, their widths revert to match their respective contents.
So, using CSS grid, how can I get the days of the week elements to all have equal widths no greater than the natural width (as prescribed by its content) of the widest element?
You need to do like below:
.full-width-banner {
background-color: #aaa;
padding: 5px;
margin-bottom: 5px;
}
.days-of-week {
display: inline-grid; /* inline grid */
grid-auto-columns: 1fr; /* all of them the same size */
grid-auto-flow:column; /* a column flow */
}
.item {
padding: 2px;
border: 1px solid #ccc;
}
<div class="container">
<div class="full-width-banner">Hi there!</div>
<div class="days-of-week">
<div class="item">Monday</div>
<div class="item">Tuesday</div>
<div class="item">Wednesday</div>
<div class="item">Thurdsday</div>
<div class="item">Friday</div>
<div class="item">Saturday</div>
<div class="item">Sunday</div>
</div>

CSS Flex Box Gallery Issue

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>

How set full screen width background on fixed width element?

I have simple structure of element container of dynamic height and fixed width (Markup below). On one hand the element's background should span the whole window width, on the other the children's size must be limited by the container (Desired layout below). The number of children and their sizes (which are equal on the image only for simplicity) are dynamic.
Is that possible without adding extra container? I want to avoid achieving the desired element content width by setting width on the children, because their number is dynamic and the size relationships become complicated to write unless their total width is already limited by container's width.
Here's a pen to experiment;
Markup
<div class="container">
<div class="child">
<div class="child">
...
</div>
.container {
width: <fixed-width>px;
}
Desired layout (the whitespace between children and container is irrelevant)
One route we can take to solve this is by using viewport width on the parent container padding, to force the children into a box that is only 500px wide (as per your codepen).
The important thing to remember when doing this is that box-sizing:border-box; will need to be set on the container, otherwise the padding goes ballistic.
We do this by using calc, vw and padding.
padding: 20px calc(50vw - /*half of container width*/);
Here's the full expanded code of your container on the linked codepen:
.container {
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin-left: auto;
margin-right: auto;
height: 300px;
width: 100%;
padding: 20px calc(50vw - 250px);
background-color: #acffac;
background-size: 100vw auto;
background-position: center top;
box-sizing: border-box;
}
html {
overflow-y:scroll; /* fixes potential calculation errors caused by scroll bar - thanks to Roberts comment */
}
Here's a working version of the codepen, and for the sake of keeping all my eggs in one basket, here's an expandable code snippet:
.container {
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin-left: auto;
margin-right: auto;
height: 300px;
width: 100%;
padding: 20px calc(50vw - 250px);
background-color: #acffac;
background-size: 100vw auto;
background-position: center top;
box-sizing: border-box;
}
.child {
flex: 1 0 auto;
width: 100px;
height: 100%;
background-color: #ff4444;
}
.child+.child {
margin-left: 20px;
}
<div class="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
I will finish off by pointing out that if someone else has a better solution, you may want to look at that for time being instead as there is some issues with using vw inside calc on older versions of Chrome and Safari.
EDIT:
As noted in the comments by Vadim and Robert there are a few things that can cause some snags.
Firstly, assuming you are working with a bare minimum template (i.e. no normalize/reset.css), your body will most probably still have the inherent margins that would mess with this kind of layout. You can fix this with:
body {
margin:0;
}
Secondly, depending on your OS (Yes I'm looking at you Microsoft!) your scrollbars can push your content to the side whilst simultaneously still being included in the calculation for vw.
We can fix this one of two way. The first being an adjustment on the padding calculation to include the scrollbar side, but you would have to write a script to ensure that scrollbar is actually present, and scrollbars differ in sizes (I.E -> 17px, Edge -> 12px).
The other alternative would be to use a custom content scroller, which would do a full overflow:hidden; over the content, thereby removing the scroll bar, before implementing it's own version of a scrollbar (which generally lies on top of the content with a position:fixed;) it.
Using vw and flex we can center the child elements and achieve exactly what you require. I have written a JSfiddle where you can check it out.
Basically what I have done is created a container with display set to flex. Using margin property of the first child element, I have centered all of the other child divs and then the regular properties were added to other divs.
Here's the code
body{
margin: 0;
padding: 0;
}
#container{
display: flex;
width: 100vw;
height: 40vw;
background-color: #333333;
align-items: center;
}
.child{
width: 4vw;
height: 80%;
background-color: red;
margin-right: 10vw;
}
.child:first-child{
margin-left: 28vw;
}
<div id="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>

Responsive layout: middle content of centered div with fixed width must become the right column without overflowing

I have a centered div with a width of 700px, with a middle part that must become a right column when viewport is > to some width. I used absolute positioning for that purpose but like this column must be responsive, I don't know its width.
First, I would like to know what is the rule for how behave the width of absolute positioned elements which are out of their relative parent. Absolute positioning should use the width of their relative parent but when the element is out of that parent, the element is shrinked. If there is a word without space, it extends the element accordingly and everything follows. I don't understand how it works and how predict that behavior. It's the same when that element without width is supposed to start overflowing out of its parent.
Then, is there a way to make this column fills the right until it reaches the limit of the window without overflowing (with a little margin-right)? If I fix a big width on that column assuming it will be the max-width that column will achieve in the biggest viewport and use the overflow property to hide what is out of the window, of course, the absolute positioned element is just cut.
I really don't know how to make that responsive because it seems like absolute positioning removes the element from the flow, it is not made for my purpose. Of course, no JS, please. And it must support Internet Explorer since IE8.
The only solution that comes to my mind is to duplicate the content and use display:none/block to switch blocks with media queries but it means redundant code. I tried with a complicated display:table layout until I found that colspan doesn't exist.
(Just so you know, I have a left column too to take into consideration, the reason why I am using a three columns display:table layout. If that's relevant.)
Here is a simplified code:
I didn't put media queries but the aside-on-small-screen is obviously what it should look like on small screens, replacing the aside selector.
main{
overflow:hidden;
}
.colMain{
background-color:green;
margin-left:auto;
margin-right:auto;
position:relative;
width:300px;
}
.aside{
background-color:red;
position:absolute;
top:0px;
left:320px;
}
.aside-on-small-screen{
background-color:red;
}
<main>
<div class="colMain">
<div>stuff</div>
<div class="aside">aside that must extend all the way to the right until it reaches the window limit</div>
<div>stuff</div>
</div>
</main>
Thank you.
Used flexbox and assigned aside a percentage width. The details are in the CSS portion of Snippet.
Flexbox
justify-content: space-between
order
flex-shrink, flex-grow, flex-basis
Relative units of measurement
Viewport width/height vw and vh
Percentage
em
/* Optional Defaults and Resets */
* {
-ms-box-sizing: border-box;
box-sizing: border-box;
}
html {
font: 400 10px/1 Arial;
width: 100%;
height: 100%;
}
/*,
*:before,
*:after {
box-sizing: inherit;
margin: 0;
padding: 0;
border: none;
}*/
body {
font: inherit;
font-size: 160%;
/* background: rgba(0, 0, 0, .2);*/
line-height: 1;
overflow: visible;
width: 100%;
height: 100%;
}
/* Demo Styles */
/* All outlines and backgrounds are for presentational purposes */
/* vw/vh viewport width/height 1vw/vh = 1% of viewport width/height */
main {
overflow: hidden;
/* width: 100vw;
height: 100vh;
background: rgba(0, 0, 255, .2);*/
width: 100%;
height: 100%;
min-height: 35em;
display: table;
}
/* Flexbox layout will automatically keep .aside to the right with the */
/* property justify-content: space-between; which keeps the max amount */
/* of even space between flex-items (which is .stuff and .aside) */
.colMain {
/* display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between; */
background-color: green;
margin-left: auto;
margin-right: auto;
position: relative;
min-width: 99%;
min-height: 99%;
padding: 1em;
display: table-row;
width: 700px;
}
/* Removed absolute positioning in favor of flexbox and a percentage */
/* width. .aside will start dis-proportionally expanding while the viewport */
/* expands. The two columns on the right while begin to shrink in response */
/* to.aside's expansion. All this stretching and shrinking happens when the */
/* elements are at 210px or more (210 is 30% of 700px). This behavior is */
/* accomplished by using flex-shrink, flex-grow, and flex-basis */
.aside {
display: table-cell;
background-color: red;
position: absolute;
top: 1em;
right: 0;
left: 70%;
/* order: 3; */
min-width: 30%;
max-width: 500px;
min-height: 100%;
/* flex-grow: 1;
flex-basis: 210px;*/
outline: 2px solid #7c1b38;
padding: 5px;
}
.aside-on-small-screen {
background-color: red;
}
.stuff {
outline: 2px dotted white;
width: 30%;
max-width: 210px;
min-height: 100%;
position: absolute;
/* flex-shrink: 1;
flex-basis: 210px; */
display: table-cell;
}
#col1 {
left: 1em;
top: 1em;
}
#col2 {
left: 36%;
top: 1em;
}
/*.stuff:first-of-type {
order: 1;
}
.stuff:last-of-type {
order: 2; */
}
/* The HTML shows that the second column (the second .stuff) would be */
/* in-between .aside and the edge of .colMain. Instead of moving it out of */
/* the way in markup (HTML), I used the flexbox property, order. */
<main>
<div class="colMain">
<div id="col1" class="stuff">stuff</div>
<div class="aside">aside that must extend all the way to the right until it reaches the window limit</div>
<div id="col2" class="stuff">stuff</div>
</div>
</main>
There are three problems in one:
First problem.
How to transform a middle content
<div class="wrapper">
<div>stuff</div>
<div class="aside">Middle content</div>
<div>stuff</div>
</div>
in a right column that expends to the right without overflowing out of the window, when the rest of the past column "wrapper" must be a centered column of fixed width.
<div class="colLeft"></div>
<div class="wrapper" style="text-align:center; width:700px;">
<div>stuff</div>
<div>stuff</div>
</div>
<div class="aside">Middle content now to the right</div>
Absolute positioning doesn't help because without fixed sizes (% or px), it is out of the flow and the content of variable width won't adapt to the situation (and overflow).
This can be easily solved with display table.
Second problem.
Display table/table-cell leads to the second problem.
To make three "columns" with display:table-cell, order is really important. That means the "aside" div must be the last element of its column (the wrapper column in my first snippet) in order to make it an independent cell of a row put to the right. If you don't have to worry about this story of middle content and you just have to switch a content at the end of a div to the right or a content at the beginning to the left, it's already over.
You just have to style colLeft, wrapper and aside of my second snippet with display:table-cell and use another global wrapper with display:table and some other styles like table-layout:fixed and width:100% to do the trick. With a media queries for small screen, you just have to hide the colLeft with display:none.
But if you need that middle content to be a middle content nonetheless on small screens and a right column on large screens, it's a different case.
This can be solved with anonymous table objects and table-header/footer/row-group.
With table-header/footer/row-group, you can reorganize your rows so you can put the "aside" at the end to transform it in an independent cell on large screens and place it in the middle with table-row-group on small screens:
.header{
background-color:green;
display:table-header-group;
}
.footer{
background-color:green;
display:table-footer-group;
}
.aside{
background-color:red;
display:table-row-group;
}
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">Middle content</div>
Third problem.
The hardest problem is the centered "column" of fixed width. With table-xxx-group, it is forbidden to put a wrapper around the table-header-group and table-footer-group to set a width of 700px because table-group are row elements and the wrapper will automatically becoming a table object, excluding the "aside" that won't be able to insert itself in the middle with its table-row-group style on small screens.
Without putting a wrapper around the "stuff", you won't be able to control the width of the created anonymous cell on large screens because you can't style something anonymous. So it takes a width of 1/3 like each cell.
main{
display:table;
table-layout: fixed;
width:100%;
}
.colLeft{
background-color:yellow;
display:table-cell;
}
.header,.footer{
background-color:green;
/*no display style > it will create an anonymous cell
object around the header/footer elements*/
}
.aside{
background-color:red;
display:table-cell;
}
<main>
<div class="colLeft"></div>
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">Middle content now to the right</div>
</main>
The solution is to use table-column-group/table-column. You will be able to style your columns and set a width to the middle column even though it is determined anonymously.
The solution
Small screens
.rowTabled{
display:table;
table-layout: fixed;
width:100%;
}
.header{
background-color:green;
display:table-header-group;
}
.footer{
background-color:green;
display:table-footer-group;
}
.aside{
background-color:red;
display:table-row-group;
}
.colLeft, .colgroup{
display:none;
}
<main>
<div class="colgroup">
<div class="colCol left"></div>
<div class="colCol middle"></div>
<div class="colCol right"></div>
</div>
<div class="rowTabled">
<div class="colLeft"></div>
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">asideeeeeeeeeeeex eeeeee eeeeeeeee eeeeeeeeeeeeee</div>
</div>
</main>
Large screens
main{
display:table;
table-layout: fixed;
width:100%;
}
.colgroup{
display:table-column-group;
}
.colCol{
display:table-column;
}
.middle{
background-color:green;
width:100px;
}
.left,.right{
background-color:yellow;
}
.rowTabled{
display:table-row;
}
.colLeft{
display:table-cell;
}
.aside{
background-color:red;
display:table-cell;
}
<main>
<div class="colgroup">
<div class="colCol left"></div>
<div class="colCol middle"></div>
<div class="colCol right"></div>
</div>
<div class="rowTabled">
<div class="colLeft"></div>
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">asideeeeeeeeeeeex eeeeee eeeeeeeee eeeeeeeeeeeeee</div>
</div>
</main>

CSS column layout with last elements' heights set equally

I have a 3-column layout which I'm trying to show you with this paint illustration.
I want the last divs of each column to take up the remaining space (blue).
The overall height of this layout is not fix, nor the number of divs.
Some of the divs will have fix dimensions, others don't.
Is there a pure CSS solution for this?
The cleanest way to achieve this is to use CSS flexible boxes:
<div class="col1"> ... </div>
<div class="col2"> ... </div>
<div class="col3"> ... </div>
CSS:
body{
display: -ms-flexbox; /* ie 10 (older but working flex implementation) */
display: -webkit-flexbox;
display: flex;
min-height: 100vh; /* optional, forces minimum height to 100% of viewport */
margin: 0;
padding:0;
}
.col1, .col3{
width: 25%;
}
.col2 {
width: 50%;
}
(demo)
The markup is simple, CSS is easy to understand, no "hacks". The only disadvantage right now is the poor browser support (IE 10+). I wouldn't consider it a big one, because you can work around this in IE 9- by using javascript.
Check out "Solved by flexbox" for other uses cases.
Another good solution that I have been using for years is the "The Perfect 3 Column Liquid Layout". The CSS is clean, but a little harder to understand and HTML is a little bulky because it requires wrapper elements for each column. If you need IE 6+ support without resorting to javascript, this is probably the 2nd best choice.
There are other ways to do this:
Table layout (display:table and related properties)
Background images on the body (for solid colors CSS gradients work too)
They are explained in this article (ignore the flex box one, because it uses the old implementation with some unnecessary 99999px margin hack).
But these introduce other limitations that can outweigh the ones from the first two methods. For example, Firefox not positioning absolute elements relative to the table cell. With backgrounds this kind of positioning is not possible at all, because the columns don't have real 100% height
Susy might do the trick for you.
It lets you easily make responsive grids in Sass which isn't vanilla css but will compile down to it. Square Market uses susy and if you take a look at their home page, linked previously and included below, they accomplish a similar effect to what your looking for.
Heres a basic example of a responsive grid so you can get a feel for how easy it is:
// Complex AG grid, brought to you by Susy:
.ag1 { #include span-columns(2,10); }
.ag2 { #include span-columns(6,10); }
.ag3 { #include span-columns(2 omega, 10); }
.ag4 { #include span-columns(3,6); }
.ag5 { #include span-columns(3 omega,6); }
.ag6 { #include span-columns(2,6); }
.ag7 { #include span-columns(4 omega,6); }
.ag8 { #include span-columns(2,4); }
.ag9 { #include span-columns(2 omega,4); }
.ag10 { clear: both; }
Like you want, you dont have to specify the overall height of a particular column and can lock the dimensions of a particular column in.
This can be achieved with a combination of CSS Grid and Flexbox:
html,
body {
height: 100%;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
border: solid 2px gray;
padding: 12px;
height: 100%;
grid-gap: 10px;
min-height: 450px;
}
.column {
display: flex;
flex-flow: column;
}
.item {
border: solid 2px orangered;
height: 100%;
margin: 5px 0;
}
.item.fixed1 {
height: 100px;
}
.item.fixed2 {
height: 380px;
}
<div class="grid">
<div class="column">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="column">
<div class="item fixed1"></div>
<div class="item"></div>
</div>
<div class="column">
<div class="item fixed2"></div>
<div class="item"></div>
</div>

Resources