Keep the same flex-growth between lines [duplicate] - javascript

My problem is that I want the flexbox with variable range width, and all works well, but not on the last row. I want the same dimension for all children even where the row is not full of children (the last row).
#products-list {
position:relative;
display: flex;
flex-flow: row wrap;
width:100%;
}
#products-list .product {
min-width:150px;
max-width:250px;
margin:10px 10px 20px 10px;
flex:1;
}
I created a dynamic situation in jsFiddle
My flex divs can shrink until 150px and grow up to 250px, but all must be with the same size (and obviously I want a CSS solution, with JS I know the way).

Unfortunately, in the current iteration of flexbox (Level 1), there is no clean way to solve the last-row alignment problem. It's a common problem.
It would be useful to have a flex property along the lines of:
last-row
last-column
only-child-in-a-row
alone-in-a-column
This problem does appear to be a high priority for Flexbox Level 2:
CSS Working Group Wiki - Specification Issues and Planning
https://lists.w3.org/Archives/Public/www-style/2015Jan/0150.html
Although this behavior is difficult to achieve in flexbox, it's simple and easy in CSS Grid Layout:
Equal width flex items even after they wrap
In case Grid is not an option, here's a list of similar questions containing various flexbox hacks:
Properly sizing and aligning the flex item(s) on the last row
Flex-box: Align last row to grid
Flexbox wrap - different alignment for last row
How can a flex item keep the same dimensions when it is forced to a new row?
Selector for an element alone in a row?
Aligning elements in last flexbox row
How can I allow flex-items to grow while keeping the same size?
Left-align last row of flexbox using space-between and margins
Inconsistent margin between flex items on last row
How to keep wrapped flex-items the same width as the elements on the previous row?
How to align left last row/line in multiple line flexbox
Last children of grid get giant gutter cause of flexbox space-between
Managing justify-content: space-between on last row
Flexbox space between behavior combined with wrap
Possible to use CSS Flexbox to stretch elements on every row while maintaining consistent widths?

As a quick and dirty solution one can use:
.my-flex-child:last-child/*.product:last-child*/ {
flex-grow: 100;/*Or any number big enough*/
}

You could try using grid instead of flexbox here:
#products-list {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(auto-fit, minmax(100px, 250px)); //grid automagic
justify-content: start; //start left
}
Fiddle link

There is a great solution that works always.
add a div with class product (The same class for other items that are under flex) and add a style for this div:height:0px;
you need to add as many dives that are possible to be in one row.
<div class="product" style="height:0px">
as many that can be in one row.
That's all. Works always.

If all your rows have the same number of items, you can use :nth-last-child. For example, if all the rows have 3 items, you can do something like this to remove the margin of the last 3 items:
.container{
display: flex;
flex-wrap: wrap;
background: yellow;
}
.item{
width: calc((100% - 2*10px)/3);
height: 50px;
background: blue;
color: white;
margin-right: 10px;
margin-bottom: 10px;
padding: 5px;
box-sizing: border-box;
}
/* last item of each row */
.item:nth-child(3n){
margin-right: 0;
font-size: 150%;
}
/* last 3 items */
.item:nth-last-child(-n+3){
margin-bottom: 0;
background: green;
}
<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>

A simple trick adds a flexible space to fill the rest of the last row:
#products-list{
display:flex;
flex-flow: row wrap;
justify-content:space-between;
}
#products-list::after {
content: "";
flex: auto;
flex-basis: 200px;/*your item width*/
flex-grow: 0;
}
But you shouldn't use margins on items then. Rather wrap them into containers with padding.

