CSS Grid - position text in three columns - html

currently I’m struggling with positioning these 3 text columns just like in picture. Each column contains 3 patagraphs.
Problem is, paragraph’s width is not equal, so grid-template-columns:repeat(3, 1fr) is not ideal solution because second and third paragraph will have unnecessary big white-space and that’s the problem when responsibility comes in. (Layout will break very soon because of that white-space).
I’ve tried min-content or max-content atributes but still I can’t figure it out, so it will look just as in the picture.
So goal is to align columns and paragraphs in it just like in the picture but without unwanted whitespace so work with responsibility will be easier.
Is there any better solution for it?
I have tried my best, here’s codepen
Thank you!

You can use minmax in your grid-template-column property, minmax(5rem, 10rem) minmax(3rem, 5rem) auto;, this will set the minimum width of the first column to 5rem and the maximum width to 10rem, the second to min of 3rem and max of 5rem, then the last columns width will be the width of its content => auto.
css-grid-layout-minmax ~ MDN
.card {
background: silver;
padding: 0 1rem;
border-radius: 12px;
}
.column {
display: grid;
grid-template-columns: minmax(5rem, 10rem) minmax(3rem, 5rem) auto;
justify-content: flex-start;
}
p:nth-of-type(3),
p:nth-of-type(4),
p:nth-of-type(2) {
text-align: right;
}
p + p {
margin-left: 1rem;
}
<div class="card">
<div class="column-wrapper">
<div class="column">
<p>lorem:</p>
<p>282726€</p>
<p>28%</p>
</div>
<div class="column">
<p>lorem ipsum:</p>
<p>287€</p>
<p>10%</p>
</div>
<div class="column">
<p>lorem:</p>
<p>19118€</p>
</div>
</div>
</div>

Related

How do I set the height of a column in CSS grid in order to make it scrollable?

I removed excess code but I think this is the core of what I need done. I am currently mapping a list of activities into the first grid__column. However, that list is very long of 40 items and I need to scroll the whole page to see it. I want to be able to set a height on this 1st column then set overflow: scroll on it to limit the view to maybe 10 items and scroll for the rest. I can't seem to be able to set a height on the column or put overflow on it.
#main-content.container {
padding: 0 20px;
max-width: 1200px;
margin: 0 auto;
}
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
gap: 74px;
}
.grid__column {
height: 10rem;
}
html:
<div id="main-content" className="container">
<div className="grid">
<div className="grid__column">
<div className="first-grid__column-title">Scroll Table</div>
<ActivitiesGuide />
</div>
<div className="grid__column">
<div className="second-grid__column-title">Second Column</div>
</div>
</div>
</div>
John, I'm not sure exactly what you are asking, but I did find this question that might be able to help you.
adding scrolling to divs
I hope this give you insight, or an idea in the right direction.

Why is auto-fill property of CSS Grid not working in column direction

I am practicing auto-fill property with rows, however, it is not doing what I desire. I want to create rows with height minmax(140px, 200px), but instead get one row with 200px height and the rest are 18px. Why is it happening?
body,
html {
height: 100%;
margin: 0;
}
.wrapper {
display: grid;
grid-template-rows: repeat(auto-fill, minmax(140px, 200px));
}
.wrapper>div:nth-child(odd) {
background-color: red;
}
<div class="wrapper">
<div class="one"> 1 </div>
<div class="one"> 1 </div>
<div class="one"> 1 </div>
<div class="one"> 1 </div>
<div class="one"> 1 </div>
</div>
To wrap grid in vertical direction you have to do a bit more:
specify a height for the grid container so that the grid items know when to wrap,
also specify grid-auto-flow: column (overriding default grid-auto-flow: row)
See demo below (have set height: 100% for illustration):
body,
html {
height: 100%;
margin: 0;
}
.wrapper {
display: grid;
grid-template-rows: repeat(auto-fill, minmax(140px, 200px));
grid-auto-flow: column; /* added */
height: 100%; /* adjust this*/
}
.wrapper>div:nth-child(odd) {
background-color: red;
}
<div class="wrapper">
<div class="one"> 1 </div>
<div class="one"> 2 </div>
<div class="one"> 3 </div>
<div class="one"> 4 </div>
<div class="one"> 5 </div>
</div>
Why specify a height?
Because auto-fill or auto-fit requires a definite dimension in that axis:
7.2.3.2. Repeat-to-fill: auto-fill and auto-fit repetitions
When auto-fill is given as the repetition number, if the grid
container has a definite size or max size in the relevant axis, then
the number of repetitions is the largest possible positive integer
that does not cause the grid to overflow the content box of its grid
container (treating each track as its max track sizing function if
that is definite or as its minimum track sizing function otherwise,
and taking gap into account); if any number of repetitions would
overflow, then 1 repetition. Otherwise, if the grid container has a
definite min size in the relevant axis, the number of repetitions is
the smallest possible positive integer that fulfills that minimum
requirement. Otherwise, the specified track list repeats only once.
Auto-fill in row direction is simpler
Note that here, you don't need to specify a width as display: grid is a block element and block elements have the width of the viewport. You can just use grid-template-columns: repeat(auto-fill, minmax(140px, 200px)) here:
body,
html {
height: 100%;
margin: 0;
}
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 200px));
/*grid-auto-flow: row; --> default (so not needed) */
}
.wrapper>div:nth-child(odd) {
background-color: red;
}
<div class="wrapper">
<div class="one"> 1 </div>
<div class="one"> 2 </div>
<div class="one"> 3 </div>
<div class="one"> 4 </div>
<div class="one"> 5 </div>
</div>
Why grid-auto-flow: column?
See the relevant excerpts from its definition - this property controls how grid items flow in a grid container if they are not explicitly placed:
grid-auto-flow
The grid-auto-flow CSS property controls how the auto-placement
algorithm works, specifying exactly how auto-placed items get flowed
into the grid.
The default value of grid-auto-flow is row which is why you need to override it to column:
row
The auto-placement algorithm places items by filling each row in turn,
adding new rows as necessary. If neither row nor column is provided,
row is assumed.

