Overflow-X not working in muli-column CSS grid layout - css

I have a simple grid layout with 2 columns. Inside of the grid cells overflow-x seems to not be working. Is there any way to make this layout with working overflow-x inside of the cells?
.main-grid {
display: grid;
grid-template-columns: minmax(min-content, 1fr) auto;
gap: 20px;
}
.main-grid>div {
display: flex;
flex-direction: column;
gap: 20px;
}
.main-grid>div>div {
background-color: lightpink;
}
.scroll-me {
overflow-x: auto;
}
.i-am-too-wide {
width: 800px;
}
.margin-top {
margin-top: 50px;
}
<div class="main-grid">
<div>
<div>
1
</div>
<div>
2
</div>
</div>
<div>
<div>
A
</div>
<div>
B
<div class="scroll-me">
<div class="i-am-too-wide">
Wide element inside grid
</div>
</div>
</div>
</div>
</div>
<div class="scroll-me margin-top">
<div class="i-am-too-wide">
WIDE element outside grid
</div>
</div>

Related

flex-column: how to limit the height of grow part so it does not expand?

I'm sure this kind of question was asked before, but I really can't describe it exactly and concisely enough to let the search engine to understand me. So here we go:
To better explain my question I'm writing the code in tailwind style here. A stack snippet is also attached below:
<div class="root w-screen h-screen flex flex-col">
<div class="header h-[72px] w-full bg-red shrink-0"></div>
<div class="content grow">
<!-- a whole lot of content, very tall, height > 2000 px -->
</div>
</div>
In this example, I would like to limit the height of the entire div.root to 100vh. However, because div.content is very tall, it expands the body that it shows a vertical scrollbar.
Well this is fairly easy to overcome, I only need to add scroll-y-auto to div.content. So the body scrollbar disappears, and div.content shows a vertical scrollbar. Perfect.
However later on, I decided to split div.content into two columns: both column shall have its own vertical scrollbar. Intuitively I changed the code to:
<div class="root w-screen h-screen flex flex-col">
<div class="header h-[72px] w-full bg-red shrink-0"></div>
<div class="content grow">
<div class="left overflow-y-auto">
<!-- a whole lot of content, very tall, height > 2000 px -->
</div>
<div class="right overflow-y-auto">
<!-- a whole lot of content, very tall, height > 2000 px -->
</div>
</div>
</div>
But this does not work at all, as the attached snippet demonstrates. body got its scrollbar back, but not div.left or div.right.
I've explored several ways to solve this problem. In the end the best solution I got was to set the height of div.content to calc(100% - 72px). This works perfectly, but I understand it's only because I know the exact height of div.header is fixed at 72px.
Was I doing something wrong here? What's the most elegant way to solve this kind of problem?
body {
margin: 0;
}
.root {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
height: 72px;
width: 100%;
background-color: red;
flex-shrink: 0;
}
.content {
flex-grow: 1;
display: flex;
flex-direction: row;
}
.very-tall-content {
background-color: green;
height: 2400px
}
.left, .right {
flex-grow: 1;
margin: 0 4px;
overflow-y: auto;
}
<div class="root">
<div class="header"></div>
<div class="content">
<div class="left">
<p class="very-tall-content"></p>
</div>
<div class="right">
<p class="very-tall-content"></p>
</div>
</div>
</div>
Allright, try this one maybe it fixed your problem :)
instead of using flex for .root use grid. down here we have a
header with minimum height of 72px and if it's content overloads, the
header will auto-fit them
:root {
--header-min-height: 72px;
}
body {
margin: 0;
}
.root {
display: grid;
grid-template-rows: minmax(var(--header-min-height), auto) 1fr;
height: 100vh;
}
.header {
grid-row: 1;
background: darkcyan;
}
.content {
grid-row: 2;
display: flex;
background-color: palegreen;
overflow-y: hidden;
}
.content>div {
flex-grow: 1;
overflow-y: auto;
}
.white-space {
height: 3000px;
}
<div class="root">
<div class="header"></div>
<div class="content">
<div class="left">
Left Side
<div class="white-space"></div>
Left Side
</div>
<div class="right">
Right Side
<div class="white-space"></div>
Right Side
</div>
</div>
</div>
here's the example if it overloads.
:root {
--header-min-height: 72px;
}
body {
margin: 0;
}
.root {
display: grid;
grid-template-rows: minmax(var(--header-min-height), auto) 1fr;
height: 100vh;
}
.header {
grid-row: 1;
background: darkcyan;
}
.content {
grid-row: 2;
display: flex;
background-color: palegreen;
overflow-y: hidden;
}
.content>div {
flex-grow: 1;
overflow-y: auto;
}
.white-space {
height: 3000px;
}
.row {
display: flex;
flex-direction: row;
width: fit-content;
}
.item {
background: rgba(255, 255, 255, .5);
width: fit-content;
padding: 10px;
margin: 5px;
border-radius: 5px;
}
<div class="root">
<div class="header">
<div class="row">
<div class="item">test</div>
<div class="item">test</div>
<div class="item">test</div>
</div>
<div class="row">
<div class="item">test</div>
<div class="item">test</div>
<div class="item">test</div>
</div>
<div class="row">
<div class="item">test</div>
<div class="item">test</div>
<div class="item">test</div>
</div>
</div>
<div class="content">
<div class="left">
Left Side
<div class="white-space"></div>
Left Side
</div>
<div class="right">
Right Side
<div class="white-space"></div>
Right Side
</div>
</div>
</div>

