CSS3 grid layouts: New row after specific element - possible? - css

I've got a list of items, sorted by date.
Some of the items are in the future (green items), thus more interesting, some are in the past (brown items). I want the second group of items to start in a new row.
.grid{
width: 120px;
display:grid;
grid-template-columns: repeat(3,1fr);
grid-gap: 10px;
}
.item{
border:1px solid black;
height:50px;
width:50px;
}
.green{
background:green;
}
.brown{
background:brown;
}
<div class="grid">
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
</div>
The number of overall items / items per category is constantly changing, the number of Items per row depends on screen size - that might eliminate some possible solutions to this.
I could of course split the array containing all items at a certain point and organize the output into two separate grids, like so:
.grid{
width: 120px;
display:grid;
grid-template-columns: repeat(3,1fr);
grid-gap: 10px;
margin-bottom:10px;
}
.item{
border:1px solid black;
height:50px;
width:50px;
}
.green{
background:green;
}
.brown{
background:brown;
}
<div class="grid">
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
</div>
<div class="grid">
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
</div>
Probably that's the easiest option. Looks like what I want to achieve & isn't too difficult to do. But anyway, I'm curious: Is there a more elegant approach to this? I was thinking something like:
.item.green + .item.brown:before {
/* force new row */
}

You could target the first .brown after .green and set grid-column-start to 1.
.grid {
width: 120px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
}
.item {
border: 1px solid black;
height: 50px;
width: 50px;
}
.green {
background: green;
}
.brown {
background: brown;
}
.green + .brown {
grid-column-start: 1;
}
<div class="grid">
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
</div>

Since you are using grid-template-columns, you won't be able to acheive this with before or after, you would need to set the grid-column-start to 1 with the item.green + .item.brown selection:
.grid{
width: 120px;
display:grid;
grid-template-columns: repeat(3,1fr);
grid-gap: 10px;
}
.item{
border:1px solid black;
height:50px;
width:50px;
}
.green{
background:green;
}
.brown{
background:brown;
}
.item.green + .item.brown {
grid-column-start: 1;
}
<div class="grid">
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item green"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
<div class="item brown"></div>
</div>

The approach that I came up with is definitely the longest one, but if for what ever reason you need to have a modular design I think this way would save you time in the end. Added grid-areas and added individual class for all your tiles.
.grid{
width: 120px;
display:grid;
grid-template-columns: repeat(3,1fr);
grid-template-areas: "green1 green2 green3"
"green4 green5 green6"
"green7 green8 green9"
"brown1 brown2 brown3"
"brown4 brown5 brown6";
grid-gap: 10px;
}
.item{
border:1px solid black;
height:50px;
width:50px;
}
.green1 {
background:green;
grid-area: green1;
}
.green2 {
background:green;
grid-area: green2;
}
.green3 {
background:green;
grid-area: green3;
}
.green4 {
background:green;
grid-area: green4;
}
.green5 {
background:green;
grid-area: green5;
}
.brown1{
grid-area: brown1;
background:brown;
}
.brown2{
grid-area: brown2;
background:brown;
}
.brown3{
grid-area: brown3;
background:brown;
}
.brown4{
grid-area: brown4;
background:brown;
}
<div class="grid">
<div class="item green1"></div>
<div class="item green2"></div>
<div class="item green3"></div>
<div class="item green4"></div>
<div class="item green5"></div>
<div class="item brown1"></div>
<div class="item brown2"></div>
<div class="item brown3"></div>
<div class="item brown4"></div>
</div>

Related

Set width as percentage of overflowing flexbox container

