I'm creating a 3-column grid.
Each cell uses clamp(Xem, 33.33%, Xem) so there is a min size for big screens as well as a max size for small screens. If the screen is too small, the idea is that the grid's container will support that by becoming horizontally scrollable.
The page itself has left and right margins of 1em. To make the experience nice, the horizontally scrollable grid container uses negative margins and equal padding on the left and right so that it feels that the entirety of the width of the screen is visible and scrollable.
See the demo below where I've simulated the grid's behaviour in different screen sizes by manipulating the min and max of the clamp. You can see in the big size and perfect size screens it works nicely. The padding on both sides is visible.
However, for small screens, when it becomes scrollable, you scroll to the right and the right side padding is not there. This seems to be because the grid div itself is not stretching to accomodate its children, and so its parent's padding isn't "reaching" the right side (yet somehow, the grid's horizontal scroll container is aware that its content stretches - not sure how that works but that's a different topic I think).
The grid div is outlined in red. You can inspect it, along with the horizontal container, and see that the right padding ends halfway through the grid horizontally rather than at the end of the grid where one would expect it to be.
.background {
background-color:#f003;
overflow: hidden;
display: flex;
justify-content: center;
}
.scrollcontainer {
background-color:#ff03;
width: 300px;
height: 400px;
padding-left: 1em;
overflow: scroll;
padding-right: 1em;
}
.scrollGrid {
margin-left: -1em;
margin-right: -1em;
padding-left: 1em;
padding-right: 1em;
width: 100%;
background-color: #00f3;
overflow-y: scroll
}
.grid {
display:grid;
width: fit-content;
min-width: 100%;
background-color: #f0f3;
outline: 1px solid red;
}
.grid.perfect {
grid-template-columns: repeat(3, clamp(2em, 33.33%, 30em));
}
.grid.small {
grid-template-columns: repeat(3, clamp(9em, 33.33%, 10em));
font-size: 1.5em;
}
.grid.big {
font-size: 0.5em;
grid-template-columns: repeat(3, clamp(2em, 33.33%, 5em));
}
.grid > div {
height: 50px;
border: 1px solid black;
padding: 1em;
}
<div class="background">
Background
<div class="scrollcontainer">
<h2>Scrollable section of stuff here</h2>
<p>simulated perfect screen</p>
<div class="scrollGrid">
<div class="grid perfect">
<div>Cell 1</div>
<div>Cell 2</div>
<div>Cell 3</div>
</div>
</div>
<p>simulated small screen (this is where the problem is, scroll hroizontally and notice there is no padding on the right side, the grid container ends where the blue ends)</p>
<div class="scrollGrid">
<div class="grid small">
<div>Cell 1</div>
<div>Cell 2</div>
<div>Cell 3</div>
</div>
</div>
<p>simulated big screen (works as desired)</p>
<div class="scrollGrid">
<div class="grid big">
<div>Cell 1</div>
<div>Cell 2</div>
<div>Cell 3</div>
</div>
</div>
<p>more text to show that this is scrollable</p>
</div>
</div>
Thank you to anyone who sheds light on this.
Using minmax instead of clamp fixed the issue for me. Not sure why. minmax(2em, min(33.33%, 30em)). The problem also still seems to happen when using minmax(max(2em, 33.33%, 30em)), so I'm not sure why it only works for the former.
.background {
background-color:#f003;
overflow: hidden;
display: flex;
justify-content: center;
}
.scrollcontainer {
background-color:#ff03;
width: 300px;
height: 400px;
padding-left: 1em;
overflow: scroll;
padding-right: 1em;
}
.scrollGrid {
margin-left: -1em;
margin-right: -1em;
padding-left: 1em;
padding-right: 1em;
width: 100%;
background-color: #00f3;
overflow-y: scroll
}
.grid {
display:grid;
width: fit-content;
min-width: 100%;
background-color: #f0f3;
outline: 1px solid red;
}
.grid.perfect {
grid-template-columns: repeat(3, minmax(2em, min(33.33%, 30em)));
}
.grid.small {
grid-template-columns: repeat(3, minmax(9em, min(33.33%, 10em)));
font-size: 1.5em;
}
.grid.big {
font-size: 0.5em;
grid-template-columns: repeat(3, clamp(2em, 33.33%, 5em));
}
.grid > div {
height: 50px;
border: 1px solid black;
padding: 1em;
}
<div class="background">
Background
<div class="scrollcontainer">
<h2>Scrollable section of stuff here</h2>
<p>simulated perfect screen</p>
<div class="scrollGrid">
<div class="grid perfect">
<div>Cell 1</div>
<div>Cell 2</div>
<div>Cell 3</div>
</div>
</div>
<p>simulated small screen (this is where the problem was, not scrolling to the side reveals the grid element stretched all the way to the end and the appropriate padding)</p>
<div class="scrollGrid">
<div class="grid small">
<div>Cell 1</div>
<div>Cell 2</div>
<div>Cell 3</div>
</div>
</div>
<p>simulated big screen (works as desired)</p>
<div class="scrollGrid">
<div class="grid big">
<div>Cell 1</div>
<div>Cell 2</div>
<div>Cell 3</div>
</div>
</div>
<p>more text to show that this is scrollable</p>
</div>
</div>
Related
im trying to make navbar using flexbox for learning purposes, and i want to hide all elements that are being wrapped to the second row. I achievied that by overflow: hidden and flex-wrap: wrap
But the main problem now, is that when items are being moved to new row, the first one is moving higher to allow centering them both in container.
I want to keep only my first row centered, and second one to go with a flow. (I mean i will use gap or margin-top to move it away from my first row, and even parent container, but the drawing is simplified.)
I achieved what i drawed with:
position: relative;
left:0;
top:50%;
transform: translateY(-25%);
but it doesnt seem to be responsive and ideal solution, because what if the third row will appear. I wonder if there is a better way to do it without media queries.
You most likely have a align-content: center rule on the flexbox;
if you set it to align-content: start it should act like how you've described.
.example {
display: flex;
flex-wrap: wrap;
align-content: start;
/*padding vertical alignment */
padding: 20px;
overflow: hidden;
/* no actual height, will grow to largest content*/
/*max-height for cut off */
max-height: 70px;
/* additional styles */
border: 5px solid #333;
border-radius: 4px;
margin: 20px;
}
.large {
max-width: 400px;
}
.small {
max-width: 200px;
}
.item {
border: 5px solid #a349a4;
border-radius: 4px;
min-height: 40px;
min-width: 150px;
margin: 2px 20px;
/* use align-self: start to stop stretching */
align-self: auto;
}
.two {
min-height: 50px;
}
.solution-2 .item{
margin: auto 20px;
}
solution 1: align-content: start, children will stretch to equal size
<div class="solution-1">
<div class="example large">
<div class="item one"></div>
<div class="item two"></div>
</div>
<div class="example small">
<div class="item one"></div>
<div class="item two"></div>
</div>
</div>
solution 2: align-content: start, item with auto margin, will self-verrtical center.
<div class="solution-2">
<div class="example large">
<div class="item one"></div>
<div class="item two"></div>
</div>
<div class="example small">
<div class="item one"></div>
<div class="item two"></div>
</div>
</div>
Here is a codepen.
Here is code:
HTML
<div class="body">
<div class="page">
<div class="regular-flow">
</div>
<div class="regular-flow">
</div>
<div class="regular-flow">
</div>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
<div class="item">11</div>
<div class="item">12</div>
<div class="item">13</div>
<div class="item">14</div>
<div class="item">15</div>
<div class="item">16</div>
</div>
<div class="regular-flow">
</div>
<div class="regular-flow">
</div>
</div>
</div>
CSS
.body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: grey;
}
.page {
height: 100vh;
width: 100%;
background-color: lightgrey;
overflow: hidden;
}
.regular-flow {
height: 20px;
background-color: limegreen;
margin: 10px 24px;
}
.container {
width: 100%;
height: 25%;
padding-left: 24px;
padding-right: 24px;
background-color: orangered;
display: flex;
gap: 16px;
overflow-x: scroll;
-ms-overflow-style: none;
scrollbar-width: none;
}
.container::-webkit-scrollbar {
display: none;
}
.item {
height: 100%;
width: 121px;
color: yellow;
background-color: blue;
flex-shrink: 0;
}
We have several "regular flow" items (green) that keep their own margin consistently down the page (grey). However, I'd like to have a horizontal scrolling div (blue and orangered) that disrespects these boundaries, allowing items to seemingly pass from "edge" to "edge" of the screen. My thought was to overflowX: 'scroll' a 100% width div and put padding on the left and right equal to the margin being set by the other items. This way, on the "edges" of the scrollable content, it appears to still respect the margin set by the other regularly flowing items. However, no matter what I try or how many items you put into this container, it will always scroll right only to the right edge of the last item. It will not show the last bit of right padding.
Things to keep in mind about the codepen
You have to have enough items for it to need to scroll horizontally, obviously.
I am hiding the scrollbar, so hover over the blue/orange container and shift+scrollwheel to move the items. I know this isn't great UX.
Most Basic Question
Why can you not scroll right far enough such that the padding-right (orangered) is visible?
Update
I was able to come up with a workaround for this issue, and that is to go into the parent component (in my codepen, this would be .container and remove the padding-right and padding-left at that level, but then add:
.container & .div:first-child {
padding-left: 24,
}
.container & .div:last-child {
padding-right: 24,
}
This seems to accomplish the same goals, but only if you do NOT have any background color to the .item. For my purposes, this works. I only added a background color here for visualizing the issue. I would still be curious if anyone can tell me what the problem above was, so I will keep this question up and not edit the codepen. Thanks!
Here's my code:
.media {
display: grid;
box-sizing: border-box;
padding: 10rem;
border: 1px solid red;
grid-template-columns: repeat(auto-fit, minmax(50rem, 1fr));
}
.big-pic {
width: 100%;
height: 10rem;
border: 1px solid blue;
}
.small-pic {
display: inline-block;
margin-right: -.5rem;
width: 50%;
height: 10rem;
border: 1px solid blue;
}
<div class="media">
<div class="column">
<h2>On TV</h2>
<div class="big-pic">
Main Pic
</div>
<div class="small-pic">
Pic 1
</div>
<div class="small-pic">
Pic 2
</div>
</div>
<div class="column">
<h2>In Theaters </h2>
<div class="small-pic">
Pic 1
</div>
<div class="small-pic">
Pic 2
</div>
<div class="big-pic">
Main Pic
</div>
</div>
When you lower the screen size of the browser, the child elements will overflow out of the container. Why is not the column (a wrapper <div> with a class of column) width not filling the parent's width?
I used grid-template-columns: repeat(auto-fit, minmax(50rem, 1fr)); So 1fr should fill up the parent's width. When you add the padding, it overflows. Without the padding, it fills up the parent's width. Not sure what's happening.
Adding box-sizing: border-box doesn't fix the issue either. Any ideas on how to fix it?
My qeustion is that How do I make two divs tag that they function as column?
Another question is how do I make the div element to use only 60% of the page width and center the div within the page?
Is it like div{ margin:auto;width:60%;}?
The easiest way to set up a column layout is to simply have parent containers that have a width as a percentage. If you want two columns, you would have width: 50%, for example. If you are unsure of the percentage value you need, you can calculate this by dividing 100% by the desired number of columns with calc():
width: calc(100% / 3); -- 3 columns (33.33%)
As for setting an element that's centralised with a 60% width, all you need to do is set:
margin: 0 auto;
width: 60%;
Both of these can be seen in the following:
.container {
display: flex;
background: green;
margin: 0 auto;
width: 60%;
}
.parent {
width: 50%;
border: 1px solid #626262;
padding: 10px;
}
.child {
background: cyan;
margin: 20px;
height: 50px;
line-height: 50px;
text-align: center;
}
<div class="container">
<div class="parent left-column">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
</div>
<div class="parent right-column">
<div class="child">Child 3</div>
<div class="child">Child 4</div>
</div>
</div>
I'm trying to make this layout (I've made a picture to explain what i want to do):
So I've 4 divs where I'm going to put some text inside. I've used flexbox and justify content to align them center, but i want to put a text "Latest News" that is aligned with the first div (in this case Element 1).
I'm not able to think about an elegant solution to my problem, so I'm here to ask for help.
.wrapper{
display: flex;
justify-content: center;
}
.box{
height: 200px;
background-color: red;
margin: 10px;
width: 200px;
}
<p class="section-title">Latest News</p>
<div class="wrapper">
<div class="box">Element 1</div>
<div class="box">Element 2</div>
<div class="box">Element 3</div>
<div class="box">Element 4</div>
</div>
There are a few ways you can do it, and it depends how dynamic your box elements are going to be.
One simple solution that works for n boxes is to include the section title to the first box and give it position: absolute whilst adding margin-top to the wrapper to make space for the title.
https://codepen.io/anon/pen/MJpOrM
.wrapper {
display: flex;
justify-content: center;
margin-top: 40px;
}
.box {
height: 200px;
background-color: red;
margin: 10px;
width: 300px;
}
.section-title {
position: absolute;
top: 0px;
}
<div class="wrapper">
<div class="box">
<p class="section-title">Latest News</p>
Element 1
</div>
<div class="box">Element 2</div>
<div class="box">Element 3</div>
<div class="box">Element 4</div>
</div>
Considering that you have a fixed width for your boxes, the easiest solution is to make the section-title a fixed width too:
.section-title {
width: 1260px; //This is merely 300 * 4 + the margin
margin: auto;
}
https://codepen.io/anon/pen/BpWmJV