-
-
Save easierbycode/24acdbcd3f033c65b3a7906abc733dc0 to your computer and use it in GitHub Desktop.
<responsive-element> custom element for enabling container/element queries
This file contains hidden or 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 hidden or 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