Child div elements that auto-columises based on 100% parent height - css

I have numerous div elements that I would like to be scrolled horitonzaly rather than vertically, based on 100% parent height.
I have done a quick move up of the desired result.
As an example if the parent is 600 pixels tall, six 100px items will fit before it makes a new column and a 900px height would fit 9 items.
How can I achieve this affect? I only need it to work in Chrome is cross-browser support is not available for this.
Code for you to fiddle with, http://jsfiddle.net/yQ5AR/
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
<div class="item">11</div>
<div class="item">12</div>
<div class="item">13</div>
<div class="item">14</div>
<div class="item">15</div>
<div class="item">16</div>
<div class="item">17</div>
<div class="item">18</div>
<div class="item">19</div>
<div class="item">20</div>
</div>
.container{
max-height: 400px;
width: 100%;
overflow: scroll;
}
.item{
height: 100px;
}

Use flexbox for this
FIDDLE
CSS
.container{
max-height: 600px;
width: 100%;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.item{
height: 70px;
background: silver;
width: 200px;
margin: 10px;
padding: 5px;
}

CSS columns and column-break-inside should do what you're looking for (-webkit in this case since you only care about Chrome).
http://jsfiddle.net/yQ5AR/4/
CSS
.container{
max-height: 400px;
width: 100%;
overflow: scroll;
-webkit-columns: 100px;
}
.item{
height: 100px;
-webkit-column-break-inside: avoid;
}

Related

flex-column: how to limit the height of grow part so it does not expand?

I'm sure this kind of question was asked before, but I really can't describe it exactly and concisely enough to let the search engine to understand me. So here we go:
To better explain my question I'm writing the code in tailwind style here. A stack snippet is also attached below:
<div class="root w-screen h-screen flex flex-col">
<div class="header h-[72px] w-full bg-red shrink-0"></div>
<div class="content grow">
<!-- a whole lot of content, very tall, height > 2000 px -->
</div>
</div>
In this example, I would like to limit the height of the entire div.root to 100vh. However, because div.content is very tall, it expands the body that it shows a vertical scrollbar.
Well this is fairly easy to overcome, I only need to add scroll-y-auto to div.content. So the body scrollbar disappears, and div.content shows a vertical scrollbar. Perfect.
However later on, I decided to split div.content into two columns: both column shall have its own vertical scrollbar. Intuitively I changed the code to:
<div class="root w-screen h-screen flex flex-col">
<div class="header h-[72px] w-full bg-red shrink-0"></div>
<div class="content grow">
<div class="left overflow-y-auto">
<!-- a whole lot of content, very tall, height > 2000 px -->
</div>
<div class="right overflow-y-auto">
<!-- a whole lot of content, very tall, height > 2000 px -->
</div>
</div>
</div>
But this does not work at all, as the attached snippet demonstrates. body got its scrollbar back, but not div.left or div.right.
I've explored several ways to solve this problem. In the end the best solution I got was to set the height of div.content to calc(100% - 72px). This works perfectly, but I understand it's only because I know the exact height of div.header is fixed at 72px.
Was I doing something wrong here? What's the most elegant way to solve this kind of problem?
body {
margin: 0;
}
.root {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
height: 72px;
width: 100%;
background-color: red;
flex-shrink: 0;
}
.content {
flex-grow: 1;
display: flex;
flex-direction: row;
}
.very-tall-content {
background-color: green;
height: 2400px
}
.left, .right {
flex-grow: 1;
margin: 0 4px;
overflow-y: auto;
}
<div class="root">
<div class="header"></div>
<div class="content">
<div class="left">
<p class="very-tall-content"></p>
</div>
<div class="right">
<p class="very-tall-content"></p>
</div>
</div>
</div>
Allright, try this one maybe it fixed your problem :)
instead of using flex for .root use grid. down here we have a
header with minimum height of 72px and if it's content overloads, the
header will auto-fit them
:root {
--header-min-height: 72px;
}
body {
margin: 0;
}
.root {
display: grid;
grid-template-rows: minmax(var(--header-min-height), auto) 1fr;
height: 100vh;
}
.header {
grid-row: 1;
background: darkcyan;
}
.content {
grid-row: 2;
display: flex;
background-color: palegreen;
overflow-y: hidden;
}
.content>div {
flex-grow: 1;
overflow-y: auto;
}
.white-space {
height: 3000px;
}
<div class="root">
<div class="header"></div>
<div class="content">
<div class="left">
Left Side
<div class="white-space"></div>
Left Side
</div>
<div class="right">
Right Side
<div class="white-space"></div>
Right Side
</div>
</div>
</div>
here's the example if it overloads.
:root {
--header-min-height: 72px;
}
body {
margin: 0;
}
.root {
display: grid;
grid-template-rows: minmax(var(--header-min-height), auto) 1fr;
height: 100vh;
}
.header {
grid-row: 1;
background: darkcyan;
}
.content {
grid-row: 2;
display: flex;
background-color: palegreen;
overflow-y: hidden;
}
.content>div {
flex-grow: 1;
overflow-y: auto;
}
.white-space {
height: 3000px;
}
.row {
display: flex;
flex-direction: row;
width: fit-content;
}
.item {
background: rgba(255, 255, 255, .5);
width: fit-content;
padding: 10px;
margin: 5px;
border-radius: 5px;
}
<div class="root">
<div class="header">
<div class="row">
<div class="item">test</div>
<div class="item">test</div>
<div class="item">test</div>
</div>
<div class="row">
<div class="item">test</div>
<div class="item">test</div>
<div class="item">test</div>
</div>
<div class="row">
<div class="item">test</div>
<div class="item">test</div>
<div class="item">test</div>
</div>
</div>
<div class="content">
<div class="left">
Left Side
<div class="white-space"></div>
Left Side
</div>
<div class="right">
Right Side
<div class="white-space"></div>
Right Side
</div>
</div>
</div>

