FireboxFlexfox-Dynamic
Showcases a bug in firefox flexbox rendering when combined with absolute positioning.
by Luke May
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<!-- ================================================== -->
<!-- knockout template -->
<!-- ================================================== -->
<script type="text/html" id="flex">
<span class="label small-font" data-bind="
text: label
">
</span>
<div class="child">
<!-- ko foreach: child -->
<div class="outer" data-bind="
template: 'flex'
">
</div>
<!-- /ko -->
</div>
<div class="overlay">
</div>
</script>
<!-- ================================================== -->
<!-- Html -->
<!-- ================================================== -->
<div class="app">
<input class="select-children" type="number" data-bind="
value: nestedNumber
"></input>
<div class="outer" data-bind="
template: {
name: 'flex',
data: root
}
">
</div>
</div>
CSS
* {
word-wrap: break-word;
overflow-wrap: break-word;
box-sizing: border-box;
min-width: 0px;
min-height: 0px;
}
body {
height: 100%;
width: 100%;
position: absolute;
margin: 0;
padding: 0;
display: flex;
align-items: stretch;
}
.app {
outline: 1px solid black;
background-color: #ddd;
padding: 0 10px 0 10px;
/* sizing and alignment */
display: flex;
flex-direction: column;
align-items: stretch;
flex: 1 1 10px;
}
.select-children {
width: 100px;
}
/* Knockout Template CSS */
.outer {
background-color: #aaa;
padding: 1px;
outline: solid 1px;
display: flex;
flex-direction: column;
flex: 1 1 10px;
align-items: stretch;
justify-content: space-around;
position: relative;
}
.label {
background-color: #eee;
padding: 1px;
display: flex;
flex: 0 0 8px;
align-items: stretch;
justify-content: space-around;
}
.small-font {
font-size: 6px;
}
.child {
background-color: #ccc;
padding: 1px;
width: auto;
height: auto;
display: flex;
flex-direction: row;
flex: 1 1 50px;
align-items: stretch;
justify-content: space-around;
overflow: auto;
}
.overlay {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
border-top-width: 1px;
border-top-style: dotted;
border-top-color: blue;
border-bottom-width: 1px;
border-bottom-style: dotted;
border-bottom-color: red;
}
JavaScript
function createVerticalLabel (label) {
var spaced = "";
_.each(label+"", function (val) {
spaced += val + " ";
});
return spaced;
}
var startingNestedNumber = 5;
var KoViewModel = function () {
var self = this;
self.nestedNumber = ko.observable(startingNestedNumber);
self.root = ko.observable(new FlexViewModel(1, self.nestedNumber));
self.usePercent = ko.observable(false);
self.nestedNumber.subscribe(function () {
self.root().updateDepth();
});
};
var FlexViewModel = function (num, nestedNumberObs) {
var self = this;
self.number = num;
self.nestedNumber = nestedNumberObs;
var label = (self.number % 10 === 0) ? createVerticalLabel(self.number) : undefined;
self.label = ko.observable(label);
self.child = ko.observable();
self.addChild = function() {
if (!self.child()) {
self.child(new FlexViewModel(self.number+1, self.nestedNumber));
}
};
self.updateDepth = function () {
// console.log("updateDepth: " + self.number + " out of " + self.nestedNumber());
if (self.number < self.nestedNumber()) {
self.addChild();
self.child().updateDepth();
return;
}
self.child(undefined);
}
};
var koViewModel = new KoViewModel();
var domBody = $('body')[0];
ko.applyBindings(koViewModel, domBody);
koViewModel.root().updateDepth();