javascriptcssfont-faceshadow-domicon-fonts

External font does not load when link is loaded from inside the shadowDOM


At the begining I want to say that I'm aware that the question is similar to:

How to let imported css font / icons have effects on elements in the shadow dom?

It's not the case and it does not help.

Issue: I've recently decided to use the ShadowDOM to encapsulate the styles in my project. At the very begining it I thought it worked as expected but I've noticed that some of the icons coming from the external CSS files were gone. It's important to notice that those styles are external and possibilities of making changes are limited.

I've prepared the code to demonstrate the issue (look at the snippet below).

Everything seems to be working fine except the @font-face

As You can see, HTML containing the external CSS file with icons works as expected outside the ShadowDOM. I'd like to use it inside the shadowDOM as well.

How can I achieve that ?

NOTE: If you check the dev tools, there is a problem with the CSS path in network tab but it's the SO snippet issue. If You run the snippet locally, everything is ok in network.

const body = document.getElementsByTagName('body')[0];
const wrapper = document.querySelector('.wrapper')

const handleAddToShadowClick = (param) => {
  const host = document.querySelector('#shadowHost');
  if(param === 'insideShadow') {
    const shadowRoot = host.attachShadow({mode: 'open'});
     shadowRoot.innerHTML = firstComponent
  } else {
    const shadowRoot = host;
    wrapper !== null ? body.removeChild(wrapper): '' 
    shadowRoot.innerHTML = firstComponent
  }
}

const firstComponent = `
<div class="wrapper">
  <div class="icon login">Bla bla</div>
  <div style="font-family: testFont;">Sample String od text</div>
  <link rel="stylesheet" href="./style.css" />
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.13.0/css/all.css" integrity="sha384-Bfad6CLCknfcloXFOyFnlgtENryhrpZCe29RTifKEixXQZ38WheV+i/6YWSzkz3V" crossorigin="anonymous">
</div>  
`
.wrapper {
    font-family: agGridBalham;
    background-color: aquamarine;
    color: black;
}

.balham:before {
    content: "\F11F";
}

.login::before {
    font-family: "Font Awesome 5 Free";
    font-weight: 900; 
    content: "\f007";
  }
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
      Refresh the page after each button click
    </p>
    <button onclick="handleAddToShadowClick('outside')">Add outside shadow</button>
    <button onclick="handleAddToShadowClick('insideShadow')">Add inside shadow</button>  
<div>
  <div id="shadowHost"> </div> 
</div>
    
    <script src="./script.js"></script>
  </body>
</html>


Solution

  • The behavior mentioned in the question is a bug which has been there in chromium(It was also there in Gecko too not sure if it has been fixed or not).

    Here is the link for the bug reported at chromium related to this issue, which still not resolved by them. At, present i feel this is the only workaround which will work.

    The issue is mainly related to scoping of @font-face. Currently you cannot use the fonts awesome fonts when they are only included inside the shadow DOM. So inorder to use the fonts the fonts css must be present inside both light DOM and shadow DOM. So you need to import the font css both inside the shadow dom and the light dom.

    Here is a Working Plunker which solves your problem.

    <html>
      <head>
        <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.13.0/css/all.css" integrity="sha384-Bfad6CLCknfcloXFOyFnlgtENryhrpZCe29RTifKEixXQZ38WheV+i/6YWSzkz3V" crossorigin="anonymous">
      </head>
    
      <body>
          Refresh the page after each button click
        </p>
        <button onclick="handleAddToShadowClick('outside')">Add outside shadow</button>
        <button onclick="handleAddToShadowClick('insideShadow')">Add inside shadow</button>  
        <div>
          <div id="shadowHost"> </div> 
        </div>
        <script src="lib/script.js"></script>
      </body>
    </html>
    

    As you can see the plunker above, we have included the font-awesome css both in light DOM and Shadow Dom. And it is working fine as intended.