I’d like to set up a page with multiple entries consisting of some description text and associated icons. The icons may vary in size and should be aligned. (I use letters “i” and “w” instead of icons for simplicity in my examples below.)
When the page is wide enough, I’d like them to be set up as a grid with a wide left column and the icons to the right, that should take as few horizontal space as possible. Here is an example with two “icons”.
.container {
display: grid;
grid-template-columns: 1fr repeat(2, max-content);
}
.content {
justify-self: center;
}
<div class="container">
<div class="header">Some text</div>
<div class="content">i</div>
<div class="content">i</div>
<div class="header">Some more text</div>
<div class="content">w</div>
<div class="content">w</div>
</div>
When the viewport is too small, so that the left column would be reduced, say, below 200 px, I’d like to switch responsively the layout and have it displayed as a stack, as in this example.
.container {
display: grid;
grid-template-columns: 1fr repeat(2, max-content) 1fr;
}
.container > div {
justify-self: center;
}
.header {
grid-column-start: 1;
grid-column-end: 5;
}
.content1 {
grid-column-start: 2;
}
.content2 {
grid-column-start: 3;
}
<div class="container">
<div class="header">Some text</div>
<div class="content1">i</div>
<div class="content2">i</div>
<div class="header">Some more text</div>
<div class="content1">w</div>
<div class="content2">w</div>
</div>
This approach works, but there are multiple aspects that I’d like to improve, if possible.
My web site uses bootstrap, so I could use their “row” and “col” functionalities (or other bootstrap concepts). Designing my own grid instead feels like not using the right tools for the job. But I could not find out how to design such a grid with bootstrap’s rows and columns. (This question raises a similar problem.)
My approach requires an explicit media query and uses two completely different designs depending on the available space. This feels more complex than necessary. Is it possible to make better use of the grid module responsiveness (or any other appropriate html or css trickery), so that the icons would automatically flow below the text when the viewport is too small? I thought about using auto-fill, but as my columns do not all have the same size, I ignore how to proceed.
My current design for the small viewport case uses classes content1, content2, and so on, and repetitive CSS instructions to place them in successive columns. This problem will be exacerbated if I want more icons. Can I avoid such repetition?
The display classes are responsive. Therefore you can use d-flex d-md-grid on the container. When it switches to display:flex the grid-template-columns will be ignored.
.container {
grid-template-columns: 1fr repeat(2, max-content);
}
.content {
justify-self: center;
}
<div class="container d-flex d-md-grid flex-wrap align-items-center justify-content-center text-md-start text-center">
<div class="header w-100">Some text</div>
<div class="content">i</div>
<div class="content">i</div>
<div class="header w-100">Some more text</div>
<div class="content">w</div>
<div class="content">w</div>
</div>
Demo on Codeply
Of course, you could use d-sm-grid, d-lg-grid or d-xl-grid instead of d-md-grid to set the breakpoint as desired.
Related
Is there a way to make a grid item span over all free space automatically?
For example here, the grid has two rows and two columns. In the first row, the second column is free, so I'd like to span the item (as it does when I explicitly set grid-column-end: 3).
But I do not want to calculate the spans, but let the browser do that.
Edit: to make the question clearer: the container is only allowed to specify the number of rows and cols. The items are only allowed to specify the row- and col-start but no spans and -ends so if there is an item with row-start: i followed by an item with row-start: i+1+n and no items with row-start: i+1+m with m<n the item with row-start: i should automatically span n.
<div style="display: grid; gap: 5px;">
<div style="
background: red;
grid-row-start: 1;
grid-column-start: 1;
/* how can I get rid of this */
grid-column-end: 3;">1 1</div>
<div style="
background: red;
grid-row-start: 2;
grid-column-start: 1;">2 1</div>
<div style="
background: red;
grid-row-start: 2;
grid-column-start: 2;">2 2</div>
</div>
First off,
You cannot automatically span grid items over all free space.
Without explicitly setting the grid-column-end property or calculating the spans yourself - it would be best to resort to something like flexbox.
The way the grid layout works is that it uses the grid-row-start, grid-column-start, grid-row-end and grid-column-end properties to determine the size and position of each item within the grid. Without explicitly setting these properties, the browser will not know how to position the items and you'll inevitably end up with a gigantic mess. Grids aren't like flexbox since they aren't really smart and require you to explicitly set nearly every aspect of it in order to be rendered properly. They aren't really responsive either.
If you do decide to continue sticking with CSS Grid, one option would be to use JavaScript to calculate the spans based on the position of the other items on the grid and then set these properties dynamically. This is more complex and will add more overhead to your code - making it less easy to maintain
Another option (which I personally recommend) is to use flexbox instead of CSS Grid. A flexbox automatically adjusts the size of its flex items based on the available space, and you can use the flex-wrap property to wrap the items onto new rows if there is not enough space.
Flexbox is also responsive. CSS Grid is not.
Therefore, the pros weigh out the cons when compared to CSS Grid.
I don't know if that can totally suits you but one way would be to defined class with span 2 and span1.
.row {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: 1fr auto;
}
.col1 {
grid-column: auto / span 2;
}
.col2 {
grid-column: auto / span 1;
}
<div class="row">
<div class="col1" style="background-color: red">
1 1
</div>
</div>
<div class="row">
<div class="col2" style="background-color: green">
2 1
</div>
<div class="col2" style="background-color: blue">
2 2
</div>
</div>
we can put css grid-column: 1 / -1; as it will automatically fill the cell to the last. So basically we don't need to provide grid-column-end with specific number.
.row {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.col-stretch{
grid-column: 1 / -1;
}
<div class="row">
<div class="col-stretch" style="background-color: red">
1 1
</div>
</div>
<div class="row">
<div class="col" style="background-color: green">
2 1
</div>
<div class="col" style="background-color: gray">
2 2
</div>
<div class="col" style="background-color: yellow">
2 3
</div>
</div>
I'm trying to space out elements inside a Card evenly, but they are not lined-up:
here's the code:
<div className="card">
<header className="card-header">
<div className="card-header-info">
<p>{`#${driver.driverId}`}</p>
<h1>{driver.name}</h1>
</div>
<div className="card-header-info">
<p>VEHICLE</p>
<p>{driver.vehicleId}</p>
</div>
<div className="card-header-info">
<p>HOMETOWN</p>
<p>{driver.hometown}</p>
</div>
</header>
</div>
CSS
.card-header-info {
padding-left: 20px;
margin-right: auto;
}
I have also tried Bulma (CSS framework) columns but got nothing. Anyone know a slick technique that would achieve this goal while at the same time making the space relative to the size of the Card? I would appreciate any help.
I recommend the following for the header element using css grid:
.card-header {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
I have started using css grids recently (https://css-tricks.com/snippets/css/complete-guide-grid/) but feel like I'm not fully exploiting them. My question concerns a situation where my displayed data is dynamic. For instance I want to display this:
In short:
each row of data can contain one or two columns
rows are separated by a divider row
data is dynamic, the css grid layout cannot be pre-set
It feels like css grids have a way of doing this (without dynamically generating the css), using repeat etc... but I don't really see how.
This is done under React, some dynamic rows are generated using a map, the code would looks something like this:
return (
<div>
<div> 1A </div>
<div> 1B </div>
<MyDivider />
<div> 2 </div>
<MyDivider />
{myData.map((row) => (
<div key={row.key}>
<div>{row.A}</div>
<div>{row.B}</div>
<MyDivider />
</div>
))}
// more rows, with single (merged) or dual columns...
</div>
);
Is it possible to do this without dynamically generating the grid css? Namely, defining grid settings for single / dual column lines, and divider lines? Also, due to the map function, under React, my dynamic content ends up wrapped in a div; do I need to break this down in multiple map's so that I don't have this wrapping div?
Thanks!
Edit 10/24/2020:
To clarify things, I don't want to literally display what is in this drawing, this is just a layout, with each '1A', '1B' block corresponding to some data cell, just like in a tabulator.
Assuming that you know if a row is single or dual columns.
You can make a cell span by using grid-column like the sample below
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 5px; // for demonstration purposes
}
.grid-item {
background-color: lightblue; // for demonstration purposes
}
.grid-item.single {
grid-column: span 2;
}
.grid-separator {
grid-column: span 2;
background-color: lightgreen; // for demonstration purposes
}
<div class="grid">
<div class="grid-item">A1</div>
<div class="grid-item">B1</div>
<div class="grid-separator">Separator</div>
<div class="grid-item single">A2</div>
<div class="grid-separator">Separator</div>
<div class="grid-item">A3</div>
<div class="grid-item">B3</div>
<div class="grid-separator">Separator</div>
<div class="grid-item">A4</div>
<div class="grid-item">B4</div>
<div class="grid-separator">Separator</div>
<div class="grid-item single">A5</div>
</div>
Note that you need to add the single class under some condition
Please show us your css or you can do it like that way...
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
}
.grid div {
text-align: center;
background: #ddd;
margin: 2px;
padding: 10px;
}
.mydevider {
grid-column: 1 / span 2;
}
<div class="grid" >
<div> 1A </div>
<div> 1B </div>
<div class="mydevider">
<div> 1A </div>
</div>
<div> 1B </div>
<div> 1B </div>
<div class="mydevider">
<div> 1A </div>
</div>
<div> 1B </div>
<div> 2 </div>
</div>
I have created a form with two columns. But when I decrease the browser width, two columns are preserved even when their content overflows. I have tried to change the code to plain DIV with container class, specify cols count, set width but it resists.
Here is the codepen: https://codesandbox.io/s/stoic-goldberg-4ugt6
and the source code of the parent container:
<div class="container flex-wrap pt-3 w-75 ml-auto mr-auto mt-auto mb-5">
<div class="row">
<div class="col">
<b-card>
<SeriesForm />
</b-card>
</div>
<div class="col">
<b-card :header="captions[1]">
<SeriesForm :group="forms[1]" />
</b-card>
</div>
</div>
<div class="row">
<div class="col text-center p-4">
<b-button>Analyse</b-button>
</div>
</div>
</div>
How can I make it two columns when there is enough space and single column otherwise?
U can try class like col-sm-6 or col-xs-6 or col-md-6 or col-lg-6 according to your need.
<div class="container flex-wrap pt-3 w-75 ml-auto mr-auto mt-auto mb-5">
<div class="row">
<div class="col-sm-6">
<b-card>
<SeriesForm />
</b-card>
</div>
<div class="col-sm-6">
<b-card :header="captions[1]">
<SeriesForm :group="forms[1]" />
</b-card>
</div>
</div>
<div class="row">
<div class="col text-center p-4">
<b-button>Analyse</b-button>
</div>
</div>
</div>
The issue isn't with the bootstrap grid itself, the issue is with how your checkboxes are displayed.
You're defining in the .align-nicely class, that your checkbox group must always be 3 columns.
display: grid isn't that smart. So if you tell it to be 3 columns, it will be 3 columns and ignore everything else. This is why your content is overflowing.
So to fix the issue or improve it at least. You have to change how the display: grid columns are handled.
One method would be to use CSS #media queries, to define how many columns there should be at a given screen width. This way you can scale them down as the screen gets smaller.
The below CSS should work if you use <b-col xl='6'> with your current text.
.align-nicely {
display: grid;
grid-column-gap: 10px;
grid-row-gap: 10px;
grid-template-columns: 1fr 1fr 1fr;
}
#media screen and (max-width: 1350px) {
.align-nicely {
grid-template-columns: 1fr 1fr;
}
}
#media screen and (max-width: 576px) {
.align-nicely {
grid-template-columns: 1fr;
}
}
Another solution could be to use the repeat() function combined with minmax().
This option will be a lot more dynamic than the first one, but will break the alignment across your different groups.
.align-nicely {
display: grid;
grid-column-gap: 10px;
grid-row-gap: 10px;
/*
The 110px inside minmax(), is how small each column is allowed to get.
So if there isn't space on the current row for the column to be over 110px,
it will be moved to a new row. So you will need to adjust this based on your content size.
*/
grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
}
This is happening because of the flex display,
what you need to do is set the columns with below your row for each form :
use this <div class='col-12 col-xl-6'> instead of <div class='col'> .. the spacing is a little bit tight so you might need to remove some of the margins and paddings
this will make each form take full width on big screens and below and will make them 50% width on xl screens
I have added attribute to your tags
If you will expand the screen then u will get the initial format.
Though this question has been asked a lot before, all answers suggestion that to span a column, place the other columns into an inner row, like so:
<div class="row">
<div class="col-12 col-md-4">logo</div>
<div class="col-12 col-md-8">
<div class="row">
<div class="col-12">top nav</div>
<div class="col-12">bottom nav</div>
</div>
</div>
</div>
The result would look like so on a desktop:
And, on mobile it would look like this:
However, the required result would be to place the logo between the two navigation, like below:
My best bet so far, is two place two logos, then hide and show them at different viewport sizes. Which works, but isn't really a neat solution.
Using custom grid layout is my first suggestion. (Or maybe bootstrap has some shortcuts to that, but I don't know of them) You can play with order-X classes of bootstrap. But that will not help you to get logo div, in between nav divs in different wrapper
.special {
display: grid;
}
div {border: 1px solid grey;}
/* for tablets and desktops*/
#media screen and (min-width: 600px) {
.special {
grid-template-columns: 1fr 2fr;
grid-template-rows: 50px 50px;
}
.logo {grid-area: 1/1/3/2;}
}
<div class="special">
<div class="topNav">top nav</div>
<div class="logo">logo</div>
<div class="bottomNav">bottom nav</div>
</div>