Flexbox - Variable Number of Columns Problem - css

I'm trying to aim for a responsive design wherein a long list of links is arranged in columns, the number of columns varying according to the width of the display device screen. As I understand it, I must specify the height of the container to get multiple columns. However, then the columns continue to the right off the screen. I do not know the length of the links. Is there any way to do this through Flexbox? It seems like such an obvious requirement.
The CSS I have so far is:
/* Container */
.links {
display: flex;
flex-direction: column;
flex-wrap: wrap;
width: 100vw !important;
height: 90vh;
}
/* Links in Container */
.links a {
white-space: nowrap;
flex: 1;
margin: 5px 5px 0 20px;
}
Edit: this it NOT a duplicate as commented. The problem not that the container width doesn't grow horizontally. The problem is that it DOES grow horizontally, not vertically.

Have you considered just using CSS Columns?
You wouldn't need to specify any height and then as the screen width changes, the number of columns will adjust based on the width you specify - taking up whatever height it needs, accordingly.
Your CSS could just look like this:
.links {
columns: 5 100px; // # of columns | minimum column width
column-gap: 40px; // space between columns
}
.links > a {
display: block;
padding: 10px 5px;
}
<div class="links">
link1
link2
link3
link4
link5
link6
link7
link8
link9
link10
link11
link12
link13
link14
link15
link16
link17
link18
link19
link20
</div>
Browser support for columns is pretty good.
Hope this helps!

Related

Have two questions on the small project, one about Flexbox other about Grid

https://xvicissitudex.github.io/Basic_Website_Template/
Used Flex Box for the Nav bar. However I want it to be more responsive as it shrinks, especially the text. To get it responsive I added a media query at 600px.
`nav_main {
display: flex;
margin: 0px;
padding-left: 1rem;
list-style-type: none;
}
#media only screen and (max-width: 600px) {
.nav_main {
font-size: 1.2rem;
}
li {
padding: .4rem;
}
}
`
But is there another way to get the flex children to shrink along viewport? I was trying flex shrink property but that only works when you want one flex item to shrink more than the others not when you want them all to shrink in unison.
The blue background was set up with grid:
`.blue {
display: grid;
grid-template-columns: repeat( auto-fit, minmax(350px, 1fr));
grid-gap: 20px;
padding: 20px;
}`
My question is how do I center the content once the grid items get pushed down to the second row.For example on a 24" motitor there are 5 grid items on first row, and 3 on second. I want to center second row. justify-content: center does nothing.
Thanks for any help.
I am not sure about your first question.
But for the second one you can check out this site with great explanation - https://css-irl.info/controlling-leftover-grid-items/

Angular Material Select w/ Columns

I am trying to style the selection panel such that the items display in several columns, but the last item of each column seems to become off-center and split, with the overflow starting at the top of the next column. Ideally the scroll would be vertical, but instead it seems to scroll horizontal to cover the overflow. My list has 30+ items and multiple selections are allowed. The goal is to display as many options as possible to the user at once so they don't have to scroll too much.
Full StackBlitz:
https://stackblitz.com/edit/angular-bt3gs6
select-multiple-example.scss
.toppings-panel.mat-select-panel {
column-count: 2;
column-width: 200px;
width: 400px;
max-width: 400px;
}
select-multiple-example.html
<mat-select [formControl]="toppings" panelClass="toppings-panel" multiple>
<mat-option *ngFor="let topping of toppingList" [value]="topping">{{topping}}</mat-option>
</mat-select>
select-multiple-example.ts
export class SelectMultipleExample {
toppings = new FormControl();
toppingList: string[] = ['Pepperoni', 'Sausage', 'Ham', 'Bacon', 'Chicken',
'Mushroom', 'Red onion', 'White onion', 'Tomato', 'Olives',
'Green bell peppers', 'Pineapple', 'Artichoke', 'Spinach',
'Basil', 'Hot pepper flakes',
'Parmesan', 'Shredded cheddar', 'Extra mozzarella'];
}
The problem with the columns that become off-center and split, is the height of the .mat-select-panel.
It has max-height:256px; (setted in Angular Material code). But, since it has a horizontal scrollbar (which has a height of 17px, in Windows - Chrome), the available remaining space will be: 256 - 17 = 239px.
The height of the mat-option is 48px, so 5 options in a column will take 240px.
A quick solution would be to increase the height of the .mat-select-panel to 257px:
Demo: https://stackblitz.com/edit/angular-bt3gs6-wxwkgg
But, the example above will not display correctly on MacOS; which displays scrollbars like an absolute positioned content, and it has more space available:
I've found a cross platform solution by removing columns (which are kind of difficult to implement cross-browser and cross-platform) and taking an
approach with display: flex for the .mat-select-panel element:
Horizontal scrolling:
.toppings-panel.mat-select-panel {
width: 400px;
max-width: 400px;
display: flex;
flex-direction: column;
flex-wrap: wrap;
min-height: 257px; // min-height needed for windows browsers
}
.toppings-panel.mat-select-panel .mat-option {
min-width: 50%; // 50% to have 2 columns visible
}
Demo: https://stackblitz.com/edit/angular-bt3gs6-lwvwav
Vertical scrolling:
If you prefer vertical scrolling, just remove flex-direction: column; from the code above and play with the max-height in order to set the default visible rows:
.toppings-panel.mat-select-panel {
width: 400px;
max-width: 400px;
display: flex;
flex-wrap: wrap;
max-height: 240px; /* 240px - for 5 items / column */
}
.toppings-panel.mat-select-panel .mat-option {
min-width: 50%;
}
Demo: https://stackblitz.com/edit/angular-bt3gs6-iykn4w