How to Center a list of inline-block items, while aligning the content of the list to the Left?

I have a list of inline-block elements inside a parent element. I wont to center the parent element while keeping the child elements aligned to the left.
<body>
<style>
/* the width of the container is dynamic by the width of the window */
.container {
height: 600px;
text-align: center;
border: 1px solid red;
overflow-y: auto;
}
/* i don't know the width of the list element, it's only for centering */
.list {
text-align: left;
}
/* the width of the item is const - always 200px */
.item {
display: inline-block;
width: 200px;
height: 200px;
margin: 10px;
background: gray;
}
</style>
<div class="container">
<div class="list">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
</div>
</div>
</body>
As you can see in the attached example, the list element isn't centered.
If I remove the align: left style then the list element will be centered but then the item elements will be centered as well (I want them to be aligned to the left)
This what I'm trying to achieve:
Some thing like this just give text-align: left; to item and remove text-align: center; from list
<body>
<style>
.container {
width: 600px;
height: 600px;
text-align: center;
border: 1px solid red;
overflow-y: auto;
}
.item {
display: inline-block;
width: 200px;
height: 200px;
margin: 10px;
background: gray;
text-align: left;
}
</style>
<div class="container">
<div class="list">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
</div>
</div>
</body>
make all items fit the width of the list either by putting a fixed width to list or edit the width of item to have less than 50% of list, .item{width: 46%;} worked well
.container {
width: 600px;
height: 900px;
border: 1px solid red;
overflow-y: auto;
}
.list {
border: 1px solid #bbb;
width: 445px;
margin: 0px auto;
}
.item {
text-align: left;
display: inline-block;
width: 200px;
height: 200px;
margin: 10px;
background: gray;
}
<body>
<div class="container">
<div class="list">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
</div>
</div>
</body>
What are you actually trying to achieve?
Now you have .container and .list that are both 600px wide, so you don't see if list element is aligned to left or center.
First, you should have different widths for .list and .container. Then your list should be an inline-block element for it to react to text-align: center.
I made a codepen for you to make this more clear: https://codepen.io/leo-melin/pen/MWYbLLa
.container {
width: 800px;
height: 600px;
text-align: center;
border: 1px solid red;
overflow-y: auto;
}
.list {
display: inline-block;
width: 500px;
border: solid 1px #000; /* Added border to make it visual */
text-align: left;
}
.item {
display: inline-block;
width: 200px;
height: 200px;
margin: 10px;
background: gray;
}
UPDATE 1
If I now understand you correctly, you have n-elements per row that are all 200px wide and you want to center them in container if there's not enough space to fit another 200px element. You want the last item to be aligned to left inside the container.
As in this another stackoverflow answer: https://stackoverflow.com/a/40936683/2061685 you probably need to utilize flexbox for that behaviour to work.
So something like this would do:
<div class="container">
<div class="list">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
<div class="item phantom"></div>
</div>
</div>
.container {
width: 100%;
height: 600px;
border: 1px solid red;
overflow-y: auto;
text-align: center;
}
.list {
display: inline-flex;
flex-wrap: wrap;
justify-content: center;
text-align: left;
}
.list:after {
content: '';
flex: auto;
}
.item {
display: inline-block;
width: 200px;
height: 200px;
margin: 10px;
background: gray;
}
.item.phantom {
visibility: hidden;
height: 0;
}
Working codepen: https://codepen.io/leo-melin/pen/gObgLrX
As you can see, you need to add those phantom items to make the last element stay on the left. On very wide screen with just a few items, you need to control the amount of phantom elements. Use mediaqueries or define an algorithm while rendering the items to make sure it works in all cases.
Hope this helps now for you to figure out a solution.

Fixed Row using Flexbox Grid

