Ссылка на стандарт: www.w3.org/TR/2013/WD-shadow-dom-20130514
Итак, что же такое shadow DOM:
Shadow DOM (или теневая модель документа) — часть документа, реализующая инкапсуляцию в DOM дереве. Она (теневая модель) является частью документа и встраивается непосредственно внутрь страницы.
Для упрощения отладки shadow DOM, в хроме можно включить отображение в веб-инспекторе (Settings — General — Show shadow DOM).
Надо заметить, что в стандарте реализуемая инкапсуляция называется функциональной, поскольку shadow DOM встраивается в документ и является одной из многих его частей, работающих «независимо» (более-менее независимо) друг от друга. Соответственно, при проектировании реализации, нужно было установить функциональные границы в дереве документа, чтобы как-то оперировать с множеством таких «независимых» фрагментов. Для решения проблемы инкапсуляции, и была введена новая абстракция — shadow DOM, позволяющая создавать несколько DOM деревьев в пределах одного родительского дерева и был разработан документ, описывающий ее.
Дочернее дерево размещается внутри некоторого элемента на странице. Функциональные границы между главным деревом документа и теневым называются shadow boundaries (теневые границы). Элемент, который размещает в себе теневое дерево, называется shadow host, а корень теневого дерево, соответственно, называется shadow root.

Во время рендеринга shadow tree занимает место содержимого shadow host (элемента).
Пример реализации в chromium:

Для композиции потомков shadow host и shadow tree используются insertion points. Insertion points определяют местонахождение потомков shadow host в shadow tree. При рендеринге shadow tree потомки проецируются в это место. Механизм, определяющий какие потомки shadow host будут спроецированы в insertion point называется distribution.
Реализация:

::distributed(selector) — функциональный псевдо-элемент принимающий относительный селектор в качестве аргумента. Он представляет отношение между insertion point в shadow tree и элементом, перенесенным в insertion point.
Реализация (chrome canary only):
Один shadow host может вмещать в себя несколько shadow tree — они будут отображены в порядке их добавления. Такой набор деревьев называется shadow stack. Более «старый» shadow tree так же можно переносить в другой shadow tree посредством shadow insertion point.
Перепроецирование это ситуация, при которой первое shadow tree уже имеет insertion point, а второй shadow tree имеет shadow insetion point, при этом контент, взятый из shadow host сначала проецируется в первом shadow tree, а затем во втором.
Автор стандарта пишет:
В определенных ситуациях, автору shadow tree захочется назначить один или несколько элементов из shadow tree как стукртурную абстракцию, дающую дополнительную информацию о контенте shadow tree.
Что я понимаю как возможность использовать css селекторы вне shadow tree для доступа к элементам внутри него:
Некоторые события пропускаются через shadow boundary, некоторые нет. Исключение составляют mutation events — они вообще не должны возникать в shadow tree и, соответственно, переходить через shadow boundary. При прохождении события через shadow boundary у него меняется event.target для поддержания инкапсуляции.
Вот интересный пример:
События спроецированного элемента всплывают в shadow host, как-будто он все еще находится непосредственно внутри shadow host. События first-inner-element не всплывают в shadow host, в отличие от second-inner-element, который абсолютно спозиционирован и вынесен за пределы shadow host (при этом event.target сменился).
Есть два метода, позволяющие манипулировать стилями shadow tree:
shadowRoot.resetStyleInheritance (false by default)
Сбрасывает наследование стилей для shadow tree (стили снаружи не применяются на shadow tree).
shadowRoot.applyAuthorStyles (false by default)
Применяет стили авторского (главного) документа.
Итог
Можно сказать, что некоторой «инкапсуляции» для html не хватало. Это открывает большие возможности по созданию и шаблонизации различных, заранее подготовленных, виджетов на странице. Удивляет только отсутствие инкапсуляции JavaScript кода внутри виджетов, хотя мне казалось бы это довольно логичным.
Итак, что же такое shadow DOM:
Shadow DOM (или теневая модель документа) — часть документа, реализующая инкапсуляцию в DOM дереве. Она (теневая модель) является частью документа и встраивается непосредственно внутрь страницы.
Для упрощения отладки shadow DOM, в хроме можно включить отображение в веб-инспекторе (Settings — General — Show shadow DOM).
Надо заметить, что в стандарте реализуемая инкапсуляция называется функциональной, поскольку shadow DOM встраивается в документ и является одной из многих его частей, работающих «независимо» (более-менее независимо) друг от друга. Соответственно, при проектировании реализации, нужно было установить функциональные границы в дереве документа, чтобы как-то оперировать с множеством таких «независимых» фрагментов. Для решения проблемы инкапсуляции, и была введена новая абстракция — shadow DOM, позволяющая создавать несколько DOM деревьев в пределах одного родительского дерева и был разработан документ, описывающий ее.
Дочернее дерево размещается внутри некоторого элемента на странице. Функциональные границы между главным деревом документа и теневым называются shadow boundaries (теневые границы). Элемент, который размещает в себе теневое дерево, называется shadow host, а корень теневого дерево, соответственно, называется shadow root.