I used this workaround, even if it's not very elegant and it doesn't use the power of Flexbox.
It can be carried out on the following conditions:
All the items have the same width
The items have a fixed width
You use SCSS/SASS (can be avoided though)
If this is the case, you can use the following snippet:
$itemWidth: 400px;
$itemMargin: 10px;
html, body {
margin: 0;
padding: 0;
}
.flex-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0 auto;
border: solid 1px blue;
}
#for $i from 1 through 10 {
#media only screen and (min-width: $i * $itemWidth + 2 * $i * $itemMargin) {
.flex-container {
width: $i * $itemWidth + 2 * $i * $itemMargin;
}
}
}
.item {
flex: 0 0 $itemWidth;
height: 100px;
margin: $itemMargin;
background: red;
}
<div class="flex-container">
<div class="item"></div>
<div class="item" style="flex: 500 0 200px"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Here I have created an example on codepen which also implements margin.
The second and the third conditions can be avoided respectively using css variables (if you decided to provide support for it) and compiling the above scss snippet.
Well, it's true, we could do it also before flexbox, but display: flex can be still essential for a responsive design.

I was facing this same issue where I wanted to have a variable number of items in a resizable container.
I wanted to use all of the horizontal space, but have all of the flex items at the same size.
I ultimately came up with a javascript approach that dynamically added padding spacers as the container was resized.
function padLastFormRow() {
let topList = [];
let nSpacersToAdd = 0;
$('#flexContainer').find('.formSpacer').remove();
$('#flexContainer').find('.formItem').each(function(i, formItem) {
topList.push($(formItem).position().top);
});
let allRowLengths = getFlexLineLengths(topList);
let firstRowLength = allRowLengths[0];
let lastRowLength = allRowLengths[((allRowLengths.length) - 1)];
if (lastRowLength < firstRowLength) {
nSpacersToAdd = firstRowLength - lastRowLength ;
}
for (var i = 1; i <= nSpacersToAdd; i ++) {
$('#flexContainer').append(formSpacerItem);
}
}
Please see my Fiddle:
http://jsfiddle.net/Harold_Buchman/z5r3ogye/11/

I was having a similar challenge with menu rows. I wanted more spacing on the top of the second row of menu items.
The use of flex-box's row-gap worked well.
https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap
.menu {
display: flex;
flex-wrap: wrap;
row-gap: 10px;
}
This added a margin-top type effect to menu items were wrapped to the second line.

If all your rows have the same number of items, you can use :nth-last-child. For example, if all the rows have 3 items, you can do something like this:
.container{
display: flex;
flex-wrap: wrap;
background: yellow;
}
.item{
width: calc((100% - 2*10px)/3);
height: 50px;
background: blue;
color: white;
margin-right: 10px;
margin-bottom: 10px;
padding: 5px;
box-sizing: border-box;
}
// last item of each row
.item:nth-child(3n){
margin-right: 0;
background: green;
}
// last 3 items
.item:nth-last-child(-n+3){
margin-bottom: 0;
font-size: 150%;
}
<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>

Related

Animate elements in and out of page

I have several images that I need to horizontally cross the page to the right, exit the page and then re-enter the page from the left. Some of the images will already be out of view, so they will have to enter first.
This is a sketch of what I've tried so far:
var elems = document.getElementsByClassName("child");
for (const elem of elems) {
elem.animate(
[
// keyframes
{transform: "translateX(300px)"},
],
{
// timing options
duration: 5000,
iterations: Infinity
},
);
}
.container {
background-color: aqua;
width: 1000px;
display: flex;
flex-direction: row;
overflow:hidden;
padding: 20px 0;
gap: 10px;
}
.child {
background-color: red;
flex: 0 0 20%;
}
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
<div class="child">7</div>
<div class="child">8</div>
</div>
For start I tried to slide out all the divs, but even that I don't understand why is not working.
I'm using your code as a starting point however there are 2 major differences between my code and yours. The first is that this solution is not using JavaScript, which is a plus, but it may not be what you are looking for. The second difference is that rather of animating the div elements with the class child, this solution is animating a wrapper div with the class slider.
One important thing to note, is that some calculations must be used for the animation to work properly. Adding or removing elements will require that the values are updated. The formula is the following:
Child div size: 20% (CHILD_SIZE)
Gap between children divs: 10px (GAP)
Amount of the children: 8 (CHILDREN_AMOUNT)
So together it goes like this: translateX(calc((CHILD_SIZE - GAP) * CHILDREN_AMOUNT));
var slider = document.getElementsByClassName('slider')[0];
slider.innerHTML += slider.innerHTML;
.container {
background-color: aqua;
width: 100%;
overflow: hidden;
}
.slider {
display: flex;
flex-direction: row;
padding: 20px 0;
gap: 10px;
animation: slideRight 10s infinite linear;
}
.child {
background-color: red;
flex: 0 0 20%;
}
#keyframes slideRight {
from {
transform: translateX(calc((-20% - 10px) * 8));
}
to {
transform: translateX(100% + 10px);
}
}
<div class="container">
<div class="slider">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
<div class="child">7</div>
<div class="child">8</div>
</div>
</div>
Updated considering the comment:
There are a few ways, the simpler way though is just to duplicate the div.child elements without touching the animation formula. This can be done just in the markup or using JavaScript to have a more dynamic solution (I have updated the code above to have the desired result).
What I consider a better way, though (not going to elaborate here as many libraries already solve this problem, just search for carousel js libraries), is to just prepend and append the necessary amount of elements to have the desired result instead of duplicating all of them.

