Reputation: 136074
I have a layout with a top section which can grow in height, and a content section below which contains a chart. The basic HTML structure can be characterized as:
<div class="wrapper">
<div class="top">
<span class="box">Box 0</span>
<span class="box new">
<button>+</button>
</span>
</div>
<div id="chart">
Chart
</div>
</div>
Each box
element is a fixed width and height, and is a fluid design so that as the boxes cannot fit onto the same line, they wrap round to the next, making their container (top
) grow.
Here is an interactive demo at this stage: http://jsfiddle.net/d1d6bwbc/ where you can see that the wrapper
is 100% width & height (red border). The top
has a magenta border, and grows as the boxes need to wrap and the chart
has a blue border.
I am trying to make that chart
element fill 100% of the remaining height in wrapper
.
Here is my css so far
body{margin:0}
.wrapper{
position:absolute;
border:1px solid red;
height:calc(100% - 2px); /* account for border in this example */
width:calc(100% - 2px); /* account for border in this example */
}
.top{
border: 1px solid magenta;
padding-bottom:5px
}
#chart{
border: 1px solid blue;
/* style chart to fill 100% of wrapper
}
I have tried numerous css hacks and tricks, such as those found in this question and this one too but they do not seem to work on my layout.
I have complete control over the layout so if my markup requires some work that will be fine, but a simple way to achieve a fill on that chart
element is what I'm after.
Upvotes: 1
Views: 1329
Reputation: 78676
Looks like a perfect case for CSS table layout. Set the wrapper as table
, top and bottom box as table-row
, and the bottom box with height:100%
that pushes the top box to its minimal height to fit the content inside.
function ViewModel() {
var self = this;
self.boxes = ko.observableArray([new Box(0)]);
self.addBox = function () {
self.boxes.push(new Box(self.boxes().length));
}
}
function Box(index) {
self.text = "Box " + index;
}
ko.applyBindings(new ViewModel())
html, body {
height: 100%;
margin: 0;
}
.wrapper {
display: table;
border-collapse: collapse;
border: 1px solid red;
box-sizing: border-box;
height: 100%;
width: 100%;
}
.top {
border: 1px solid magenta;
display: table-row;
}
#chart {
border: 1px solid blue;
display: table-row;
height: 100%;
}
.box {
width: 150px;
height: 50px;
border: 2px solid black;
display: inline-block;
vertical-align: top;
margin: 5px;
}
.box.new {
border: 1px dashed black;
}
.box.new button {
display: inline-block;
width: 100%;
height: 100%;
text-align: center;
font-size: 3em;
border: none;
background: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="wrapper">
<div class="top">
<!-- ko foreach:boxes -->
<span class="box" data-bind="text:text">
</span>
<!-- /ko -->
<span class="box new">
<button data-bind="click:addBox">+</button>
</span>
</div>
<div id="chart">
Chart
</div>
</div>
http://jsfiddle.net/d1d6bwbc/4/
Upvotes: 2
Reputation: 1169
I am not sure if this behavior is achievable via pure CSS . But it is easy to create using javascript. I've added this JS to your example
var Fill = function (){
var top =document.getElementById("top").offsetHeight;
var wrapper =document.getElementById("wrapper").clientHeight;
document.getElementById("chart").setAttribute("style","height:"+(wrapper-top-1)+"px");
}
var addEvent = function(elem, type, eventHandle) {
if (elem == null || typeof(elem) == 'undefined') return;
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
} else {
elem["on"+type]=eventHandle;
}
};
addEvent(window, "resize", Fill);
Fill();
and also edited the addBox function to fire the event
self.addBox = function(){
self.boxes.push(new Box(self.boxes().length));
Fill();
}
I also Had to add id's to top
and wrapper
for this example but you can use class obviously.
Here is the working Fiddle
Upvotes: 1