Make text inside header responsive [duplicate]

This question already has answers here:
Make container shrink-to-fit child elements as they wrap
(4 answers)
Closed 2 years ago.
The following header looks fine on full-width; but once I start sizing down; there's a large gap to the left of the ipsom lorem text, where it should be filling in the full-width of the screen as it sized down. (First picture is full-width; second picture is what should happen when it sizes down).
Here is my code so far:
.header {
background-color: #090c1a;
}
.header-inner {
color: white;
display: grid;
max-width: 1180px;
margin: 180px auto;
grid-template-columns: 1fr minmax(50%, auto);
}
I've also created a codepen for convenience. https://codepen.io/tiotolstoy/pen/PoPzoQw
I don't think a grid is the best approach for what you described. I would do it with a "max-width: 590px" on the nested div inside the header-inner. like here - https://codepen.io/urich/pen/rNOLNZd
.header-inner {
color: white;
max-width: 1180px;
margin: 180px auto;
}
.header-inner >div {
max-width: 590px;
}
If you just want the mobile version's p element to take up full width, with just a tiny bit of padding to prevent text from touching the edge, change your CSS to this:
.header {
background-color: #090c1a;
}
.header-inner {
color: white;
padding: .5rem;
}
You could also add a media query for the larger version to prevent the text from stretching the entire length of the div if you don't want the p element spread out too far on large screens, like this:
#media(min-width: 768px) {
.header-inner {
width: 50%;
}
}
Play around with the percentage until you get the desired width on full screens.

CSS Flex Column Layout without Specified Height

Just discovered flex today and I'm hoping it'll solve a small visual challenge.
I have a list of items already alphabetically sorted. They all have the same width and, up until now, I've had them floating left. This results in a left-to-right order with wrapping when horizontal space runs out.
What I was hoping to do is have top-down sorting with as many columns as possible with the available width. Seeing as this list is dynamic, the height would be variable. And the height would have to increase as horizontal space is lost (resizing) preventing as many columns.
Given the apparent nature of what flex is trying to accomplish I'd think this would be supported, but thus far I can't figure it out. "display: flex" and "flex-flow: column wrap" seem correct, but it requires a specific height to work, which I can't provide.
Am I missing something?
Edit:
I've created a JSFiddle to play with here: https://jsfiddle.net/7ae3xz2x/
ul {
display: flex;
flex-flow: column wrap;
height: 100px;
}
ul li {
width: 150px;
list-style-type: none;
border: 1px solid black;
text-align: center;
}
If you take the height off the ul, nothing wraps.
It seems the conceptual problem is that "column" flow is all tied to the height of the container instead of to the width, which is what I want. I don't care how tall the area has to be. I care about having as many columns as possible in the available width. Maybe this is just an annoying shortcoming of the flex convention.
This seems like a job for CSS columns: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Columns
Instead of flex, give the ul a column-width CSS rule:
ul {
column-width: 150px;
}
Here's a JSFiddle.
I'm not sure if this is what you're looking for, but you might need to change flex-flow: column wrap: to flex-flow: row wrap; and change the height and width to 100vh and 100vw
ul {
display: flex;
flex-direction: column;
flex-flow: row wrap;
height: 100vh;
width: 100vw;
}
So now the list items keep the same width and adjust height based on the size of the view width. Updated Fiddle

Get flexbox column wrap to use full width and minimize height

I have a container with a fixed width and variable height. I'm filling the container with an unknown amount of elements.
I'd like the elements to arrange themselves in columns, from top to bottom and then left to right.
I could use column, but I don't know the maximum width of the child elements, so I can't set a column-width or column-count.
I think display: flex with flex-flow: column wrap is the way to go, but if I maintain height: auto on the container, it will generate as a single column without wrapping elements to use all the available width.
Can I convince flexbox to use all the available width and thus minimize the container's height?
Would you suggest a different solution?
Fiddle: http://jsfiddle.net/52our0eh/
Source:
HTML:
<div>
<span>These</span>
<span>should</span>
<span>arrange</span>
<span>themselves</span>
<span>into</span>
<span>columns,</span>
<span>using</span>
<span>all</span>
<span>available</span>
<span>width</span>
<span>and</span>
<span>minimizing</span>
<span>the</span>
<span>container's</span>
<span>height.</span>
</div>
CSS:
div {
outline: 1px solid red;
width: 100%;
display: flex;
flex-flow: column wrap;
align-items: flex-start;
/*height: 8em;*/
}
span {
outline: 1px solid blue;
}
What you look for is more like the column rules: DEMO
div {/* do not set column numbers rule */
width: 100%;
-moz-column-width:4em;
column-width:4em;
-moz-column-gap:0;
column-gap:0;
-moz-column-rule:solid 1px;
column-rule:solid 1px;
text-align:center;
}
I've compromised and set height: 10em (which seems acceptable) along with overflow-y: auto (to add a horizontal scrollbar in case of overflow) on the container element.
I would still like to know if there is a way to use all available width and minimize the height, though.
In the end, your options for overflowing are hide, scroll, or wrap. How about this version instead? It takes any overflowing items and puts them on a second row. Items on the second row still fill the available space, but are larger due to the smaller number of items sharing the space.
http://jsfiddle.net/52our0eh/14/
div {
outline: 1px solid red;
display: flex;
flex-flow: row wrap;
}
span {
outline: 1px solid blue;
flex:1;
}

Resources