Skip to content

Instantly share code, notes, and snippets.

@xem
Created November 5, 2013 10:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xem/7316939 to your computer and use it in GitHub Desktop.
Save xem/7316939 to your computer and use it in GitHub Desktop.
A Pen by Secret Sam.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>POC</title>
<link rel=stylesheet href=style.css>
</head>
<body class="info">
<div class="row header">
<div class="col">
<h1><button onclick="this.insertAdjacentHTML('afterEnd', 'title title title title title title')">More</button>title title title title title</h1>
<h2><button onclick="this.insertAdjacentHTML('afterEnd', 'subtitle subtitle subtitle subtitle subtitle subtitle ')">More</button>subtitle subtitle subtitle subtitle</h2>
</div>
</div>
<div class="row content layout-remaining-height">
<div class="col h100 media">
<div class="table">
<div class="td middle">
<div class="layout-remaining-height layout-fit-to-children illustration">
<h3 id="legend" >
<p><button onclick="this.insertAdjacentHTML('afterEnd', 'label label label ')">More</button>label label</p>
</h3>
<img id="image" class="layout-remaining-height layout-fit-to-parent" data-layout-fit-to-parent-ref="4" data-layout-remaining-height-width-auto=true src="//placehold.it/200x200">
<h4 id="caption" >
<p><button onclick="this.insertAdjacentHTML('afterEnd', 'caption caption caption ')">More</button>caption caption</p>
</h4>
</div>
</div>
</div>
</div><!--
--><div class="col h100 text">
<div class="table">
<div class="td middle">
<p>
<button onclick="this.insertAdjacentHTML('afterEnd', 'bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla ')">More</button>bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
</p>
</div>
</div>
</div>
</div>
<div class="row footer">
<div class="col">
<p>
<button onclick="this.insertAdjacentHTML('afterEnd', 'bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla ')">More</button>bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
</p>
</div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="layouter.js"></script>
</body>
</html>
// Debug
onhashchange = hashchange = function () {
if (window.location.hash.indexOf("dev") > -1) {
$("body").addClass("dev");
} else {
$("body").removeClass("dev");
}
}
hashchange();
var layoutEngine = (function () {
var $body = $("body");
var rhClass = ".layout-remaining-height";
var csmhClass = ".layout-children-same-max-height";
var ftpClass = ".layout-fit-to-parent";
var ftcClass = ".layout-fit-to-children";
var qsNotClass = function (cssClass) {
return ":not(" + cssClass + ")";
};
///
var passRemainingHeight = function () {
// HANDLES HEIGHTS
var ordered = $(rhClass)
.sort(function (a, b) {
var a = $(a);
var aParents = a.parents();
a.data("layout-deepness", aParents.length);
var b = $(b);
var bParents = b.parents();
a.data("layout-deepness", bParents.length);
return aParents.length > bParents.length;
});
//console.log(ordered);
ordered
.each(function (i, v) {
var $this = $(v);
var parent = $this.parent();
//console.group("layouting", $this[0]);
var parentRemainingHeight = (function () {
var parentRemainingHeight = parent.height();
//console.group("parent remaining height", parentRemainingHeight);
parent.children(qsNotClass(rhClass)).each(function (i, v) {
var $this = $(v);
var outerH = $this.outerHeight(true);
//console.log("parent", $this[0], outerH);
parentRemainingHeight -= outerH;
});
//console.log("final remaining height", parentRemainingHeight);
//console.groupEnd();
return parentRemainingHeight;
})();
// get ancestors until we hit a .remaining-height and excludes it
//console.group("computing parents margins (exclugind rh)");
var ancestors = $this.parents(qsNotClass(rhClass));
var ancestorsHeightMargins = $this.getHeightMargins();
var ancestorsToHandle = [];
ancestors.each(function (i, v) {
var $this = $(v);
var margins = $this.getHeightMargins();
//console.log("parent margins", $this[0], margins);
ancestorsHeightMargins += margins;
});
//console.groupEnd();
var height = parentRemainingHeight - ancestorsHeightMargins - 2;
var currentHeight = $this.height();
var currentComparableHeight = height - $this.getHeightMargins();
//console.log("final height", height);
//console.groupEnd();
$this.setOuterHeight(height).addClass("layout-done");
if ($this.data("layout-remaining-height-width-auto")) {
$this.width("auto");
}
});
};
var passChildrenSameMaxHeight = function () {
// HANDLES HEIGHTS
// apply same max height on direct children
var maxHeight = null;
$(csmhClass)
.each(function (i, v) {
var $this = $(v);
var children = $this.children();
var maxHeight = null;
children
.each(function (i, v) {
var $this = $(v);
var height = $this.outerHeight();
if (isNaN(maxHeight) || height > maxHeight) {
maxHeight = height;
}
})
.setOuterHeight(maxHeight);
})
};
var passFitToParents = function () {
// HANDLES WIDTHS
//only for medias ?
//console.group("passFitToParents");
$(ftpClass).each(function (i, v) {
var $this = $(v);
var parentRefData = $this.data("layout-fit-to-parent-ref");
var parentRef = null;
if (isNaN(parentRef)) {
parentRef = $this.parents(parentRefData);
} else {
parentRef = $($this.parents()[parentRefData - 1]);
}
var parentWidth = parentRef.width();
var ancestorsMargins = $this.parentsUntil(parentRef).getWidthMargins();
var currentWidth = $this.width();
var width = parentWidth - ancestorsMargins;
var currentWidthSuperiorWidth = currentWidth > width
if (currentWidthSuperiorWidth) {
$this.setOuterWidth(width);
$this.height("auto");
}
});
//console.groupEnd();
};
var passFitToChildren = function () {
// HANDLES HEIGHTS
$(ftcClass).each(function (i, v) {
var $this = $(v);
var childrenHeight = 0;
$this.children().each(function (i, v) {
var $this = $(v);
childrenHeight += $this.outerHeight(true);
});
$this.setOuterHeight(childrenHeight);
});
};
var layoutingPasses = [passRemainingHeight, passChildrenSameMaxHeight, passFitToParents, passFitToChildren];
var layoutEngine = function () {
$body.height(document.documentElement.clientHeight);
for (var i in layoutingPasses) {
layoutingPasses[i]();
}
};
return layoutEngine;
})();
// On load / resize: call the layout engine
onclick = // <-- this line is only for the POC!
onload = onresize = function () {
// Compute em size
$("body").css("font-size", $("body").width() / 100);
//setTimeout(layoutEngine, 0);
setTimeout(function () {
layoutEngine();
}, 0);
}
// Sets the height with value minus its margin so total outerHeight = value
$.fn.setOuterHeight = function (value) {
$(this).each(function (i, v) {
var $this = $(v);
$this.height(value - ($this.outerHeight(true) - $this.outerHeight()));
});
return this;
}
// Sets the width with value minus its margin so total outerWidth = value
$.fn.setOuterWidth = function (value) {
$(this).each(function (i, v) {
var $this = $(v);
$this.width(value - ($this.outerWidth(true) - $this.outerWidth()));
});
return this;
};
// returns the vertical margins (top + bottom)
$.fn.getHeightMargins = function () {
return this.outerHeight(true) - this.height();
}
// Returns the horizontal margins (left + right)
$.fn.getWidthMargins = function () {
var margins = 0;
if (this.length > 1) {
$(this).each(function (i, v) {
margins += $(v).getWidthMargins();
});
} else {
margins = this.outerWidth(true) - this.outerWidth();
}
return margins;
}
/* Reset */
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
body {
overflow-x: hidden;
overflow-y: auto;
font: normal 14px Arial;
min-width: 480px;
}
/* CSS grid */
.row:before, .row:after {
content: "";
display: table;
}
.row:after {
clear: both;
}
.col {
padding: 0 1.5em;
display: inline-block;
width: 100%;
vertical-align: top;
overflow-x: hidden;
overflow-y: auto;
}
/* Common classes */
.table, .td, .h100 {
height: 100%;
}
.table, .td {
width: 100%;
}
.table {
display: table;
}
.td {
display: table-cell;
}
.middle {
vertical-align: middle;
}
/** Debug **/
.dev .col {
border: 1px solid green;
padding: 2px;
}
.dev .row {
border: 1px solid red;
padding: 2px;
}
button {
float: right;
}
/* Common elements */
.header div {
width: 100%;
text-align: left;
padding: 1.5em;
background: #fff;
border: 1px solid #000;
}
img {
min-height: 3em;
}
/* Templates style */
.info .footer {
max-height: 15em;
overflow: auto;
}
.info .footer p {
margin: 2em;
padding: 1em;
background: #eee;
}
.info .content {
min-height: 15em;
text-align: center;
}
.info .col.media {
width: 40%;
}
.info .col.text {
width: 60%;
}
.info .illustration {
margin: 1.5em auto;
}
.moreabout .content {
overflow-x: hidden;
overflow-y: auto;
}
.moreabout .images {
width: 100%;
text-align: center;
}
.moreabout .images .col{
display: inline-block;
width: 20em;
height: 20em;
margin: 1em;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment