Shadow DOM
Huh? What?
Light DOM vs Shadow DOM
Light DOM is what you use today.
Shadow DOM is what you will be using in the future.
Shadow DOM visually replaces existing Elements.
Hello World
<h3>Hello World</h3>
var heading = currentSlide.querySelector('h3')
var root = heading.createShadowRoot()
Shadow DOM is a sub-tree inside a DOM node
Like a mini-iframe that replaces an Element.
Light DOM
<h3>Light DOM</h3>
var heading = currentSlide.querySelector('h3')
var root = heading.createShadowRoot()
root.innerHTML = 'Shadow DOM'
Shadow DOM = view
HTML = model
You can inject your original content into the Shadow DOM
Light DOM
<a href="#" id="anchor">Light DOM</a>
var anchor = currentSlide.querySelector('#anchor')
var root = anchor.createShadowRoot()
root.innerHTML = '\
Shadow DOM\
'
How is this useful?
Remember the idea of semantic markup?
Decouple content from presentation.
HEADING
<font size="30px">HEADING</font>
CSS
Great on small scale.
Terrible on big scale.
<div class="Center-Container is-Table">
<div class="Table-Cell">
<div class="Center-Block">
</div>
</div>
</div>
.Center-Container.is-Table { display: table; }
.is-Table .Table-Cell {
display: table-cell;
vertical-align: middle;
}
.is-Table .Center-Block {
width: 50%;
margin: 0 auto;
}
But are divs & classes really 'semantic'?
divs + class abuse is about as good as we get in HTML4
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
Things are getting better
Progress on both ends of the spectrum
HTML5 gives us a lot more semantic elements to work with
<heading>Heading</heading>
<main>Content</main>
<aside>Sidebar</aside>
<footer>Footer</footer>
Reality: HTML5 can't save you from CSS
<div class="page-wrapper">
<div class="page-wrapper-inner">
<heading><span>Heading</span></heading>
<div class="main-wrapper">
<main>
<div class="wrapper">
Content
</div>
</main>
</div>
<aside>Sidebar</aside>
<footer><span>Footer</span></footer>
</div>
</div>
CSS Flexbox makes CSS more powerful for layouts
<body class="HolyGrail">
<header>...</header>
<div class="HolyGrail-body">
<main class="HolyGrail-content">...</main>
<nav class="HolyGrail-nav">...</nav>
<aside class="HolyGrail-ads">...</aside>
</div>
<footer>...</footer>
</body>
.HolyGrail {
display: flex;
min-height: 100vh;
flex-direction: column;
}
.HolyGrail-body {
display: flex;
flex: 1;
}
.HolyGrail-content {
flex: 1;
}
.HolyGrail-nav, .HolyGrail-ads {
flex: 0 0 12em;
}
.HolyGrail-nav {
order: -1;
}
When you need a div you need a div
Pseudo Elements :before :after
#example:before {
content: "";
display: block;
width: 100px;
height: 100px;
}
Shadow DOM
Hide non-semantic DOM in the Shadow DOM
Main Content
<main>Main Content</main>
// wrap main in a div
var main = currentSlide.querySelector('main')
var root = main.createShadowRoot()
root.innerHTML = '\
\
\
'
Use templates to keep things tidy
Main Content
<main>Main Content</main>
<template>
<div style="border: 1px solid;">
<content></content>
</div>
</template>
// wrap main in a div
var main = currentSlide.querySelector('main')
var template = currentSlide.querySelector('template')
var root = main.createShadowRoot()
root.appendChild(template.content)
Wrap different content
Heading
Content
<div class="body">
<heading>Heading</heading>
<main class="content">Content</main>
</div>
<template>
<style>
.green {
color: green;
}
.blue {
color: blue;
}
</style>
<div class="green">
<content select="heading"></content>
</div>
<div class="blue">
<content select=".content"></content>
</div>
</template>
var body = currentSlide.querySelector('.body')
var template = currentSlide.querySelector('template')
var root = body.createShadowRoot()
root.appendChild(template.content)
Hide style in the Shadow DOM
Specificity wars suck
Main Content
<main>Main Content</main>
.slide div main * {
color: blue;
}
body .slide div main * {
color: red;
}
Ignore the rest of the DOM
Main Content
<main>Main Content</main>
<template>
<style>
* {
color: red;
}
</style>
<content></content>
</template>
var main = currentSlide.querySelector('main')
var template = currentSlide.querySelector('template')
var root = main.createShadowRoot()
root.appendChild(template.content)
Shadow DOM elements are unaffected by existing page styles
Light DOM
Shadow DOM
<a href="#" id="anchor">Light DOM</a>
<template>
<a href="#">Shadow DOM</a>
</template>
a {
color: #B22D1A;
text-decoration: none;
}
var anchor = currentSlide.querySelector('#anchor')
var template = currentSlide.querySelector('template')
var root = anchor.createShadowRoot()
root.appendChild(template.content)
Applying page styles
Main Content
<main>Main Content</main>
<template>
<a href="#"><content></content></a>
</template>
var main = currentSlide.querySelector('main')
var template = currentSlide.querySelector('template')
root = main.createShadowRoot()
root.appendChild(template.content)
/* Toggle apply page styles */
root.applyAuthorStyles = !root.applyAuthorStyles
Inheriting Styles
Main Content
<main>Main Content</main>
<template>
<a href="#"><content></content></a>
</template>
var main = currentSlide.querySelector('main')
var template = currentSlide.querySelector('template')
root = main.createShadowRoot()
root.appendChild(template.content)
/* Toggle reset inherited styles */
root.resetStyleInheritance = !root.resetStyleInheritance
Allowing external styling
Main Content
<main id="content">Main Content</main>
<style>
#content::x-thumb {
background: green;
width: 10px;
height: 10px;
display: block;
}
</style>
var main = currentSlide.querySelector('main')
var template = currentSlide.querySelector('template')
var root = main.createShadowRoot()
var thumb = document.createElement('div');
thumb.part = 'x-thumb';
root.appendChild(thumb);
Styling Native Elements
<progress value="35" max="100"></progress>
progress.custom {
-webkit-appearance: none;
}
progress.custom::-webkit-progress-bar {
background: burlywood;
}
progress.custom::-webkit-progress-value {
background: coral;
}
progress = currentSlide.querySelector('progress')
progress.value += 5
progress.value %= 100
progress.classList.add('custom')
Styling native elements is crucial
Rebuilding native elements is awful.
You will get it wrong.
Many elements starting to expose their Shadow DOM
Browser Support
Evergreen Browsers, kinda.
- Chrome
- Canary
- Chrome Android
- Firefox
- Safari 6+
- Mobile Safari
- Internet Explorer 10+
Shadow DOM is what you will be using in the future.
Keep up or be left behind.
Questions?