Prevent "widows" - items alone in a row - when using css grid

I created a responsive grid which should contain rows of 4, 3, 2 or 1 items, depending on the window size. Hard requirement from Design is that no widows and no half filled rows are allowed. So for 11 items, there could be two rows of four items and one of three, or three rows of three items and one of two items, or... . You get the idea.
To solve the problem, I created a css grid:
display: grid;
grid-template-columns: repeat(auto-fit, minmax(264px, 1fr));
grid-gap: 24px;
This works fine for the resizing, but it does not take care of the widow problem. At first I did the naive approach of selecting the last item with a last-of-type selector and giving it a grid-row: 1 / -1 style, but that does not ensure that the row above is fully filled.
I guess there won't be a css only solution. Is there a way for an element to realize that it is alone in a row, or that it has to grow to fill the row? I had an idea using the nextSibling property to select the last child via JavaScript and maybe determine via the page offset if it fills the whole row. But my problem is that I can't hardcode the width of the screen.
Alternatively, is there a way to tell an element to spread until the end of the row? I tried this, but it did not work:
.card:last-of-type {
grid-column-end: span -1;
}
Click here for minimal reproducible example.
A solution is to use flexbox instead of grid. This way it can stretch with the screen size.
We use 25% for a 4 column layout. Subtracting 1rem for a bit of margin. (0.5 left + 0.5 right)
(Open snippet in fullscreen to see it working)
.my-grid {
display: flex;
flex-wrap: wrap;
}
.card {
min-width: 264px;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 1px 1px #00000026;
font-size: 14px;
background-color: red;
margin: .5rem;
flex: 1 1 calc(25% - 1rem);
}
<div class="my-grid">
<div class="card">1</div>
<div class="card">1</div>
<div class="card">1</div>
<div class="card">1</div>
<div class="card">1</div>
<div class="card">1</div>
<div class="card">1</div>
<div class="card">1</div>
<div class="card">1</div>
<div class="card">blub</div>
</div>

How to increase height of subcategories Item on side menu?

I work on angular 7 I work on app display categories reports and and reports sub
categories for every category selected .
I face Issue I need to increase Height of every sub category reports .
as example SwTest as Image I need to Increase height of cell of sub categories only .
On my stackblitz full sample work of menu
See the code here
For subcategory :
<div *ngIf="subrep.reportCategoryID === rep.reportCategoryID" class="wrapper" >
<a href="/reportdetails?id={{subrep.reportID}}">
<span class="sideNav nav navbar">{{subrep.reportName}}</span>
</a>
</div>
.wrapper{
background:#f1f1f1;
width: 100%;
border-top: 1px solid #d1b792;
border-bottom: 1px solid #d1b792;
}
You have a wrapper CSS class on the submenu <div>. Try this:
.wrapper {
height: 50px;
display: flex;
flex-direction: column;
justify-content: center;
}
It'll look like this:

Break all lines in CSS if one breaks

