<html>
<head>
<script src="https://rawgithub.com/ai/autoprefixer-rails/master/vendor/autoprefixer.js"></script>
<meta name="description" content="pull off stack css">
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1">
<title>pull off stack css</title>
<style type="unprocessed" id="AutoprefixerIn">%css%</style>
<style id="AutoprefixerOut"></style>
<script>
AutoprefixerSettings = { browsers: ['last 2 versions'] };
document.getElementById("AutoprefixerOut").innerHTML = autoprefixer.process(document.getElementById("AutoprefixerIn").innerHTML, AutoprefixerSettings).css;
</script>
</head>
<body>
<div class="nav"></div>
<div class="stacks">
<div class="stack">
<div class="stack-intro">intro</div>
<div class="stack-pages">
<div class="stack-page">page 1</div>
<div class="stack-page">page 2</div>
<div class="stack-page stack-page--has-fixed">
<div class="stack-page-fixed">
<div class="stack-page-fixed-content">
<div style="text-align: right"><a href="#">page</a> 3 fixed</div>
</div>
</div>
<div class="stack-page-content">
<span>page 3</span>
</div>
</div>
<div class="stack-page">page 4</div>
<div class="stack-page">page 5</div>
</div>
<div class="stack-after">rest of stuff in site</div>
</div>
</div>
</body>
</html>
@import url('https://necolas.github.io/normalize.css/7.0.0/normalize.css');
:root {
--viewportHeight: 100vh;
--navHeight: 3rem;
/* should also make variant class for fixed foot */
--stackHeight: calc(var(--viewportHeight) - var(--navHeight));
}
*,
*::before,
*::after {
box-sizing: inherit;
flex-shrink: 0;
flex-shrink: 0;
}
html {
box-sizing: border-box;
}
.nav {
position: fixed;
top: 0;
left: 0;
right: 0;
height: var(--navHeight);
background: red;
z-index: 9999;
}
.stack > :first-child {
margin-top: var(--navHeight);
}
/* only use this if there is 'stack-after' block */
.stack::after {
content: '';
display: block;
height: var(--stackHeight);
visibility: hidden;
}
.stack-pages {
position: relative;
z-index: 999;
box-shadow: 0 -3px 1px rgba(0,0,0,.2);
}
.stack-page {
height: var(--stackHeight);
background: #f60 linear-gradient(to bottom, #f60, #f93);
position: sticky;
bottom: 0;
/* this would break fixed inner panel */
will-change: transform;
/* skin */
display: flex;
flex-flow: column;
justify-content: center;
border-bottom: 20px solid rgba(255,255,255,.1);
background-size: 100% calc(100% + 20px);
/* border: 1rem solid #fff; */
color: #fff;
padding: 1rem;
box-shadow: 0 3px 1px rgba(0,0,0,.2);
}
.stack-page--has-fixed {
/* really can't tell if this helps with the paint at all :/ */
will-change: initial;
}
/* used so that semantics of document sequence doesn't need to be flipped and using flex-flow: column-reverse on flex container */
.stack-page:nth-child(1) {z-index: 999;}
.stack-page:nth-child(2) {z-index: 998;}
.stack-page:nth-child(3) {z-index: 997;}
.stack-page:nth-child(4) {z-index: 996;}
.stack-page:nth-child(5) {z-index: 995;}
.stack-page:nth-child(6) {z-index: 994;}
.stack-page:nth-child(7) {z-index: 993;}
.stack-page:nth-child(8) {z-index: 992;}
.stack-page:nth-child(9) {z-index: 991;}
/* ... */
/* normal stack is using reveal */
.stack-pages--wipe {
box-shadow: 0 3px 1px rgba(0,0,0,.2);
}
.stack-pages--wipe .stack-page {
top: 0;
/* must set bottom auto, or some browsers try to stick it */
bottom: auto;
z-index: auto;
box-shadow: 0 -3px 1px rgba(0,0,0,.2);
}
.stack-page-content {
position:relative;
z-index:1;
pointer-events: none;
transform: translate3d(0,0,0);
}
.stack-page-fixed {
clip: rect(auto,auto,auto,auto);
clip-path: content-box;
clip-path: polygon(0% 100%, 0% 0%, 100% 0%, 100% 100%);
z-index: 0;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
pointer-events: none;
}
.stack-page-fixed-content {
position: fixed;
top: var(--navHeight);
height: var(--stackHeight); bottom: 0;
left: 0;
right: 0;
/* set to match border on page */
border-bottom: 20px solid transparent;
padding: calc(1rem + 20px);
transform: translate3d(0,0,0);
display: flex;
flex-direction: column;
justify-content: center;
align-items: stretch;
/* height: calc(var(--stackHeight) - 20px); */
/* left: 50%; */
background: url('//placekitten.com/456/678') center / cover;
}
.stack-page-fixed-content > *,
.stack-page-content > * {
pointer-events: auto;
}
.stack-intro {
height: var(--stackHeight);
background: #09f;
position: sticky;
top: var(--navHeight);
/* if nav is transparent and/or movable and want initial intro/page to show through/behind, change here to offset flow/stick */
}
.stack-after {
position: sticky;
top: var(--navHeight);
min-height: var(--stackHeight);
margin-top: calc(-1 * var(--stackHeight));
/* skin */
/* padding-top only demo pushin text to bottom */
padding-top: calc(var(--stackHeight) - 1.25em);
min-height: calc(1.875 * var(--stackHeight));
background: #ddd;
}
/* garbage feeing with proximity, but wouldnt want to use manditory because of free scrolling after the stack pages end */
@supports (scroll-snap-type: y proximitys) {
html, body,
.stacks {
scroll-behavior: smooth;
scroll-snap-type: y proximity;
}
/* sentinel nodes that have since been removed */
.stack-stick {
display: block;
scroll-snap-align: start;
}
}
/* this tries to isolate mobile browsers that resize on scroll, and would be cool applying this to all browsers, but if stacks is the scrolling node on desktop, it makes pointer-events on the fixed block inside a stack-page not scroll the stacks element itself */
/* in other words, on desktop you must scroll the html/body in order for scrolling to work on top of the fixed inner pages */
/* this is suuuuuubpar for hasFixed pages because pointer-events for the scrolling context are completely lost, so clickable/scrollable are completely at odds. But if you ARE NOT USING FIXED then feel free to use this non viewport scroller */
@supports (overflow-scrolling: touch) or (display:block-) {
html,
body {
height: var(--stackHeight);
overflow: hidden;
}
.stacks {
position: absolute;
top: var(--navHeight);
left: 0;
right: 0;
height: var(--stackHeight);
overflow-scrolling: touch;
overflow-x: hidden;
overflow-y: auto;
}
.stack > :first-child {
margin-top: 0;
top: 0;
}
.stack-after {
top: 0;
}
}
@media
(max-height:20em),
(max-width:20em),
(max-height:30em) and (max-aspect-ratio: 3/4) {
.stack-page-fixed-content,
.stack-intro,
.stack-page,
.stack-after {
position: relative;
height: auto;
min-height: var(--stackHeight);
}
.stack > :first-child {
top: auto;
}
.stack-page-fixed-content {
position: static;
}
.stack-after {
margin-top: 0;
top: 0;
}
.stack::after {
display: none;
}
}
// refactored this to not need resize, but just finds vh value in px and sees if it doesn't match window.innerHeight, then setting value to be % of vh
// 100vh = 500, w.iH = 400, --v = 80vh
// all none resize/scrolling browsers will stay 100vh, so resize should be handled
function setHeight() {
var HTML = document.documentElement;
var heightEl = document.createElement('div');
heightEl.style.visibility = 'hidden';
heightEl.style.position = 'absolute';
heightEl.style.height = '100vh';
HTML.appendChild(heightEl);
var heightElHeight = window.getComputedStyle(heightEl).height;
var ratioHeight = window.innerHeight / parseInt(heightElHeight,10);
if (ratioHeight !== 1) {
var newHeight = (ratioHeight * 100) + 'vh';
HTML.style.setProperty('--viewportHeight', newHeight);
}
HTML.removeChild(heightEl);
}
function ripstop(el) {
el.addEventListener('touchstart',function(){
var fromTop = el.scrollTop;
var fromBot = el.scrollHeight - el.clientHeight - fromTop;
if (fromBot === 0) {
el.scrollTop = el.scrollHeight - el.clientHeight - 1;
return;
} else if (fromTop > 0) {
return;
}
el.scrollTop = 1;
});
};
document.addEventListener('DOMContentLoaded', function() {
setHeight();
var isTouch = CSS.supports('( -webkit-overflow-scrolling: touch )');
if (isTouch){
ripstop(document.querySelector('.stacks'));
}
});
window.addEventListener("orientationchange", function() {
setHeight();
});
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |