Sou DOM, Shadow DOM

Sou DOM, Shadow DOM

Shadow DOM é uma especificação (ainda em status de rascunho) que faz parte do recente trabalho Web Components da W3C, que é composto por mais 3 partes: templates, decorators e custom elements – falaremos mais sobre estes novíssimos recursos futuramente por aqui no Loop Infinito. Corrijam-me se eu estiver falando besteira, mas acredito que o Web Components será um trabalho estável apenas quem sabe num suposto HTML6.

Shadow DOM é simplesmente uma sub-árvore de elementos DOM que pode ser aninhada dentro de outro elemento (host). A diferença é que, quando um elemento qualquer possui uma shadow DOM, seus elementos filhos comuns não são renderizados, em vez disso, o conteúdo da shadow DOM que é renderizado.

Na verdade, a shadow DOM existe desde os primórdios da web, e sempre esteve presente em nossos navegadores para que a componentização viesse a se tornar possível. A novidade aqui é que este recurso agora torna-se acessível a nós, desenvolvedores. Agora vamos entender como funciona.

Visão estrutural

shadowhostchildchildchildchildchildchildchildchildchildshadowrootdocument treeSub-árvores shadow DOM

Como mencionei anteriormente, uma shadow DOM pode ser aninhada a qualquer elemento, chamaremos este elemento de host. E qualquer elemento (host) pode ter várias shadow DOMs (figura acima). No momento da renderização, o conteúdo dentro de host é substituído pelo conteúdo da shadow DOM (figura abaixo). Os lugares onde os elementos da sub-árvore shadow são inseridos em host são chamados de pontos de inserção. No exemplo abaixo, temos 2 pontos de inserção (os 2 filhos de shadow host).

shadowhostshadowchildshadowchildshadowchildshadowchildSub-árvoreshadow DOM

Encapsulamento faz todo o sentido

Uma das grandes razões para a implementação da Shadow DOM pelos navegadores é para poder manter seus widgets inalteráveis, isolando-os de todo tipo de acesso – ou seja, mantendo tudo dentro de uma caixa preta.

Sabe esses componentes de interface que usamos em nossas aplicações como <select> (combo box) e <input> dos tipos text, range, number, color, datetime etc? Pois bem, estes componentes não passam de elementos HTML estilizados com CSS de acordo com o estilo de cada plataforma, acredite. A grande diferença é o encapsulamento.

Por exemplo, sabemos que o elemento <input type="range"> se parece com o seguinte:

input range

O input range visivelmente é composto basicamente por 2 partes: uma trilha e um botão – o qual é possível deslizar pela trilha.

Sabemos que não temos acesso aos elementos internos do componente/widget, não podemos manipula-los e nem mesmo estiliza-los, justamente porque não temos acesso a shadow DOM do elemento. Para ilustrar este exemplo, suponha que tenhamos:

<input type="range" id="slider" />

Se tentarmos obter o primeiro elemento filho de #slider via JavaScript:

var slider = document.getElementsById( "slider" )
console.log( slider.firstChild ) // retorna null

Nada é retornado, mas como isto é possível, então? Isso é a shadow DOM em ação. Apenas precisamos incluir <input type="range"> em nosso código e o navegador se vira com o resto, ou seja, com a montagem estrutural e com a renderização do componente por completo.

Este tipo de coisa acontece muito, os componentes são encapsulados em apenas um elemento (definido no código) que age como uma caixa preta, mas o que rola por baixo dos panos é algo bem mais complexo.

Rolling Stones

O elemento <input type="range"> é bem simples em relação a outros, como por exemplo <audio> e <video>, que possuem controles de play/pause, volume, trilha, rewind, forward, display de tempo, etc. E no caso de <video>, ainda há o display de mídia (onde toca o vídeo) e um botão para tela cheia.

Mais liberdade

Imagine poder ter acesso aos elementos dos componentes e poder modificar as propriedades inerentes a apresentação de qualquer um deles. Isto se torna possível com a abertura da shadow DOM.

Quando o assunto é design de UI, quem nunca desejou poder alterar os estilos dos componentes, de modo que estes apareceriam sempre de forma igual independente de plataforma? Por exemplo, poder estilizar o player de vídeo mostrado acima com as cores da sua aplicação.

Tente você

Com o navegador Google Chrome é possível visualizar a shadow DOM de vários elementos de formulário pelo Web Inspector. As instruções para tornar isto possível estão neste post (em inglês).

Tentei usar a ShadowRoot API para implementar algum exemplo customizado de widget aqui no post, mas infelizmente esta API ainda não está disponível – nem nas versões mais novas do Google Chrome Canary e Webkit. Então, por enquanto ficaremos só na vontade, e assim que soubermos de algo, prometo fazer um post sobre criação de widgets com a Shadow DOM.

No próximo post falarei sobre estilização de widgets de formulário com CSS através de novos seletores e propriedades que permitem o alcance aos estilos da shadow DOM.

#15