How to vertically center align the bottom of a horizontal list of items of varying heights

I'm trying to achieve the following layout without using absolute positioning
The reason is that I would like to use css grid or flexbox as much as possible and try to avoid taking thins out of the flow if at all possible. In this case the surrounding div has a padding which should be respected, if it comes to that, and instead it should increase it's height if necessary. Usually I use max-content with css grid to achieve this.
If it was only the text it would have been as easy as align-items: center; however, because of the images/badges, the text will not properly align in the center if I do this.
https://stackblitz.com/edit/react-ts-t4h6ff?file=style.css
.list {
width : 100%;
background : red;
display : flex;
flex-direction : row;
align-items : center;
}
.list-item {
background : yellow;
display : grid;
grid-template-rows : max-content max-content;
padding : 1rem;
}
<div class="list">
<div class="list-item">list item 1</div>
<div class="list-item">
<div>image</div>
<div>list item 2</div>
</div>
<div class="list-item">
<div>image</div>
<div>list item 3</div>
</div>
</div>
Basically https://stackblitz.com/edit/react-ts-4xy14d?file=style.css is what I want to achieve, but without position absolute or transform translate.
Ended up with: https://stackblitz.com/edit/react-ts-78pckz?file=style.css
html,
body,
#root,
.wrapper {
height: 100%;
width: 100%;
}
.wrapper {
display: grid;
grid-template-rows: minmax(5rem, 50%) auto;
background: purple;
}
.list {
width: 100%;
background: red;
display: flex;
flex-direction: row;
height: 100%;
}
.list-item {
background: yellow;
display: grid;
grid-template-rows: 1fr max-content 1fr;
padding: 1rem;
box-sizing: border-box;
height: 100%;
overflow: hidden;
}
.image-wrapper {
position: relative;
}
.image {
max-width: 100%;
max-height: 100%;
position: absolute;
bottom: 0;
right: 0;
}
.text {
align-self: center;
white-space: nowrap;
}
<div class="wrapper">
<div class="list">
<div class="list-item">
<div> </div>
<div class="text">list item 1</div>
<div> </div>
</div>
<div class="list-item">
<div class="image-wrapper">
<img class="image" src="https://via.placeholder.com/100" />
</div>
<div class="text">list item 2</div>
<div> </div>
</div>
<div class="list-item">
<div class="image-wrapper">
<img class="image" src="https://via.placeholder.com/150" />
</div>
<div class="text">list item 3</div>
<div> </div>
</div>
</div>
<div>... :-)</div>
</div>
I don't think it's the most elegant solution, but here's how I would solve the problem (assuming your diagram is saying that the size of the images are going to be consistent).
Edit: Didn't quite get there with my answers, but it did help Dac0d3r come up with this final solution. Source from him is in the comments.
html,
body,
#root,
.wrapper {
height : 100%;
width : 100%;
}
.wrapper {
display : grid;
grid-template-rows : minmax(5rem, 50%) auto;
background : purple;
}
.list {
width : 100%;
background : red;
display : flex;
flex-direction : row;
height : 100%;
}
.list-item {
background : yellow;
display : grid;
grid-template-rows : 50% 50%;
padding : 1rem;
box-sizing : border-box;
height : 100%;
}
.image {
max-width : 100%;
max-height : 100%;
align-self : end;
}
<div class="wrapper">
<div class="list">
<div class="list-item">
<div></div>
<div class="text">list item 1</div>
</div>
<div class="list-item">
<img class="image" src="https://via.placeholder.com/100" />
<div class="text">list item 2</div>
</div>
<div class="list-item">
<img class="image" src="https://via.placeholder.com/150" />
<div class="text">list item 3</div>
</div>
</div>
</div>

Responsive centering of divs

How do I go from here
To here
I'm trying to center the inner div's to their parent except for the last row where I'd like to align it left to the row above it.
Here is the jsfiddle for the top image https://jsfiddle.net/L15p2nev
.container {
text-align: center;
background-color: green;
}
.item {
display: inline-block;
width: 300px;
background-color: red;
}
<div class="container">
<div class="item">
item
</div>
<div class="item">
item
</div>
<div class="item">
item
</div>
</div>
Using grid display layout, this can be archived.
You can set grid-template-columns: repeat(auto-fit, 300px) to align items as the image.
.container {
background-color: green;
display: grid;
grid-template-columns: repeat(auto-fit, 300px);
justify-content: center;
grid-column-gap: 10px;
grid-row-gap: 10px;
}
.item {
display: inline-block;
background-color: red;
}
<div class="container">
<div class="item">
item
</div>
<div class="item">
item
</div>
<div class="item">
item
</div>
</div>