I am building a Gantt chart using CSS. I calculate the 'offset' of a task from the first date in the header, and the width of the task based on the duration as a percentage of the total range between the dates in the header - see example. This largely works fine except for when there are too many months in the header, and so the overflow starts to scroll, because the percentage of the offset & width are applied to the container width excluding the scrollable portion. How can I fix this so the these values are applied to the actual scrollable width of the container? (Hopefully without using any JS)
In the example, the task should start at 50% (i.e. start of month 7) and run for 25% (i.e. to end of month 9). You can check this by removing the min-width:300px;
(Note that the red background will ultimately be transparent)
.container {
overflow-x: auto;
width:100%;
background-color:#eee;
}
.container .months {
display:flex;
flex-direction:row;
}
.container .months .month {
min-width:300px;
padding:5px 10px;
border:solid 1px black;
flex: 1 0 0%;
}
.container .bars .bar {
display:flex;
flex-direction:row;
}
.container .bars .bar .spacer {
background-color:red;
}
.container .bars .bar .task {
background-color:yellow;
}
<div class="container">
<div class="months">
<div class="month">Month 1</div>
<div class="month">Month 2</div>
<div class="month">Month 3</div>
<div class="month">Month 4</div>
<div class="month">Month 5</div>
<div class="month">Month 6</div>
<div class="month">Month 7</div>
<div class="month">Month 8</div>
<div class="month">Month 9</div>
<div class="month">Month 10</div>
<div class="month">Month 11</div>
<div class="month">Month 12</div>
</div>
<div class="bars">
<div class="bar">
<span class="spacer" style="width:50%"></span>
<span class="task" style="width:25%">Task 1</span>
</div>
</div>
</div>
display: grid on the container will fix the issue. The bars will be inside a track that has the same size as the months element
.container {
overflow-x: auto;
display: grid;
background-color:#eee;
}
.container .months {
display:flex;
flex-direction:row;
}
.container .months .month {
min-width:300px;
padding:5px 10px;
border:solid 1px black;
flex: 1 0 0%;
}
.container .bars .bar {
display:flex;
flex-direction:row;
}
.container .bars .bar .spacer {
background-color:red;
}
.container .bars .bar .task {
background-color:yellow;
}
<div class="container">
<div class="months">
<div class="month">Month 1</div>
<div class="month">Month 2</div>
<div class="month">Month 3</div>
<div class="month">Month 4</div>
<div class="month">Month 5</div>
<div class="month">Month 6</div>
<div class="month">Month 7</div>
<div class="month">Month 8</div>
<div class="month">Month 9</div>
<div class="month">Month 10</div>
<div class="month">Month 11</div>
<div class="month">Month 12</div>
</div>
<div class="bars">
<div class="bar">
<span class="spacer" style="width:50%"></span>
<span class="task" style="width:25%">Task 1</span>
</div>
</div>
</div>

Css grid without subgrid [duplicate]

I have the following table design, laid out with CSS Grid (see first snippet).
Is it possible to make all columns of the same type/class (e.g. .Table_col_day) as wide as the column of that type/class with the widest content, with CSS/without JS? The solution doesn’t have to be CSS Grid based.
See the second code snippet for a quick JS-based solution, to illustrate what I'd like to do.
.Table__row {
background-color: plum;
display: grid;
grid-template-columns: 0.5fr 0.5fr 1fr;
}
.Table__row:nth-of-type(even) {
background-color: lime;
}
<div class="Table">
<div class="Table__row">
<div class="Table__day">Mon</div>
<div class="Table__time">10am</div>
<div class="Table__title">Some event</div>
</div>
<div class="Table__row">
<div class="Table__day">Tue</div>
<div class="Table__time">12:30pm</div>
<div class="Table__title">Another event</div>
</div>
<div class="Table__row">
<div class="Table__day">Wed</div>
<div class="Table__time">9:00am</div>
<div class="Table__title">A different event</div>
</div>
</div>
Javascript-based solution (determine widest column content, then manually set grid column styles of row element)
function resizeColumns(SELECTOR) {
const colElements = document.querySelectorAll(SELECTOR);
//////
const widths = [...colElements].map(el => el.querySelector('span').offsetWidth);
const width_max = Math.max(...widths);
//////
for(let col of colElements) {
col.parentNode.style.gridTemplateColumns = `${width_max}px 0.5fr 1fr`;
}
}
resizeColumns('.Table__col_day');
.Table__row {
background-color: plum;
display: grid;
grid-template-columns: 0.5fr 0.5fr 1fr;
}
.Table__row:nth-of-type(even) {
background-color: lime;
}
<div class="Table">
<div class="Table__row">
<div class="Table__col_day">
<span>Mon</span>
</div>
<div class="Table__col_time">
<span>10am</span>
</div>
<div class="Table__col_title">
<span>Some event</span>
</div>
</div>
<div class="Table__row">
<div class="Table__col_day">
<span>Tue</span>
</div>
<div class="Table__col_time">
<span>12:30pm</span>
</div>
<div class="Table__col_title">
<span>Another event</span>
</div>
</div>
<div class="Table__row">
<div class="Table__col_day">
<span>Wed</span>
</div>
<div class="Table__col_time">
<span>9:00am</span>
</div>
<div class="Table__col_title">
<span>A different event</span>
</div>
</div>
</div>
You said it at the beginning: "table design" so use table
.Table {
display: table;
width: 100%;
}
.Table__row {
background-color: plum;
display: table-row;
}
.Table__row > * {
display: table-cell;
white-space: nowrap;
}
.Table__row > *:not(.Table__day) {
width: 50%;
}
.Table__row:nth-of-type(even) {
background-color: lime;
}
<div class="Table">
<div class="Table__row">
<div class="Table__day">Mon</div>
<div class="Table__time">10am</div>
<div class="Table__title">Some event</div>
</div>
<div class="Table__row">
<div class="Table__day">Tue</div>
<div class="Table__time">12:30pm</div>
<div class="Table__title">Another event</div>
</div>
<div class="Table__row">
<div class="Table__day">Wed</div>
<div class="Table__time">9:00am</div>
<div class="Table__title">A different event</div>
</div>
</div>
Or consider display:contents if you want to keep display:grid;
.Table {
display: grid;
grid-template-columns: auto 1fr 1fr;
}
.Table__row {
display: contents;
}
.Table__row > * {
background-color: plum;
}
.Table__row:nth-of-type(even) > * {
background-color: lime;
}
<div class="Table">
<div class="Table__row">
<div class="Table__day">Mon</div>
<div class="Table__time">10am</div>
<div class="Table__title">Some event</div>
</div>
<div class="Table__row">
<div class="Table__day">Tue</div>
<div class="Table__time">12:30pm</div>
<div class="Table__title">Another event</div>
</div>
<div class="Table__row">
<div class="Table__day">Wed</div>
<div class="Table__time">9:00am</div>
<div class="Table__title">A different event</div>
</div>
</div>

