Here's a codepen illustrating the issue: https://codepen.io/robertcooper_rc/pen/jOYbdbR
I'm using a CSS grid to create a table layout. It's been working well, but I'm having an issue with the behavior of position: sticky on one of the columns in my grid.
I have a horizontally scrollable table with 4 columns and the first column is sticky.
When I scroll to the right, the first column does stick to the left as is expected.
However, when scrolling starts nearing the end of the table's horizontal space, the first no longer maintains its sticky position to the left edge of the table.
I've noticed that if I remove the HTML markup for the <aside>, the sticky column behavior works as expected. However, I need the <aside> to be present.
Any ideas on how to fix this with CSS while maintaining the DOM structure?
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.container {
display: flex;
width: 300px;
padding: 0.5rem;
border: 1px solid red;
}
aside {
padding-right: 1rem;
width: 100px;
}
.table {
min-width: 0;
overflow: scroll;
}
.row {
display: grid;
grid-template-columns: repeat(4, 100px);
}
.col {
border: 1px solid black;
background: #eee;
}
.sticky {
position: sticky;
left: 0;
z-index: 1;
background: lightblue;
}
<div class="container">
<aside>
My aside
</aside>
<div class="table">
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
</div>
</div>
So the problem actually falls with the min-width set on .table. The width is not defined to the end of the row which is affecting the behavior of the sticky elements at row-end.
You'll notice if you exchange min-width: 0; to min-width: 100%; it functions as you would like, but then the table overflows outside of .container.
A stickily positioned element is treated as relatively positioned until its containing block crosses a specified threshold (such as setting top to value other than auto) within its flow root.
MDN CSS/Position
So with that said, the elements with the scroll need to have a defined width so the sticky element knows to stay sticky.
A simple solution would be to nest all of the .table elements in another wrapper that has a defined width. I chose 300px based on the rendered width of the content and the container.
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.container {
display: flex;
width: 300px;
padding: 0.5rem;
border: 1px solid red;
}
aside {
padding-right: 1rem;
width: 100px;
}
.table {
min-width: 0;
overflow: scroll;
}
.row {
display: grid;
grid-template-columns: repeat(4, 100px);
}
.col {
border: 1px solid black;
background: #eee;
}
.sticky {
position: sticky;
left: 0;
z-index: 1;
background: lightblue;
}
.wrapper {
width: 300px;
}
<div class="container">
<aside>
My aside
</aside>
<div class="table">
<div class="wrapper">
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
<div class="row">
<div class="col sticky">Col 1</div>
<div class="col">Col 2</div>
<div class="col">Col 3</div>
<div class="col">Col 4</div>
</div>
</div>
</div>
</div>
Related
In this example http://jsfiddle.net/rodrigolinkweb/k8qg14xL/ I need to select only "Container 12", how can I do this?
ps: note that both divs have the same class name "wrapper".
.container:nth-child(n+3){
background-color: gray;
color:white;
}
<div class="wrapper">
<div class="container">Container 1</div>
<div class="container">Container 2</div>
<div class="container">Container 3</div>
</div>
<br />
<div class="wrapper">
<div class="container">Container 11</div>
<div class="container">Container 12</div>
<div class="container">Container 13</div>
</div>
You can select them with the .wrapper class, like this
.wrapper:nth-of-type(2) .container:nth-child(2){
background-color: gray;
color:white;
}
<div class="wrapper">
<div class="container">Container 1</div>
<div class="container">Container 2</div>
<div class="container">Container 3</div>
</div>
<br />
<div class="wrapper">
<div class="container">Container 11</div>
<div class="container">Container 12</div>
<div class="container">Container 13</div>
</div>
If you want to select it from backwards you can use :nth-last-of-type() . Refer to the following fiddle here
No matter what content the .wrapper has :nth-child will select child based on its position where as :nth-of-type selects with appropriate attribute.
.wrapper:nth-of-type(2) .container:nth-child(2){
background-color: gray;
color:white;
}
<div class="wrapper">
<div class="container">Container 1</div>
<div class="container">Container 2</div>
<div class="container">Container 3</div>
</div>
<br />
<div class="wrapper">
Some link
<div class="container">Container 12</div>
<div class="container">Container 13</div>
</div>
Question regarding styling. I have a row of div elements. They're all the same size except one, which is double in height and width. I'd like the second row of div elements to line up with the second half of the bigger div but now sure how to do it.
.wrapper {
width: 800px;
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.box {
height: 50px;
width: 50px;
margin: 5px;
border: 1px solid black;
}
.box-5 {
height: 100px;
width: 100px
}
<div class="wrapper">
<div class="box box-1">Box 1</div>
<div class="box box-2">Box 2</div>
<div class="box box-3">Box 3</div>
<div class="box box-4">Box 4</div>
<div class="box box-5">Box 5</div>
<div class="box box-6">Box 6</div>
<div class="box box-7">Box 7</div>
<div class="box box-8">Box 8</div>
<div class="box box-9">Box 9</div>
<div class="box box-10">Box 10</div>
<div class="box box-11">Box 11</div>
<div class="box box-12">Box 12</div>
<div class="box box-13">Box 13</div>
<div class="box box-14">Box 14</div>
<div class="box box-15">Box 15</div>
<div class="box box-16">Box 16</div>
<div class="box box-17">Box 17</div>
<div class="box box-18">Box 18</div>
<div class="box box-19">Box 19</div>
</div>
I'd like box 13 - 16 to be on the left side of the bottom half of box 5 and box 17 - 19 to be on the right side.
You could use CSS display: grid and its companion grid-template-columns to fix this. Updated answer thanks to Maaz Syed Adeeb's comment.
grid-template-columns: repeat(13, auto);
(It should be thirteen instead of 12 boxes).
Only box number 5 gets an upgrade in styling to expand its box:
grid-column: span 2;
grid-row: span 2;
Read more about grid at MDN.
Updated snippet:
.wrapper {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: repeat(13, auto);
grid-template-rows: auto;
grid-gap: 0;
}
.box {
height: 50px;
width: 50px;
margin: 5px;
border: 1px solid black;
}
.box-5 {
height: 100px;
width: 100px;
grid-column: span 2;
grid-row: span 2;
}
<div class="wrapper">
<div class="box box-1">Box 1</div>
<div class="box box-2">Box 2</div>
<div class="box box-3">Box 3</div>
<div class="box box-4">Box 4</div>
<div class="box box-5">Box 5</div>
<div class="box box-6">Box 6</div>
<div class="box box-7">Box 7</div>
<div class="box box-8">Box 8</div>
<div class="box box-9">Box 9</div>
<div class="box box-10">Box 10</div>
<div class="box box-11">Box 11</div>
<div class="box box-12">Box 12</div>
<div class="box box-13">Box 13</div>
<div class="box box-14">Box 14</div>
<div class="box box-15">Box 15</div>
<div class="box box-16">Box 16</div>
<div class="box box-17">Box 17</div>
<div class="box box-18">Box 18</div>
<div class="box box-19">Box 19</div>
</div>
Just need to add 10 more pixel in width
.box-5 {
height: 100px;
width: 110px;
}
.wrapper{
width: 800px;
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.box{
height: 50px;
width: 50px;
margin: 5px;
border: 1px solid black;
}
.box-5 {
height: 100px;
width: 110px;
}
<div class="wrapper">
<div class="box box-1">Box 1</div>
<div class="box box-2">Box 2</div>
<div class="box box-3">Box 3</div>
<div class="box box-4">Box 4</div>
<div class="box box-5">Box 5</div>
<div class="box box-6">Box 6</div>
<div class="box box-7">Box 7</div>
<div class="box box-8">Box 8</div>
<div class="box box-9">Box 9</div>
<div class="box box-10">Box 10</div>
<div class="box box-11">Box 11</div>
<div class="box box-12">Box 12</div>
<div class="box box-13">Box 13</div>
<div class="box box-14">Box 14</div>
<div class="box box-15">Box 15</div>
<div class="box box-16">Box 16</div>
<div class="box box-17">Box 17</div>
<div class="box box-18">Box 18</div>
<div class="box box-19">Box 19</div>
</div>
I have three nested grids each containing rows where the content height is dynamic.
When a new row begins, I would like it to align with rows from the other nested grids.
It is not important the row numbers match up. It is also not important that nested grids are used and the markup can be changed. I ended up thinking this was the best way to solve the problem.
Desired outcome:
Here is a Codepen
.grid,
.sub-grid {
display: grid;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.sub-grid {
align-content: flex-start;
grid-auto-rows: minmax(30px, auto);
}
.row {
border-bottom: 1px solid #000;
}
<div class="grid">
<div class="sub-grid">
<div class="row">Row 1</div>
<div class="row">Row 2</div>
</div>
<div class="sub-grid">
<div class="row">Row 1</div>
<div class="row">Row 2</div>
<div class="row">Row 3</div>
<div class="row">Row 4</div>
<div class="row">Row 5</div>
<div class="row">Row 6</div>
</div>
<div class="sub-grid">
<div class="row">
Row 1 contents is longer<br />
But the next<br />
row should begin<br />
inline with another row<br />
</div>
<div class="row">
Row 2<br />
I should align with another row
</div>
<div class="row">Row 3</div>
<div class="row">Row 4</div>
<div class="row">Row 5</div>
</div>
</div>
Here is some of my CSS code which I am using to create shadow boxes inside the grid view. I tried to find HTML something like rowspan and colspan but I did't got any idea.
.box{
width: 100%;
height: 240px;
background: white;
border-color: black;
border-width: 2px;
-webkit-box-shadow: -1px 2px 5px 1px rgba(10,0,10,1);
-moz-box-shadow: -1px 2px 5px 1px rgba(10,0,10,1);
box-shadow: -1px 2px 5px 1px rgba(10,0,10,1);
};
You can create columns with Bootstrap Grid system. You can try following structural.
<div class="container">
<div class="row">
<div class="col-sm-8">
<div class="box h-100">Box 1</div>
</div>
<div class="col-sm-4">
<div class="box mb-3">Box 2</div>
<div class="box mb-3">Box 3</div>
<div class="box mb-3">Box 4</div>
<div class="box">Box 5</div>
</div>
</div>
<div class="row my-3">
<div class="col-sm-4">
<div class="box">Box 6</div>
</div>
<div class="col-sm-4">
<div class="box">Box 7</div>
</div>
<div class="col-sm-4">
<div class="box">Box 8</div>
</div>
</div>
<div class="row my-3">
<div class="col-sm-4">
<div class="box">Box 9</div>
</div>
<div class="col-sm-4">
<div class="box">Box 10</div>
</div>
<div class="col-sm-4">
<div class="box">Box 11</div>
</div>
</div>
</div>
I'm trying to implement layout where on desktop screen size we have 2 columns, and one column on mobile/tablets
is it possible to make this code:
<div class="posts-2-col">
<div class="post">Post 1</div>
<div class="post">Post 2</div>
<div class="post">Post 3</div>
<div class="post">Post 4</div>
<div class="post">Post 5</div>
<div class="post">Post 6</div>
</div>
to render like this:
(knowing that height of each post can e different)
I just put the fixed height to image a higher post
Jsfiddle
*{
box-sizing: border-box;
}
.posts-2-col{
width: 300px;
margin: 0 -10px;
}
.posts-2-col .post{
border: 1px solid red;
width: 135px;
margin: 0 5px;
margin-bottom: 10px;
float: left;
}
<div class="posts-2-col">
<div class="post">Post 1</div>
<div class="post">Post 2</div>
<div class="post" style="height: 50px">Post 3</div>
<div class="post">Post 4</div>
<div class="post">Post 5</div>
<div class="post">Post 6</div>
<div class="post">Post 7</div>
</div>