Using calc() with a dynamic value? - css

I am wondering if this is possible: I have a header that can contain a variable amount of text. Below that I have another element which I want to take up the remaining height of the page.
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
Normally I would do this using calc, eg:
.content {
height: calc(100vh - 75px);
}
Where 75px is the set height of .header.
But in this example, the .header element is dynamic and does not have a set height. Only a padding and font-size are set.
To complicate things, this also uses the Foundation Grid layout, which makes me nervous about using display: table (.title and .menu sit side by side on desktop, but stacked on mobile) .
Is there anyway to get the height of the dynamic header element (without resorting to JQuery)?

You can use flexbox and set .content to flex-grow: 1 so that it will fill to grow the available space.
body {
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}
.content {
flex-grow: 1;
background: #eee;
}
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>

I made a small pen to show the way to do this using flex box, it involved changing your markup a bit:
css:
.container {
display: flex;
flex-direction: column;
height: 250px; // whatever you want here
}
.header {
width: 100%;
background: red;
padding: 10px;
}
.content {
background: yellow;
width: 100%;
flex-grow: 1;
}
So the content will always take the available space inside the content div.
check the whole pen: http://codepen.io/anshul119/pen/yMYeLa
hope this helps.

Related

how to make columns the same width with css flex

hello I need to basicaly display a table but with flex (only because I need to adjust the look for mobile)
.container {
display: flex
}
<div class="container">
<div class="row">
<div>1000</div>
<div>mary</div>
</div>
<div class="row">
<div>1</div>
<div>john</div>
</div>
<div class="row">
<div>11</div>
<div>mike</div>
</div>
</div>
how can I make each column have the same width? or at least the width of the largest item.
If you apply flex-grow: 1 to each div in the .row then it will expand accordingly. Note that the .row divs need the display flex (flex only apply to the DIRECT children of the flexed element.
The width can be set by using flex-basis and calc() and dividing the full-width by the number of columns you want (2 in this case). I added a border to demonstrate.
I would be remiss if I didn't suggest that the best tool to display a table structure - is a ... table... then you can work out how to modifiy for responsive layout - but the semantic structure of a table is correct for tabulr content.
.container {
width: 100%;
}
.row {
display: flex;
width: 100%;
}
.row div {
flex-grow: 1;
flex-basis: calc(100% / 2);
padding: 4px 8px;
border: solid 1px red;
}
<div class="container">
<div class="row">
<div>1000</div>
<div>mary</div>
</div>
<div class="row">
<div>1</div>
<div>john</div>
</div>
<div class="row">
<div>11</div>
<div>mike</div>
</div>
</div>
Use flex-basis to set the 'default' width first.
Use flex-grow and/or flex-shrink to allow it to grow /shrink
Use max-width' and min-width` to define by how much it can grow/shrink
.container{ #Stack the div inside the conainer
display:flex;
flex-flow: columns nowrap;
}
.row{ # Set div as cell in the row.
display:flex;
flex-flow: row nowrap;
flex-basis: 33%; # Calculate width from there.
flex-grow:1; #Allow resizing bigger
flex-shrink:1; #Allow resize smaller.
max-width:50%; #Adjust to your liking
min-width:25%; #Adjust o your liking
}
Please consider this ressource https://css-tricks.com/snippets/css/a-guide-to-flexbox/
You can add a flex-basis to the .row items by doing this:
.row {
flex-basis:calc(100% / 3);
}
.container {
width: 100%;
}
.row {
display: flex;
width: 100%;
}
.row div {
flex-grow: 1;
flex-basis: calc(100% / 2);
padding:10px;
margin: 5px;
background: #eee;
}
<div class="container">
<div class="row">
<div>1000</div>
<div>mary</div>
</div>
<div class="row">
<div>1</div>
<div>john</div>
</div>
<div class="row">
<div>11</div>
<div>mike</div>
</div>
</div>

CSS Grid - How to implement grid items, which don't "stretch" the grid row and have a scroll-able container

My challenge is:
I want to have a grid with a fixed amount of columns (which can later be adjusted via javascript) and a flexible amount of rows of equal height.
The number of rows are determined by the amount of grid items, which are UI cards.
These cards should fill out the entire height of their respective cell but MUST not increase the height of the row. So basically max-height = row-height assigned by grid
Then inside these cards we have the typical three parts: Header, Body and Footer. The body MUST be scroll-able, if more list items exists than the row-height allows.
I've tried to implement this on stackblitz
https://stackblitz.com/edit/angular-3gkmtm
What i don't understand is
Why the cards "stretches" the row when more items appear
How to achieve the scroll-able card body section without manually using a fixed height (like in the example i use max-height)
Why when there are more then 3 rows, it overflows
Please help!
<article>
<section>
<h2>Fixed Gird with scrollable cards</h2>
</section>
<section>
<button (click)="onAdd()">Add</button>
<button (click)="onRemove()">Remove</button>
</section>
<section class="remaining-height">
<div class="grid-container">
<div class="grid-item" *ngFor="let card of cards">
<div class="card">
<div class="card-header">Card #{{card}}</div>
<div class="card-body card-flexible-scroll">
<div class="list-item" *ngFor="let item of list">{{item}}</div>
</div>
<div class="card-footer">
Some Footer
</div>
</div>
</div>
</div>
</section>
</article>
article{
display: flex;
flex-direction: column;
height: 100%;
}
.remaining-height{
flex:1
}
.grid-container {
display: grid;
grid-gap: 0.5rem;
height: 100%;
grid-auto-rows: auto;
grid-template-columns: repeat(5, auto);
}
.grid-item{
display: flex;
padding:24px;
}
.card{
display: flex;
flex-direction: column;
width: 100%;
height:100%;
background:#ccc;
}
.card-body{
.list-item{
padding: 6px;
background:#fcd3d3;
}
.list-item:nth-child(even){
background:#efefef;
}
}
.card-flexible-scroll{
flex:1;
overflow-y:auto;
max-height: 300px; // <= no max height
}
Angular Controller to generate cards and list items
```js
export class AppComponent {
name = "Angular";
cards = new Array(8).fill(0).map((_,idx)=>idx+1);
list = new Array(30).fill(0).map((_,idx)=>idx+1);
onAdd() {
this.cards.push(this.cards.length + 1);
}
onRemove() {
this.cards.pop();
}
}
global style
html , body{
height: 100vh;
overflow: hidden;
}
If I understand correctly what you are trying to do you want that the card body takes all the available row space between the header and footer and not force the card to be bigger than the row if it contains items.
It is possible to achieve that with adding another div with absolute positioning inside the card body div that is sized to the full body height then the items inside will overflow correctly.
Here is the changed template:
<article>
<section>
<h2>Fixed Gird with scrollable cards</h2>
</section>
<section>
<button (click)="onAdd()">Add</button>
<button (click)="onRemove()">Remove</button>
</section>
<section class="remaining-height">
<div class="grid-container">
<div class="grid-item" *ngFor="let card of cards">
<div class="card">
<div class="card-header">Card #{{card}}</div>
<div class="card-body">
<div class="card-flexible-scroll">
<div class="list-item" *ngFor="let item of list">{{item}}</div>
</div>
</div>
<div class="card-footer">
Some Footer
</div>
</div>
</div>
</div>
</section>
</article>
And the updated CSS:
.card-body{
.list-item{
padding: 6px;
background:#fcd3d3;
}
.list-item:nth-child(even){
background:#efefef;
}
position: relative;
flex:1;
}
.card-flexible-scroll{
position: absolute;
width: 100%;
height: 100%;
max-height: 100%;
overflow-y: auto;
}
I created a fork of your StackBlitz where you can see how it works. If this is not what you look for please explain more.

Make an element take up available horizontal space without causing its parent to widen

I have a flexbox container with exactly two children, both of which can have variable content. I want the width of the entire container to fit the width of the first child, but I want the second child's contents to wrap and not cause the container to grow horizontally. See the runnable snippet below for a visual problem description.
Currently looking for a CSS Grid solution. I have found one partial solution, but relies on JavaScript: Make the second child a relative container, put its contents in an intermediate absolutely-positioned container, and use JS to set a fixed height. At least it's good for showing what I'm looking for.
Problem:
.container {
display: inline-flex;
flex-direction: column;
border: 1px solid red;
}
.child {
background-color: wheat;
margin: 5px;
}
<div class="container">
<div class="first child">
This content can grow and be as wide as it wants
</div>
<div class="second child">
This content will also be any size it wants, but I * want it to wrap at the asterisk in this sentence, which is where the first child above would naturally end. This will be its own flexbox container holding several buttons that should wrap onto new rows.
</div>
</div>
JavaScript/absolute solution:
let second = document.getElementsByClassName('second')[0]
let content = document.getElementsByClassName('absolute')[0]
second.style.height = content.offsetHeight + 'px'
.container {
display: inline-flex;
flex-direction: column;
border: 1px solid red;
}
.child {
background-color: wheat;
margin: 5px;
}
.second {
position: relative;
/* height to be set by JS */
}
.absolute {
position: absolute;
width: 100%;
top: 0;
left: 0;
}
<div class="container">
<div class="first child">
This content can grow and be as wide as it wants
</div>
<div class="second child">
<div class="absolute">
This content is longer than the above but still wraps in the right place.
</div>
</div>
</div>
Just set min-width and width of .second:
.container {
border: 1px solid red;
display: inline-block;
padding: 5px;
}
.child {
background-color: wheat;
}
.second {
margin-top: 10px;
min-width: 100%;
width: 0;
}
<div class="container">
<div class="first child">
This content can grow and be as wide as it wants
</div>
<div class="second child">
This content will also be any size it wants, but I * want it to wrap at the asterisk in this sentence, which is where the first child above would naturally end. This will be its own flexbox container holding several buttons that should wrap onto new rows.
</div>
</div>

CSS- Getting 100% width div to wrap under another [jsfiddle]

In a responsive layout, I have two columns. The left column is the sidebar and the right column is the content.
Using a media query, when the screen width is tiny, the columns turn to 100% width and stack on top of each other.
In this case, I want the sidebar (the first div) to appear beneath the content (the second div).
I tried using float: right on a small screen once it's at 100%, but at 100% width, the float apparently doesn't matter.
.left, .right {
width: 100%;
float: left;
background: green;
}
.left {
float: right;
background: red;
}
.half {
width: 50%;
}
.space {
width: 100%;
display: block;
height: 40px;
}
And on the page:
<div class="left half"> <!-- To mimic full screen size -->
Left
</div>
<div class="right half">
Right
</div>
<div class="space"></div>
<div class="left"> <!-- To mimic small screen size -->
Left
</div>
<div class="right"><!-- This should appear first -->
Right
</div>
Here is the fiddle: https://jsfiddle.net/ph09frvw/
I'm sure this is not the first time someone wanted to wrap the sidebar under the content, I just haven't been able to find a solution.
You can use display: flex and use the order property to change the order of the <div> elements. While floating can be helpful for horizontal alignment, it will be of little help for vertical alignment, Here is an example:
.flex {
display: flex;
flex-flow: row wrap;
}
.left {
order: 2;
flex: 1 0 50%;
background: red;
}
.right {
order: 1;
flex: 1 0 50%;
background: green;
}
.full {
margin-top: 20px;
}
.full > .left,
.full > .right {
flex: 1 0 100%;
}
<div class="flex">
<div class="left">
Left
</div>
<div class="right">
Right
</div>
</div>
<div class="flex full">
<div class="left">
Left
</div>
<div class="right">
Right
</div>
</div>
You could use the display:flex; property combined with flex-direction to reorder your divs. Ref: https://css-tricks.com/almanac/properties/f/flex-direction/
Remember to reference your related class-names in your HTML elements' class attribute.
Your CSS display:block should do the trick, else try something like:
float: left
When you use: display:block on a div element, you do not need to specify width:100% as it should automatically span across the width if it is not hindered by anything else.
Make sure the position of these elements are "relative", else it may not work as expected; it may be stated globally that some specific tags should be displayed "absolute" and that may break what you're trying to achieve.

How to equalise sibling div heights?

<div class="wrapper">
<div class="sidebar-wrapper"></div>
<div class="content-wrapper"></div>
</div>
The height of content-wrapper is dynamic (auto). Is there any way to get the height of it and use it for the sidebar-wrapper so that it looks nice?
Displaying them like table cells would do it. Table cells can adjust their height automatically to the content, and all cells on the same row get the same height. If you give the side bar a fixed width (which is likely), you can easily get the content wrapper to fill the remaining space.
Whichever has the longest content will determine the height.
.wrapper {
width: 100%;
display: table;
}
.sidebar-wrapper,
.content-wrapper {
display: table-cell
}
.sidebar-wrapper {
width: 200px;
background-color: silver;
}
.content-wrapper {
background-color: yellow;
}
<div class="wrapper">
<div class="sidebar-wrapper">Here is <br>content<br>that is .....<br><br><br><br><br><br>Quite long</div>
<div class="content-wrapper">Smaller content</div>
</div>
Flexbox is an alternative to #GolezTrol's CSS tables.
.wrapper {
display: flex;
}
.sidebar-wrapper {
width: 200px;
background-color: silver;
}
.content-wrapper {
background-color: yellow;
flex: 1;
}
<div class="wrapper">
<div class="sidebar-wrapper">Here is
<br>content
<br>that is .....
<br>
<br>
<br>
<br>
<br>
<br>Quite long</div>
<div class="content-wrapper">Smaller content</div>
</div>

Resources