I've a part of code on my website. Some time it can happen that the line breaks if the code don't fit in the parent element anymore:
If this happens I want to break all lines instead because it looks ugly when one part is broken and the other don't.
Remind
I can have a least 20 elements in one list.
Update
This is the part of my code which I all need to wrap if one of them wraps:
.elements-list {
display: -webkit-box;
display: flex;
display: -ms-flexbox;
list-style: none outside;
}
.list-entry {
display: -webkit-box;
display: flex;
display: -ms-flexbox;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
list-style: none outside;
padding-right: 8px;
max-width: 200px;
}
span.single-detail span {
letter-spacing: 1px;
display: -webkit-inline-box;
display: inline-flex;
display: -ms-inline-flexbox;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
<ul class="elements-list">
<li class="list-entry">
<span class="single-detail">
<span>Abgabefrist:</span>
<span>22.02.2222</span>
</span>
<span class="single-detail">
<span>Entlohnung:</span>
<span>2.222,00 €</span>
</span>
</li>
<li class="list-entry">
<span class="single-detail">
<span>Abgabefrist:</span>
<span>22.02.2222</span>
</span>
<span class="single-detail">
<span>Entlohnung:</span>
<span>20.222,00 €</span>
</span>
</li>
<li class="list-entry">
<span class="single-detail">
<span>Abgabefrist:</span>
<span>22.02.2222</span>
</span>
<span class="single-detail">
<span>Entlohnung:</span>
<span>22.000.222,00 €</span>
</span>
</li>
</ul>
I don't think you can solve this with CSS alone. You can solve it with JavaScript.
One way would be to constantly monitor the elements and see if one of them wrapped. But then, once wrapped you will never unwrap, it's not responsive.
So this is my alternative:
By putting the value inside inline-block elements, you can align the widths of the elements. This way, when one element wraps, they will all wrap, because they simply won't fit anymore.
Advantages of this solution:
It's responsive, responds to browser resizing.
Only requires JavaScript on load. Sizing and wrapping is handled by CSS once the widths are set, so it's fairly lightweight.
Disadvantages:
You will need to recalculate the widths if you change the content of the elements, or if you have dynamic font sizing (I hope not).
It's not pixel perfect, it seems. Maybe it can be tuned (for instance by giving the left element also a width in whole pixels), or otherwise, maybe you'll forgive me this pixel. ;)
window.addEventListener('DOMContentLoaded', function(){
var rows = document.querySelectorAll('.row');
// First loop to find which line is the widest.
var widest = 0;
for(r=0; r<rows.length; r++) {
console.log(r);
var width = rows[r].querySelector('.col1').offsetWidth +
rows[r].querySelector('.col2').offsetWidth;
if (width > widest) widest = width;
}
// second loop to set the width of col2, so they all
// get the same width.
for(r=0; r<rows.length; r++) {
rows[r].querySelector('.col2').style.width =
(widest - rows[r].querySelector('.col1').offsetWidth) + 'px';
}
});
/* This is needed */
.col2 {
display: inline-block;
}
/* This is just for show */
.col1 {
padding-right: 1em;
}
span {
box-sizing: border-box;
border: 1px solid grey;
}
<!-- hacky div/span table, since there is no HTML in the question -->
<div class="row"><span class="col1">The time</span><span class="col2">2018-12-22 12:34</span></div>
<div class="row"><span class="col1">Total price here</span><span class="col2">$ 5,-</span></div>
You either need to set the css property white-space: nowrap; on the text parent element so no text wraps for that class or you could add the <br> on the HTML after the name of the element so it breaks every time, code is needed so we can be more specific in finding a solution.
Well, easiest would be to create "abgabefrist:01/01/0001" as two elements instead of one and then add display flex to the parent. so when the screen shrinks, the element comes below another.
Below mentioned code fine, tested on codepen.
.dates div {
display: flex;
flex-wrap: wrap;
}
<div class="main">
<div class="dates">
<div><span>abgabefrist:</span>
<span>01/01/0001</span></div>
<div><span>abgabefrist:</span>
<span>02/02/0002</span></div>
</div>
<div class="btns">
<button> Button One</button>
<button> Button Two </button>
</div>
</div>

