Shadow DOM系列4-樣式(續)

英文連接:Shadow DOM: Styles (cont.), 29 AUGUST 2013 on Web Components, Shadow DOMcss

昨天的博文裏咱們總體討論了設置 Shadow DOM 樣式的一些基本事項,但咱們僅僅觸及了一些皮毛。今天咱們緊接着上文繼續討論怎樣使用分佈節點(distributed nodes)以及怎樣將咱們的組件打通使外部可使用並自定義。html

在今天開始以前,我想要感謝 Eric Bidelman 的這篇介紹 Shadow DOM 樣式添加的宏文(能夠戳中文譯版)。本文的大部分都是我對他這篇博文內容的實踐。若是有機會的話你必定要去讀一下HTLM5 Rocks 關於 Web Components 的所有文章html5

技術支持

我建議你使用 Chrome v33+ 來實驗本文的例子,由於 33+ 的 Chrome 對我所描述的這些新特性都有瀏覽器的原生支持。node

分佈節點

經過閱讀各類博客,我認識到了一點:在使用 shadow DOM 的時候應該確保內容和表現的分離。換句話說,若是你的一個按鈕上想展現一些文本,那麼這些文本應該來自頁面而不是埋在 shadow DOM 的模板裏。來自頁面並經過 <content> 標籤添加到 shadow DOM 的內容被稱爲分佈節點web

在最開始我困惑於如何給分佈節點添加樣式的時候,我這樣寫 CSS 的:瀏覽器

<div class="some-shadow-host">  
  <button>Hello World!</button>
</div>

<template>  
  <style>
    :host {
      ...
    }

    button {
      font-size: 18px;
    }
  </style>
  <content></content>
</template>

試想若是 button 是來自影子宿主的話,一旦它被 <content> 標籤選中,就應該能被個人樣式渲染。然而事實卻並不是如此,實際上,分佈節點的樣式渲染須要用到 :content 僞類選擇器。這樣作是十分有意義的,由於咱們可能會想讓影子模板中的按鈕與出如今 <content> 標籤中的按鈕擁有不一樣的樣式。app

讓咱們看一個實例:dom

<body>
  <div class="widget">
    <button>分佈節點碉堡啦!</button>
  </div>

  <template class="widget-template">
    <style>
      ::content > button {
        font-size: 18px;
        color: white;
        background: tomato;
        border-radius: 10px;
        border: none;
        padding: 10px;
      }
    </style>
    <content select=""></content>
  </template>

  <script>
    var host = document.querySelector('.widget');
    var root = host.createShadowRoot();
    var template = document.querySelector('.widget-template');
    root.appendChild(document.importNode(template.content, true));
  </script>
</body>

enter image description here

在這裏咱們將按鈕從 .widget 影子宿主中取出並放置到 <content> 標籤中。使用 ::content 僞類選擇器,咱們使用 > 將 button 定位到子元素並設置了華麗麗的樣式。ide

::shadow

迄今爲止咱們已經列舉了各類基於 shadow DOM 封裝的優勢,但有時你可能會想讓使用者打破影子邊界的壁壘,讓他們可以給你的組件添加一些樣式。網站

咱們假設你在表單裏建立了一個標誌。在你的模板裏你給輸入框定義了文字的大小,可是你但願用戶能夠改變文字大小以更好的適應本身的網站。使用 ::shadow 僞類選擇器咱們能夠賦予用戶重寫咱們默認定義的自由,若是用戶這樣作的話,他就能夠打破影子邊界的壁壘。

<body>
  <style>
    .sign-up::shadow #username,
    .sign-up::shadow #password {
      font-size: 18px;
      border: 1px solid red;
    }

    .sign-up::shadow #btn {
      font-size: 18px;
    }
  </style>
  <div class="sign-up"></div>

  <template class="sign-up-template">
    <style>
      #username,
      #password {
        font-size: 10px;
      }
    </style>
    <div>
      <input type="text" id="username" placeholder="用戶名">
    </div>
    <div>
      <input type="password" id="password" placeholder="密碼">
    </div>
    <button id="btn">註冊</button>
  </template>

  <script>
    var host = document.querySelector('.sign-up');
    var root = host.createShadowRoot();
    var template = document.querySelector('.sign-up-template');
    
    root.appendChild(document.importNode(template.content, true));
  </script>
</body>

enter image description here

/deep/

使用 ::shadow 選擇器的一個缺陷是他只能穿透一層影子邊界。若是你在一個影子樹中嵌套了多個影子樹,那麼使用 /deep/ 組合符【注】更爲簡便。

<head>  
  <style>
    #foo /deep/ button {
      color: red;
    }
  </style>
</head>  
<body>  
  <div id="foo"></div>

  <template>
    <div id="bar"></div>
  </template>

  <script>
    var host1 = document.querySelector('#foo');
    var root1 = host1.createShadowRoot();
    var template = document.querySelector('template');
    root1.appendChild(document.importNode(template.content, true));

    var host2 = root1.querySelector('#bar');
    var root2 = host2.createShadowRoot();
    root2.innerHTML = '<button>點我點我</button>';
  </script>
</body>

enter image description here

總結

若是你已經讀了本文和最近的一篇博文那麼在給 shadow DOM 添加樣式方面你已經懂得和我同樣多啦。可是咱們尚未說 JavaScript 呢!咱們把 JavaScript 的部分留到明天再說:)

和以往同樣有問題的話去個人 twitter 或者給我留言,感謝閱讀~


  • 組合符(Combinator)是 CSS 裏的一個概念,用於表示兩個選擇器之間的關係。現有的組合符號有後代選擇器(space)、子選擇器(>)、相鄰兄弟選擇器(+)和兄弟選擇器(~)。

相關文章
相關標籤/搜索