Equal margin space for flex items that wrap in flexbox grid

I am trying to create a responsive grid with flexbox:
On large screens, there should be three columns in one row
On smaller screens, just two rows or one
My code so far:
.grid {
display: flex;
flex-wrap: wrap;
}
.gridColumn {
flex: 1 1 0px;
background-color: lightblue;
min-width: 200px;
}
<div class="grid">
<div class="gridColumn">
<p>first column</p>
</div>
<div class="gridColumn">
<p>second column</p>
</div>
<div class="gridColumn">
<p>third column</p>
</div>
</div>
Now, I would like to set margins only between the columns (not on the sides of the grid as well), which should also behave correctly when the screen is resized. Does anybody know of a way to achieve this?
You can add a margin to the grid items...
.gridColumn {
margin: $margin;
}
... which is then offset by its container.
.grid {
margin: -$margin;
}
To avoid overflow, you could apply overflow-x: hidden to the body.
Codepen example
It's crashed on this part of code
.gridColumn + .gridColumn {
margin-left: 20px;
}
You should to try use media query and set margin-left: 0; on small screens.
Above part of code is still working because flex-wrap only changing the position of the "third column", that column still have "sister" before and margin-left is working.

CSS flex - is it possible to vertically align <h1> and <p> next to an <img> without using containers

A very common element containing an image, title and text is
<div class="mediaelement">
<img src="http://placekitten.com/g/500/500" />
<h1>The title. Unknown length.</h1>
<p>And the description. Which could also span multiple lines.</p>
</div>
Now display: flex appears to be a very flexible way to center and display items. E.g with the order property I could move the title before the image without touching dom.
But is it possible to align both the h1 and p vertically to the image without putting the into another container? Using only css?
Like this: http://imgur.com/draDl2q
If i put them into a container, I cannot move the h1 before the image with the flex order value.
Yes, it is....with one proviso. You need to know the height of the parent element.
Basically, you need column layout with wrapping. In order for the parent to know when to wrap you must have a limited height...or it just won't wrap.
.mediaelement {
display: inline-flex;
flex-direction: column;
flex-wrap: wrap;
height: 200px;
justify-content: center;
}
<div class="mediaelement">
<img src="http://placekitten.com/g/200/200" />
<h1>The title. Unknown length.</h1>
<p>And the description. Which could also span multiple lines.</p>
</div>
Once display:contents gains support this kind of fiddling about will become unnecessary as it will be possible to wrap and unwrap elements from their containers as required.
Here's Paulie_D's answer expanded to show the smaller issue with the widths of h1 and p. But this is already good enough solution for some cases.
.mediaelement {
display: inline-flex;
flex-direction: column;
flex-wrap: wrap;
height: 200px;
justify-content: center;
width: 600px;
}
<div class="mediaelement">
<img src="http://placekitten.com/g/200/200" style="
padding-right: 10px;
">
<h1 style="
width: calc(100% - 210px);
margin: 0;
">The title. Unknown length. Could be 2 lines</h1>
<p style="
width: calc(100% - 210px);
margin: 0;
">And the description. Which could also span multiple lines.And the description. Which could also span multiple lines.</p>
</div>
Answering my own question :)
With CSS grid, this is easier to solve.
https://codepen.io/Jaska/pen/VQGqWK
.mediaelement {
display: grid;
grid-template-columns: 1fr 1fr;
grid-column-gap: 1rem;
}
img {
grid-row: 1 / 5;
}
h1 {
grid-row: 2
}
p {
grid-row: 3;
}
So the img fills all the rows 1-4 so the h1 and p have to go to the second column. And I added h1 to start from row 2 and p to start from row 3 so there remains 2 equal height rows above and under the content.