Во время рендеринга shadow tree занимает место содержимого shadow host (элемента).
Пример реализации в chromium:
<div id="shadow-host"></div>
var shadowHost = document.querySelector("#shadow-host"),
shadowRoot = shadowHost.webkitCreateShadowRoot();

Insertion points
Для композиции потомков shadow host и shadow tree используются insertion points. Insertion points определяют местонахождение потомков shadow host в shadow tree. При рендеринге shadow tree потомки проецируются в это место. Механизм, определяющий какие потомки shadow host будут спроецированы в insertion point называется distribution.
Реализация:
<div id="shadow-host">
<span>Hi shadow DOM!</span>
</div>
var shadowHost = document.querySelector("#shadow-host"),
shadowRoot = shadowHost.webkitCreateShadowRoot(),
content = document.createElement("content");
content.select = "span"; // выбираем все спаны из shadow host
shadowRoot.appendChild(content);

Псевдо-элемент ::distributed()
::distributed(selector) — функциональный псевдо-элемент принимающий относительный селектор в качестве аргумента. Он представляет отношение между insertion point в shadow tree и элементом, перенесенным в insertion point.
Реализация (chrome canary only):
<html>
<head>
<script>
function onLoad() {
var shadowHost = document.querySelector("#shadow-host"),
shadowRoot = shadowHost.webkitCreateShadowRoot();
shadowRoot.innerHTML = document.querySelector("template").innerHTML;
}
</script>
</head>
<body onload="onLoad()">
<div id="shadow-host">
<span>Hi shadow DOM!</span>
</div>
<template>
<style>
content::-webkit-distributed(span) {
color: red !important;
}
</style>
<content></content>
</template>
</body>
</html>
Один shadow host может вмещать в себя несколько shadow tree — они будут отображены в порядке их добавления. Такой набор деревьев называется shadow stack. Более «старый» shadow tree так же можно переносить в другой shadow tree посредством shadow insertion point.
<html>
<head>
<script>
function onLoad() {
var shadowHost = document.querySelector("#shadow-host"),
firstShadowRoot = shadowHost.webkitCreateShadowRoot(),
secondShadowRoot = shadowHost.webkitCreateShadowRoot();
firstShadowRoot.innerHTML = document.querySelector("#template-1").innerHTML;
secondShadowRoot.innerHTML = document.querySelector("#template-2").innerHTML;
}
</script>
</head>
<body onload="onLoad()">
<div id="shadow-host">
<span>Hi shadow DOM!</span>
</div>
<template id="template-1">
<div>root 1</div>
</template>
<template id="template-2">
<div>root 2</div>
<shadow></shadow>
</template>
</body>
</html>
Reprojection (перепроецирование)
Перепроецирование это ситуация, при которой первое shadow tree уже имеет insertion point, а второй shadow tree имеет shadow insetion point, при этом контент, взятый из shadow host сначала проецируется в первом shadow tree, а затем во втором.
<html>
<head>
<script>
function onLoad() {
var shadowHost = document.querySelector("#shadow-host"),
firstShadowRoot = shadowHost.webkitCreateShadowRoot(),
secondShadowRoot = shadowHost.webkitCreateShadowRoot();
firstShadowRoot.innerHTML = document.querySelector("#template-1").innerHTML;
secondShadowRoot.innerHTML = document.querySelector("#template-2").innerHTML;
}
</script>
</head>
<body onload="onLoad()">
<div id="shadow-host">
<span>Hi shadow DOM!</span>
</div>
<template id="template-1">
<div>root 1</div>
<content select="span"></content>
</template>
<template id="template-2">
<div>root 2</div>
<shadow></shadow>
</template>
</body>
</html>
Псевдо-элементы (в контексте shadow DOM)
Автор стандарта пишет:
In certain situations, the author of a shadow tree may wish to designate one or more elements from that tree as a structural abstraction that provides additional information about the contents of the shadow tree.
В определенных ситуациях, автору shadow tree захочется назначить один или несколько элементов из shadow tree как стукртурную абстракцию, дающую дополнительную информацию о контенте shadow tree.
Что я понимаю как возможность использовать css селекторы вне shadow tree для доступа к элементам внутри него:
<html>
<head>
<script>
function onLoad() {
var shadowHost = document.querySelector("#shadow-host"),
shadowRoot = shadowHost.webkitCreateShadowRoot();
shadowRoot.innerHTML = document.querySelector("template").innerHTML;
}
</script>
<style>
div::x-thumb {
width: 10px;
height: 10px;
background: black;
}
</style>
</head>
<body onload="onLoad()">
<div id="shadow-host"></div>
<template>
<div pseudo="x-thumb"></div>
</template>
</body>
</html>
События
Некоторые события пропускаются через shadow boundary, некоторые нет. Исключение составляют mutation events — они вообще не должны возникать в shadow tree и, соответственно, переходить через shadow boundary. При прохождении события через shadow boundary у него меняется event.target для поддержания инкапсуляции.
Вот интересный пример:
<html>
<head>
<script>
function onLoad() {
var shadowHost = document.querySelector("#shadow-host"),
shadowRoot = shadowHost.webkitCreateShadowRoot();
shadowRoot.innerHTML = document.querySelector("template").innerHTML;
shadowHost.addEventListener("mouseout", function(e) {
console.log("mouse out", e.target);
});
}
</script>
<style>
#shadow-host {
width: 100px;
height: 100px;
background: blue;
}
#outer-element {
width: 100%;
height: 20px;
background: red;
}
</style>
</head>
<body onload="onLoad()">
<div id="shadow-host">
<div id="outer-element"></div>
</div>
<template>
<div id="first-inner-element"></div>
<div id="second-inner-element"></div>
<content></content>
<style>
#first-inner-element {
width: 100px;
height: 20px;
background: green;
position: absolute;
top: 140px;
}
#second-inner-element {
width: 100px;
height: 20px;
background: black;
margin-bottom: 40px;
}
</style>
</template>
</body>
</html>
События спроецированного элемента всплывают в shadow host, как-будто он все еще находится непосредственно внутри shadow host. События first-inner-element не всплывают в shadow host, в отличие от second-inner-element, который абсолютно спозиционирован и вынесен за пределы shadow host (при этом event.target сменился).
Стили
Есть два метода, позволяющие манипулировать стилями shadow tree:
shadowRoot.resetStyleInheritance (false by default)
Сбрасывает наследование стилей для shadow tree (стили снаружи не применяются на shadow tree).
shadowRoot.applyAuthorStyles (false by default)
Применяет стили авторского (главного) документа.
<html>
<head>
<script>
function onLoad() {
var shadowHost = document.querySelector("#shadow-host"),
firstShadowRoot = shadowHost.webkitCreateShadowRoot();
var secondShadowRoot = shadowHost.webkitCreateShadowRoot();
secondShadowRoot.resetStyleInheritance = true;
secondShadowRoot.applyAuthorStyles = true;
firstShadowRoot.innerHTML = document.querySelector("#template-1").innerHTML;
secondShadowRoot.innerHTML = document.querySelector("#template-2").innerHTML;
}
</script>
<style>
* {
font-style: italic;
}
</style>
</head>
<body onload="onLoad()">
<div id="shadow-host"></div>
<template id="template-1">
<style>
* {
color: red;
font-weight: bold;
}
</style>
<div>root 1</div>
</template>
<template id="template-2">
<div>root 2</div>
<shadow></shadow>
</template>
</body>
</html>
Итог
Можно сказать, что некоторой «инкапсуляции» для html не хватало. Это открывает большие возможности по созданию и шаблонизации различных, заранее подготовленных, виджетов на странице. Удивляет только отсутствие инкапсуляции JavaScript кода внутри виджетов, хотя мне казалось бы это довольно логичным.