Shrink grid items just like flex items in css

Is it possible to shrink grid items just like flex items in css?
Grid items
.container {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.child {
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
padding: 5px;
border: 3px solid #a07;
}
<div class="container">
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
</div>
jsfiddle
Flex items
.container {
display: flex;
margin-left: -10px;
flex-flow: row wrap;
}
.child {
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
padding: 5px;
border: 3px solid #a07;
flex: 200px 1 1;
margin-left: 10px;
margin-bottom: 10px;
}
<div class="container">
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
</div>
jsfiddle
In a nutshell I can have the following positioning of the elements with the flex above:
While I can not achieve the same behaviour by using a grid layout. Flex layout allows items to shrink on small screen, while grid layout does not allow. At the same time I would like to preserve the behavior that the item will move to the next line with another item only when after such a placement each one of them will be no shorter than a specific size (200px in our case).
I am using grid layout because it allows to preserve the invariant that widths of all the children will be the same. With flex layout the last item will be stretched to the whole line if it will be alone on the line.
New solution
An optimized version of the initial solution using min()
.container {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(min(200px,100%), 1fr));
}
.child {
display: flex;
align-items: center;
justify-content: center;
padding: 5px;
border: 3px solid #a07;
}
body {
margin:0;
}
<div class="container">
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
</div>
Old solution
One solution is to specify a max-width to the child element relying on the viewport unit since percentage values are relative to the size of the track defined by the minmax() and cannot be used. This solution isn't generic and you need to adjust the value depending on each situation.
In you case for example, we can use 100vw since the container is the only element in the body and is taking the whole width:
.container {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.child {
display: flex;
align-items: center;
justify-content: center;
padding: 5px;
border: 3px solid #a07;
max-width:100vw;
box-sizing:border-box; /* Don't forget this !*/
}
body {
margin:0;
}
<div class="container">
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
</div>
In case there is more element or some padding/margin you need to consider them within the max-width calculation:
.container {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.child {
display: flex;
align-items: center;
justify-content: center;
padding: 5px;
border: 3px solid #a07;
max-width:calc(100vw - 40px); /*we remove the body margin*/
box-sizing:border-box;
}
body {
margin:0 20px;
}
<div class="container">
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
</div>
It's like we no more have 2 constraints but 3:
The grid cell has a minimum size of 200px
The grid cell fill the remain space
The element inside the grid cell has a maximum size defined relatively to the screen size. (the shrink constraint we were missing)

Why are two of my boxes at different heights when using the same css class?

I can't see why my flexboxes are not all obeying the same padding-bottom rule. Only one class is applying the height through padding-bottom.
.col-t {
width: 100%
}
.col-s {
width: 50%
}
main#container .grid .grid-container {
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
flex-flow: row wrap;
}
main#container .grid .grid-container .box {
-webkit-flex: 1 auto;
flex: 1 auto;
position: relative;
}
main#container .grid .grid-container .box>div {
padding-bottom: 56.66666%;
}
.r {
background: red;
}
.b {
background: blue
}
.p {
background: purple
}
<main id="container">
<section class="grid">
<div class="col-s grid-container">
<div class="col-t box">
<div class="r">
</div>
</div>
<div class="col-s box">
<div class="b">
</div>
</div>
<div class="col-s box">
<div class="p">
</div>
</div>
</div>
</section>
</main>
Is it because the height through padding-top and bottom is relative to the width? But if this is the case, how would it be possible to make all of the boxes the same height using percentages?
Is it because the height through padding-top and bottom is relative to
the width?
Yes
But if this is the case, how would it be possible to make all of the
boxes the same height using percentages?
Since the col-s box element is only half the width of the col-t box, you need to double its childrens padding's percent, padding-bottom: calc(2 * 56.66666%); to make them have the same height as the col-t box's child has.
Stack snippet
.col-t {
width: 100%
}
.col-s {
width: 50%
}
main#container .grid .grid-container {
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
flex-flow: row wrap;
}
main#container .grid .grid-container .box {
-webkit-flex: 1 auto;
flex: 1 auto;
position: relative;
}
main#container .grid .grid-container .box>div {
padding-bottom: 56.66666%;
}
main#container .grid .grid-container .col-s.box>div {
padding-bottom: calc(2 * 56.66666%); /* added */
}
.r {
background: red;
}
.b {
background: blue
}
.p {
background: purple
}
<main id="container">
<section class="grid">
<div class="col-s grid-container">
<div class="col-t box">
<div class="r">
</div>
</div>
<div class="col-s box">
<div class="b">
</div>
</div>
<div class="col-s box">
<div class="p">
</div>
</div>
</div>
</section>
</main>

Resources