I am using flexboxgrid css library (www.flexboxgrid.com) and I want to achive my first row to be fixed and stays the full width of the container.
I am currently ending up in the first row being fixed but not full width. Here is what I did so far:
HTML:
<div class="Wrapper">
<div class="row center-xs middle-xs fixedHeader">
<div class="col-xs-12 col-sm-12 col-md-7 col-lg-7">
<div class="box">
<h3>Fixed Header</h3>
</div>
</div>
</div>
<div class="row center-xs middle-xs normalContent">
<div class="col-xs-12 col-sm-12 col-md-7 col-lg-7">
<div class="box">
<h3>normal content</h3>
</div>
</div>
</div>
</div>
CSS:
.Wrapper{
max-width: 1520px;
margin: 0 auto;
padding: 80px 40px;
}
.fixedHeader {
background-color: red;
position: fixed;
}
.normalContent{
min-height: 900px;
background-color:green;
}
I have also done a jsFiddle for this. Any idea what am I doing wrong ?
You need to add a width attribute to your "fixedHeader" class. I use the calc css function to make it 100% minus the padding in your "Wrapper" class.
.Wrapper{
max-width: 1520px;
margin: 0 auto;
padding: 80px 40px;
}
.fixedHeader {
background-color: red;
position: fixed;
width: calc(100% - 80px);
}
.normalContent{
min-height: 900px;
background-color:green;
}
See http://caniuse.com/#search=calc for calc() compatibility
You are using position:fixed that's why you are not getting the 100% width.
Add the width as well to your .fixedHeader
.fixedHeader {
background-color: red;
position: fixed;
width: 100%;
}

Vertically center element with dynamic height in scroll container

I have a scroll container that's usually the size of the whole screen. Inside of it I place dynamic content. So I won't know which height it has or how many elements will be inserted.
Now I want to layout it like this:
if there is enough space, I want the whole content vertically centered inside the scroll container
if the total height of the content exceeds the height of the scroll container, I want the container to just scroll the contents like there was no centering.
I created an example where I tried to solve this problem with flexbox. With content height less than the container height it works like intended. But when the content exceeds the container height, due to justify-content, some elements of the content are cut off:
You can see on the image that the scroll container's scrollTop is all the way at the top, yet elements 1 & 2 aren't visible.
I'd like to know if there is a CSS only solution. A JS solution I could do myself but that's not what I'm after. If it's not possible, that's okay too.
.container {
display: inline-block;
width: 300px;
height: 300px;
border: 2px solid red;
overflow-y: auto;
margin: 1rem 0;
display: flex;
flex-direction: column;
justify-content: center;
}
.block {
width: 80%;
height: 3rem;
margin: 1rem auto;
background: blue;
flex-shrink: 0;
color: #fff;
text-align: center;
}
<div class="container">
<div class="block">1</div>
</div>
<div class="container">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
</div>
<div class="container">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
<div class="block">4</div>
<div class="block">5</div>
<div class="block">6</div>
<div class="block">7</div>
<div class="block">8</div>
</div>
Try applying the overflow to an inner containing div like so:
.container {
display: inline-block;
width: 300px;
height: 300px;
border: 2px solid red;
margin: 1rem 0;
display: flex;
flex-direction: column;
justify-content: center;
}
.inner {
overflow-y: auto;
}
.block {
width: 80%;
height: 3rem;
margin: 1rem auto;
background: blue;
flex-shrink: 0;
color: #fff;
text-align: center;
}
<div class="container">
<div class="inner">
<div class="block">1</div>
</div>
</div>
<div class="container">
<div class="inner">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
</div>
</div>
<div class="container">
<div class="inner">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
<div class="block">4</div>
<div class="block">5</div>
<div class="block">6</div>
<div class="block">7</div>
<div class="block">8</div>
</div>
</div>

Scroll CSS Floats instead of breaking

I'm creating a series of columns all floated left against eachother. I'd like to make it so that when the columns are larger than their container a horizontal scrollbar appears instead of the columns dropping down. Here's what I have...
<body>
<div id="container">
<div id="col1" class="col">Column One</div>
<div id="col2" class="col">Column Two</div>
...
</div>
</body>
With the css:
body { width: 100%; height: 100%; overflow: auto; }
#container { width: 100%; height: 100%; }
.col { float: left; width: 250px; height: 100%; }
I would ideally like to have the scrollbar on the page/body level since the page is nothing but the columns.
It will work with this CSS :
#container { width: 100%; overflow: auto; white-space: nowrap; }
.col { display: inline-block; width: 250px; }
Caution : display-block not working on IE <= 7
An other solution is to use two containers and fix the width of the second with the sum of columns width :
#container1 { width: 100%; overflow: auto; white-space: nowrap; }
#container2 { width: 1250px; }
.col { float:left; width: 250px; }
<div id="container1">
<div id="container2">
<div class="col">Column 1</div>
<div class="col">Column 2</div>
<div class="col">Column 3</div>
<div class="col">Column 4</div>
<div class="col">Column 5</div>
...
</div>
</div>
If you want the scrollbar on the body, just remove overflow:auto on #container and #container1
put the width out of container and body. That should resolve the problem.

Resources