CSS grid where one column shrinks to fit content, the other fills the remaning space

I need to create a horizontal layout where one block takes all available space and the other ones shrink to fit their content.
For example:
<div class="grid">
<div class="expand">Long text label</div>
<div class="shrink">Button</div>
</div>
A more complex example with two rows (an actual grid):
<div class="grid">
<div class="row">
<div class="shrink">...</div>
<div class="expand">...</div>
<div class="shrink">...</div>
<div class="shrink">...</div>
</div>
<div class="row">
<div class="shrink">...</div>
<div class="expand">...</div>
<div class="shrink">...</div>
<div class="shrink">...</div>
</div>
</div>
My requirements:
The large block should fill all available space even if short
The small blocks should fit their content
The large block (usually a text label) may be a single word larger that the available space, so it should be truncated in this case
The large block should not wrap if multi-word
The small blocks should not wrap (though in the case of multiple buttons or icons, this can be solved by making one block per component)
Support multiple rows (i.e. columns should be aligned)
I am targeting Android and iOS smartphones.
I have tried to adapt the code from this answer but I could not make it work for multiple rows. Also, the source code must be out of order, which is confusing (though not blocking for my use case). Here's a jsfiddle: http://jsfiddle.net/k3W8L/
You need to use grid-template-column and set the size of column you want to shrink-to-fit as auto, and specify the size of at least one other column using the fr unit.
Example:
To recreate the sidebar-content layout, where the sidebar is collapsible,
-------------------------------
| Sidebar | Content |
-------------------------------
you can create the grid as:
.grid {
display: grid;
...
grid-template-columns: auto minmax(0, 1fr); // see note below
grid-template-areas: "sidebar content";
}
.sidebar {
grid-area: sidebar;
}
.content {
grid-area: content;
}
See the codepen here for a demo & code: https://codepen.io/khs/pen/vegPBL
You can click on the navbar to see auto-sizing in action.
Note: One thing I've learnt since writing this answer is that in most cases, and especially in a fixed-height/fixed-width layout, you should use minmax(0, 1fr) instead of 1fr. The reason is that 1fr is actually a shorthand for minmax(auto, 1fr). This breaks when used for fixed layouts with longer content. See this question for more details: Why does minmax(0, 1fr) work for long elements while 1fr doesn't?
Hence I've updated my answer to reflect the fact. The minmax might be a little verbose, but it's almost always what you want for this kind of layout.
Context: I bumped into this question recently while learning to use grid in my app. With some help from ilyaigpetrov's answer, I was able to get a shrink-to-fit column sizing to work. Their answer doesn't give much explanation though, so I thought I'd add this:
I found the answer to my own question while trying to create a concise example.
It makes use of table layout:
.grid {
display: table;
table-layout: auto;
width: 100%;
}
.row {
display: table-row;
}
.expand {
display: table-cell;
width: 100%;
max-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.shrink {
display: table-cell;
white-space: nowrap;
}
The width: 100% in .expand is what makes the block fill all available space, thus fulfilling the first two requirements.
Note that the width in .grid simply sets the width of the entire grid, you can use any value here.
For some reason, putting max-width: 0 in .expand prevents the block to grow more than the available space, a smallish value like 100px will also do. I discovered this by chance and I don't know why it works.
Here's the jsfiddle: http://jsfiddle.net/fr253/
This answer helped me getting started.
I don't know whether my code is valid, but it gets the job done: either with grid or with flex.
.container {
display: grid;
grid-template-columns: 1fr auto auto;
}
.one {
background-color: pink;
}
.two {
background-color: yellow;
}
.three {
background-color: lightgreen;
}
/* Now the same but with flex. */
.whole-row {
grid-column: 1 / -1;
}
.flexy {
display: flex;
border: 1px solid red;
}
.flexy > .one {
flex-grow: 1;
}
.flexy > .two,
.flexy > .three {
/* flex-grow: 0; <- This value is a default. */
}
<div class="container">
<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
<div class="whole-row flexy">
<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
</div>
</div>