Setting a length (height or width) for one element minus the variable length of another, i.e. calc(x - y), where y is unknown

I know we can use calc when lengths are defined:
flex-basis: calc(33.33% - 60px);
left: calc(50% - 25px);
height: calc(100em/5);
But what if a length is variable?
height: calc(100% - <<header with variable height>>);
OR
width: calc(100% - 50px - <<box with variable width>>);
Is there a standard way to do this in CSS?
I know the overall task is possible with flexbox and tables, but I'm wondering if CSS offers a simpler method. Flexbox, tables and simple Javascript are acceptable alternatives.
height demo
width demo
You can use CSS tables:
.wrapper {
display: table;
width: 100%;
margin: 15px 0;
}
.horizontal.wrapper > div {
display: table-cell;
white-space: nowrap; /* Prevent line wrapping */
border: 1px solid;
}
.left { width: 100px } /* Minimum width of 100px */
.center { width: 0; } /* Width given by contents */
.vertical.wrapper { height: 200px; }
.vertical.wrapper > div {
display: table-row;
}
.vertical.wrapper > div > span {
display: table-cell;
border: 1px solid;
}
.top { height: 100px; } /* Minimum heigth of 100px */
.middle { height: 0; } /* Height given by content */
.bottom { height: 100%; } /* As tall as possible */
<div class="horizontal wrapper">
<div class="left">100px wide</div>
<div class="center">Auto width, given by contents</div>
<div class="right">Remaining space</div>
</div>
<div class="vertical wrapper">
<div class="top"><span>100px tall</span></div>
<div class="middle"><span>Auto height, given by contents</span></div>
<div class="bottom"><span>Remaining space</span></div>
</div>
The horizontal case can also be achieved with floats:
#wrapper, .right { overflow: hidden; } /* Establish BFC */
#wrapper > div { border: 1px solid; }
.left, .middle { float: left; }
.left { width: 100px }
<div id="wrapper">
<div class="left">100px</div>
<div class="middle">Auto width, given by contents</div>
<div class="right">Remaining space</div>
</div>
Flexbox can do that.
Support is IE10 and up.
JSfiddle Demo
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
#container {
height: 100%;
display: flex;
flex-direction: column;
}
#top {
background-color: lightgreen;
}
#bottom {
background-color: lightblue;
flex: 1;
}
<div id="container">
<div id="top">green box variable height</div>
<div id="bottom">blue box no longer overflows browser window</div>
</div>
I'm looking for something simple and portable. In the same way a CSS
property can be easily applied across documents, I'm looking for
something similar in terms of ease-of-application for this function.
... isolated fix is preferred.
Horizontal:
This can be achieved using CSS only. As you do not prefer a flex layout solution, the next best bet would be a table layout.
A simple CSS snippet which you could drop into your project (and be done with) would look like this:
div.flexh {
display: table; box-sizing: border-box; padding: 0; margin: 0;
}
div.flexh > div {
display: table-cell; width: auto;
box-sizing: border-box; vertical-align: middle;
}
div.flexh > div:first-child {
/* Override your custom styling below */
min-width: 75px; width: 75px; max-width: 75px;
}
div.flexh > div:last-child { width: 100%; }
You can then add your site-specific styling to this base CSS as per site requirements. Like, nowrap etc.
Two apparent advantages of this solution are:
You do not need to change your markup and also do not need to decorate all children with classes. Just apply the class flexh to your parent div and that would be it.
Minimal Markup Required:
<div class="flexh">
<div>...</div>
<div>...</div>
<div>...</div>
</div>
You are not limited to just three columns. You could have as many columns as need be. The first one will have fixed width, the last one will be flexible, and all the columns in-between would get content-based widths.
Demo Fiddle: http://jsfiddle.net/abhitalks/qqq4mq23/
Demo Snippet:
div.flexh {
display: table; box-sizing: border-box; padding: 0; margin: 0;
/* Override your custom styling below */
width: 80%; border: 2px solid black;
border-right: 2px dashed black;
font-size: 1em;
}
div.flexh > div {
display: table-cell; width: auto;
box-sizing: border-box; vertical-align: middle;
/* Override your custom styling below */
background-color: lightgreen; border: 1px solid #ddd;
padding: 15px 5px;
}
div.flexh > div:first-child {
/* Override your custom styling below */
min-width: 75px; width: 75px; max-width: 75px;
background-color: orange;
}
div.flexh > div:last-child {
width: 100%;
/* Override your custom styling below */
background: skyblue;
}
<div class="flexh">
<div>75px Fixed Width</div>
<div>Variable Content Width</div>
<div>Flexible Remaining Width</div>
</div>
<hr/>
<div class="flexh">
<div>75px Fixed Width</div>
<div><img src='//placehold.it/128x48/66c' /></div>
<div>Flexible Remaining Width</div>
</div>
<hr/>
<div class="flexh">
<div>75px Fixed Width</div>
<div>Variable TextWidth</div>
<div>
<img src='//placehold.it/128x48/66c' />
<p>Variable ContentWidth</p>
</div>
<div>Flexible Remaining Width</div>
</div>
Vertical:
This is a bit tricky to achieve without flex layout. A table layout would not work here mainly because, the table-row would not keep a fixed height as required by your use-case. The height on a table-row or table-cell is only an indicative of the minimum height required. If the space is constrained, or the content exceeds the available space, then the cell or row will increase its height depending on the content.
As per the specs here: http://www.w3.org/TR/CSS21/tables.html#height-layout
The height of a 'table-row' element's box is calculated once the user
agent has all the cells in the row available: it is the maximum of the
row's computed 'height', the computed 'height' of each cell in the
row, and the minimum height (MIN) required by the cells...
...the height of a cell box is the minimum height required by the
content
This effect can be seen here: http://jsfiddle.net/abhitalks/6eropud3/
(Resize the window pane and you will see that the first row will increase in height as the content cannot be fit into the specified height, hence defeating the purpose)
Therefore, you can restrict the height indirectly either using inner markup like a div element, or let go of the table-layout and calculate the height for the flexible one. In your use-case, you prefer not to change the markup, hence I am not proposing an inner markup.
The best-bet here would be to use the time-tested model of plain block-level divs with the height of the flexible one to be calculated. As you have already discovered that it is not possible with CSS, you will need a small JavaScript snippet to do that for you.
A simple JavaScript snippet (no jQuery) which you could wrap in a window.load and drop into your project (and be done with) would look like this:
var flexv = document.querySelectorAll('div.flexv');
/* iterate the instances on your page */
[].forEach.call(flexv, function(div) {
var children = [].slice.call(div.children), // get all children
flexChild = children.splice(-1, 1), // get the last child
usedHeight = 0, totalHeight = div.offsetHeight;
children.forEach(function(elem) {
usedHeight += elem.offsetHeight; // aggregate the height
});
/* assign the calculated height on the last child */
flexChild[0].style.height = (totalHeight - usedHeight) + 'px';
});
The CSS snippet is more or less like the horizontal one, sans table layout, which also you could just drop into your project and just add the additional site-specific styling. Minimal markup required remains the same.
Demo Fiddle 2: http://jsfiddle.net/abhitalks/Ltcuxdwf/
Demo Snippet:
document.addEventListener("load", flexit);
function flexit(e) {
var flexv = document.querySelectorAll('div.flexv');
[].forEach.call(flexv, function(div) {
var children = [].slice.call(div.children),
flexChild = children.splice(-1, 1),
usedHeight = 0, totalHeight = div.offsetHeight;
children.forEach(function(elem) {
usedHeight += elem.offsetHeight;
});
flexChild[0].style.height = (totalHeight - usedHeight) + 'px';
});
}
div.flexv {
display: inline-table; box-sizing: border-box; padding: 0; margin: 0;
overflow: hidden;
/* Override your custom styling below */
height: 320px; width: 20%; border: 1px solid black; font-size: 1em;
margin: 8px;
}
div.flexv > div {
display: block; height: auto; box-sizing: border-box;
overflow: hidden;
/* Override your custom styling below */
background-color: lightgreen; border: 1px solid #ddd;
padding: 5px 15px;
}
div.flexv > div:first-child {
/* Override your custom styling below */
min-height: 36px; height: 36px; max-height: 36px;
background-color: orange;
}
div.flexv > div:last-child {
height: 100%;
/* Override your custom styling below */
background: skyblue;
}
<div class="flexv">
<div>36px Fixed Height</div>
<div>Variable Content Height</div>
<div>Flexible Remaining Height</div>
</div>
<div class="flexv">
<div>36px Fixed Height</div>
<div><img src='//placehold.it/64x72/66c' /></div>
<div>Flexible Remaining Height</div>
</div>
<div class="flexv">
<div>36px Fixed Height</div>
<div>Variable Text Height</div>
<div>
<img src='//placehold.it/72x48/66c' />
<p>Variable Content Height</p>
</div>
<div>Flexible Remaining Height</div>
</div>
Note: As pointed out by #LGSon, the display: inline-table used for the demo does not play well with Firefox. This is only for a demo and should be replaced by either block or inline-block as per your use-case.
Updated
As I commented earlier, and besides flex, this is also solvable using display: table and here is a fiddle demo I made showing that.
If a fixed top also were required for the vertical demo, here is an update of my original display:table version: fiddle demo
Sometimes I haven't been able (or didn't want) to use either flex nor tables, and I have, on and off, looked into making use of css calc() and css attr().
Both come short though, as calc() can only use +-*/ and attr() can only return a string value, which can't be computed by calc().
My suggestion, using plain javascript, is based on that these 2 methods, at some point, might be extended so we can make better use of them.
This is how I would like see them work;
width: calc(100% - attr(this.style.left))
but as they don't, and I can't add it to my css either as it wouldn't validate properly (might even break the parsing, who knows) I added a variant as an attribute on the element instead, with some quirks to make it easier to compute.
And in this case (the 2 demos) it looks like this:
//height
<div id="bottom" data-calcattr="top,height,calc(100% - toppx)">...</div>
//width
<div class="box right" data-calcattr="left,width,calc(100% - leftpx)">...</div>
Together with below script, which by no means is fully developed/tested on all property combinations, it does adjust the div's size.
In short, when runned, it take the attribute, split it into an array, take the first item value as from which property to read, the second to which property to set and the third to which the read value gets inserted/replaced and assigned to the property to be set (hmmm, still working on a better way to express this, but hopefully the script is clear enough with whats going on).
Here is a fiddle showing both the height and width demo, integrated, making use of the same script.
function calcattr() {
var els = document.querySelectorAll('[data-calcattr]');
for (i = 0; i < els.length; i++) {
var what = els[i].getAttribute('data-calcattr');
if (what) {
what = what.split(',');
var rect = els[i].getBoundingClientRect();
var parentrect = els[i].parentNode.getBoundingClientRect();
var brd = window.getComputedStyle(els[i].parentNode,null).getPropertyValue('border-' + what[0] + '-width');
what[2] = what[2].replace(what[0],parseInt(rect[what[0]]-parentrect[what[0]]) - parseInt(brd));
els[i].setAttribute("style", what[1] + ":" + what[2]);
}
}
}
IN CSS
Although I've never tried it, I believe that this would work:
.top {
height:13px;
}
.main {
height:calc(100% - var(height));
}
http://www.creativebloq.com/netmag/why-you-need-use-css-variables-91412904
IN SASS
$top_height: 50px
.main {
height: calc(100% - $top_height)
}
Sass Variable in CSS calc() function
In both cases on container css you should put:
#container {
overflow: hidden;
}
But, it will hide the information that overflows the container. I think that is the point, since you put white-space: nowrap; it means that you don't want to change the height, so you have to hide the text that can't fits the container.

Categories

Resources