JSFiddle - React, Tailwind, and code Playground
by Retsam19
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/bluebird/1.2.2/bluebird.js"></script>
<script type="text/html" id="flex">
<div class="label" data-bind="
text: label">
</div>
<div class="children">
<!-- ko foreach: {
data: children,
as: 'child'
} -->
<div class="outer" data-bind="
template: {
name: 'flex',
data: child
}
">
</div>
<!-- /ko -->
</div>
</script>
<div>
<h4>To see the rendering delay, open dev tools and resize viewport by sliding dev tools view divider quickly and repeatedly. In chrome there is no delay. In firefox version < 38 there is a delay due to inefficient rendering calculations.</h4>
<label>
Number of nested flex elements:
<input type="number" data-bind="
value: nestedNumber
"></input>
</label>
<br>
<label class="old-flex-toggle-label">
<input type="checkbox" data-bind="
checked: useOldFlex
"></input>
Use old mozilla prefixes (2009 -- display: -moz-box). This only has an affect if you're using Firefox version < 38.0 (red background on DOM body). You'll notice there is no longer a rendering delay, but the behavior is not exactly the same and the flexbox terminology is somewhat different.
</label>
<div>
<div class="outer">
<iframe data-bind="
iframe: {
name: 'flex',
data: root
}
"></iframe>
</div>
CSS
body {
background-color: #eee;
color: #222;
display: flex;
flex-direction: column;
height: 600px;
padding: 50px;
white-space: normal;
overflow-wrap: break-word;
word-wrap: break-word;
}
html[data-is-affected-firefox="true"] body {
background-color: red;
}
.old-flex-toggle-label {
display: none;
}
html[data-is-affected-firefox="true"] .old-flex-toggle-label {
display: inline;
}
.outer {
background-color: #aaa;
padding: 3px;
outline: solid 1px;
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: space-around;
flex: 1 1 100px;
}
html[data-use-old-flex="true"] .outer {
display: -moz-box;
-moz-box-orient: horizontal;
-moz-box-pack: justify;
-moz-box-align: stretch;
-moz-box-flex: 1;
}
.label {
background-color: #eee;
padding: 1px;
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: space-around;
flex: 0 0 8px;
}
html[data-use-old-flex="true"] .label {
display: -moz-box;
-moz-box-orient: vertical;
-moz-box-pack: justify;
-moz-box-align: stretch;
-moz-box-flex: 1;
}
.children {
background-color: #ccc;
padding: 3px;
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: space-around;
flex: 1 1 100px;
}
html[data-use-old-flex="true"] .children {
display: -moz-box;
-moz-box-orient: horizontal;
-moz-box-pack: justify;
-moz-box-align: stretch;
-moz-box-flex: 1;
}
JavaScript
var ua = navigator.userAgent;
var uaTokens = ua.split(' ');
var lastToken = uaTokens[uaTokens.length-1];
var isAffectedFirefox = false;
if (_.contains(lastToken, 'Firefox')) {
var li = lastToken.split('/');
// if user agent string says it's a firefox version under 38
// then we should use 2009 version of flexbox
isAffectedFirefox = parseFloat(li[li.length-1]) < 38;
}
if (isAffectedFirefox) {
$('html').attr('data-is-affected-firefox', isAffectedFirefox);
}
$('html').attr('data-use-old-flex', false);
var FlexViewModel = function (label, children) {
var self = this;
self.label = label + '';
self.children = children;
};
var ViewModel = function () {
var self = this;
self.nestedNumber = ko.observable(20);
self.useOldFlex = ko.observable(false);
self.useOldFlex.subscribe(function () {
$('html').attr('data-use-old-flex', self.useOldFlex());
});
self.root = ko.computed(function () {
var depth = self.nestedNumber();
rootChildren = _.range(depth).reduceRight(function (num, children) {
return [new FlexViewModel(children, num)];
}, []);
return new FlexViewModel("R", rootChildren);
});
};
ko.bindingHandlers.iframe = {
init: function(element, valueAccessor) {
function getTemplateId(value) {
return (typeof value === "object") ?
ko.unwrap(value.name) :
value;
}
function getData(value) {
return (typeof value === "object") && value.data ?
value.data :
ko.dataFor(element);
}
var value = valueAccessor();
//Get the template
var templateId = getTemplateId(value);
template = document.getElementById(templateId);
//Write the contents of the template to the iframe
element.contentDocument.open();
...