Bootstrap grid system 1 row with two columns into 2 rows

So I have this layout on my grid
But as the width goes smaller I want to change to this layout
So far I have it like this
.row > div {
border: 1px solid black
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<div class='row'>
<div class="col-md-6">
1
</div>
<div class="col-md-5">
<div class='row'>
<div class="col-md-12">
2
</div>
<div class="col-md-12">
3
</div>
</div>
</div>
</div>
I think best practice way CSS Grid layout to essay and customizable
.grid > div {
border: 1px solid black;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
#media (min-width: 768px) {
.one {
grid-row: 1/3;
}
}
.three {
grid-column: 1/3;
}
#media (min-width: 768px) {
.three {
grid-column: 2/3;
}
}
<div class='grid'>
<div class="one">
1
</div>
<div class="two">
2
</div>
<div class="three">
3
</div>
</div>
like this?
<div class='row'>
<div class="col-md-6 col-sm-6">
1
</div>
<div class="col-md-6">
<div class='row'>
<div class="col-md-12 col-sm-6">
2
</div>
<div class="col-md-12 col-sm-12">
3
</div>
</div>
</div>
</div>

I want a div of specific height to grow in width as necessary to accommodate text

As shown in the example bellow, I want a div of specific height to grow in width only as much as necessary to accommodate it's text, but I can't do it
I want it to look like this
body{
overflow-x: scroll;
}
.container{
display: flex;
flex-direction: row;
width: max-content;
}
.item{
width: min-content ;
max-height: 3em;
border: 1px solid red;
}
<body>
<div class="container" >
<div class="item"> sid jkodasjkadf kadsf kas</div>
<div class="item"> salkf hjahsadkjhfgadsakjsl</div>
<div class="item"> saf nasd kmfgdn skjdsj</div>
<div class="item"> sjfn sdnf sdmfosdj md faikmoa fia</div>
<div class="item"> siiojasd oiasdi </div>
<div class="item"> alksj fksdafja</div>
<div class="item"> sid jkodas jkadf kadsf kas</div>
<div class="item"> salkf hjahsadkjhfga dsakjsl</div>
<div class="item"> saf nasd kmfgdn skjdsj</div>
<div class="item"> sjfn sdnf sdmfosdj md faikmoa fia</div>
<div class="item"> siiojasd oiasdi </div>
<div class="item"> alksj fksdafja</div>
</div>
</body>
try this,
.container{
display:grid;
grid-template-columns:repeat(3,1fr);
}
.item{
max-height: 3em;
border: 4px solid red;
padding:1rem;
}

Automatic offset / alignment in CSS grid?

I've a five column grid, which has in some cases only content in three columns. The content should be right aligned, so that there will be an offset of two columns. Is there a possibility to do this automatically? Actually I'm doing it with grid-column-start: 3, grid-column-start: 4, grid-column-start: 5:
.grid {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 1rem;
margin: 2rem 0;
}
.col {
text-align: center;
padding: 2rem;
background-color: lightblue;
}
<div class="grid">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
</div>
<p>Actual syntax / layout:</p>
<div class="grid">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
<p>Should behave like this:</p>
<div class="grid">
<div class="col" style="grid-column-start: 3;">1</div>
<div class="col" style="grid-column-start: 4;">2</div>
<div class="col" style="grid-column-start: 5;">3</div>
</div>
Thought about something like justify-items: end but thats for the alignment of the content inside the column. For me I'm looking like even more a solution as it's behaviour in flexbox (justify-content), but I don't want to use flexbox ;)
Regards,
Markus
You can handle each case alone since they aren't a lot:
.grid {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 1rem;
margin: 2rem 0;
}
.col {
text-align: center;
padding: 2rem;
background-color: lightblue;
}
.col:nth-last-child(1):first-child {
grid-column-end: -1;
}
.col:nth-last-child(2):first-child {
grid-column-end: -2;
}
.col:nth-last-child(3):first-child {
grid-column-end: -3;
}
.col:nth-last-child(4):first-child {
grid-column-end: -4;
}
<div class="grid">
<div class="col">1</div>
</div>
<div class="grid">
<div class="col">1</div>
<div class="col">2</div>
</div>
<div class="grid">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
<div class="grid">
<div class="col" >1</div>
<div class="col" >2</div>
<div class="col" >3</div>
<div class="col" >4</div>
</div>
<div class="grid">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
</div>

Resources