Created
February 15, 2018 06:15
-
-
Save ebidel/3a42415ee1bb9d44020b159270382eba to your computer and use it in GitHub Desktop.
<responsive-element> custom element for enabling container/element queries
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- based on https://twitter.com/ebidel/status/933496242272747520 --> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<title><responsive-element></title> | |
<link rel="stylesheet" href="styles.css"> | |
</head> | |
<body> | |
<responsive-container id="container1"> | |
<div>move the <-- frame around or click-me</div> | |
</responsive-container> | |
<responsive-container small="400px" id="container2"> | |
<ul> | |
<li>one</li> | |
<li>two</li> | |
<li>three</li> | |
<li>four</li> | |
<li>five</li> | |
<li>six</li> | |
<li>seven</li> | |
<li>eight</li> | |
<li>nine</li> | |
<li>ten</li> | |
</ul> | |
</responsive-container> | |
<div id="container3"> | |
<div>right nav</div> | |
</div> | |
<script> | |
const ResizeObservableElement = (superclass) => class extends superclass { | |
static get observer() { | |
if (!this._observer) { | |
// Set up a single RO for all elements that inherit from this class. This | |
// has much better performance than creating a separate RO in every | |
// element instance. See https://goo.gl/5uLKZN. | |
this._observer = new ResizeObserver(entries => { | |
for (const entry of entries) { | |
// Custom event works for both node.onresize and node.addEventListener('resize') cases. | |
const evt = new CustomEvent('resize', {detail: entry, bubbles: false}) | |
entry.target.dispatchEvent(evt); | |
} | |
}); | |
} | |
return this._observer; | |
} | |
constructor() { | |
super(); | |
this.constructor.observer.observe(this); | |
} | |
}; | |
class ResponsiveContainer extends ResizeObservableElement(HTMLElement) { | |
static get is() { return 'responsive-container'; } | |
get mode() { return this.getAttribute('mode'); } | |
set mode(val) { | |
val ? this.setAttribute('mode', val) : this.removeAttribute('mode'); | |
} | |
constructor() { | |
super(); | |
this.smallSize = parseInt(this.getAttribute('small')) || 400; | |
// Component responds to it's own resizes. | |
this.addEventListener('resize', e => { | |
const w = e.detail.contentRect.width; | |
this.mode = w <= this.smallSize ? 'small' : 'large'; | |
}); | |
} | |
} | |
customElements.define(ResponsiveContainer.is, ResponsiveContainer); | |
// Main page can subscribe to component's resize updates too. | |
document.querySelector('#container2').addEventListener('resize', e => { | |
console.log(e.detail.contentRect.width, e.detail.contentRect.height); | |
}); | |
// Just a tester to see how component responds. | |
const c = document.querySelector('#container1'); | |
c.addEventListener('click', e => { | |
c.classList.add('off'); | |
setTimeout(() => c.classList.remove('off'), 2000); | |
}); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* { | |
box-sizing: border-box; | |
} | |
html, body { | |
height: 100vh; | |
margin: 0; | |
} | |
body { | |
display: flex; | |
font-family: sans-serif; | |
color: #455A64; | |
background: #fff; | |
} | |
ul { | |
list-style: none; | |
padding: 0; | |
width: 100%; | |
} | |
li { | |
background: #ffff; | |
padding: 16px; | |
margin: 8px; | |
} | |
#container1, #container2, #container3 { | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
reponsive-container { | |
display: block; | |
} | |
#container1 { | |
display: flex; | |
height: 100vh; | |
width: 300px; | |
background: #eee; | |
will-change: width; | |
transition: width 600ms ease-in-out; | |
} | |
#container1.off { | |
width: 0; | |
} | |
#container2 { | |
background: #ffcc00; | |
position: relative; | |
flex: 1; | |
overflow: auto; | |
min-width: 100px; | |
} | |
#container2::before { | |
font-weight: bold; | |
text-transform: uppercase; | |
background: blue; | |
padding: 8px; | |
position: absolute; | |
content: attr(mode); | |
top: 0; | |
right: 0; | |
transform: rotateZ(45deg) translate(65px, -35px); | |
width: 200px; | |
text-align: center; | |
color: white; | |
} | |
#container2[mode="large"] ul { | |
display: flex; | |
justify-content: center; | |
flex-wrap: wrap; | |
} | |
#container2[mode="large"] li { | |
width: 200px; | |
height: 200px; | |
} | |
#container3 { | |
background: #ccc; | |
min-width: 100px; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Demo: http://jsbin.com/vugacohufe/edit?html,css,output