Polymer: Style leaks on lazy loading or lazyRegister

Created on 19 May 2016  路  7Comments  路  Source: Polymer/polymer

Description

Custom element style which is defined outside of template is leaked into other elements while its module is being dynamically loaded. This fact sometimes invokes undesired FOUC.

Live Demo

http://plnkr.co/edit/kK4ex3OkNjeCuiKUDYcG?p=preview

Steps to Reproduce

  1. Click the style-out-template link
  2. Click the Reload button
  3. Go back to 1

    Expected Results

Nothing happens.

Actual Results

This is Home background color sometimes turns yellow.

Browsers Affected

  • [x] Chrome
  • [x] Firefox
  • [ ] Edge
  • [x] Safari 9
  • [ ] Safari 8
  • [ ] IE 11

    Versions

  • Polymer: v1.4.0, v1.5.0

  • webcomponents: v0.7.22
css platform

Most helpful comment

@naoak Thank you for all the PR's! Yes moving the <style> into the templates is the correct way to solve the issue.

Early in Polymer 1.0 we had support for <style> outside of the template, and in that case Polymer either a.) moves the style into the template in native shadow DOM or b.) rewrites the selectors to be scoped to and not leak in shady DOM. This all happens prior to the first paint when all imports are loaded synchronously. However, when imports are async/demand-loaded, the browser can paint between when the <style> outside the template is parsed and when it is re-written for shady DOM, hence the FOUC.

It's for this reason (among others) that we now recommend <style> be placed inside the template in the docs:

Note: Prior to Polymer 1.1, the recommendation was to place <style> tags inside the <dom-module> for an element (but outside the <template>). This is still supported, but is no longer recommended.

Awesome that you took the time to fix up elements that are lagging behind the recommended practice.

All 7 comments

This is a mis-feature of HTML Imports to apply <style> elements to the main page if they are not wrapped in <template>.

@azakus Thanks for replying. I found many custom elements whose styles are not wrapped in <template>, such as iron-icon, iron-dropdown, and so on. Is the only thing we can do is to fix those elements? Or any workaround?

By the way, this issue did not occur on shadowDOM. I think that is because document styles which are inserted do not penetrate into custom elements there.

Summarizing the facts I found,

In case x-foo, never causes style leak.

<dom-module id="x-foo">
  <template>
    <style>
      .message:after {
        content: ' style leak';
        color: red;
      }
    </style>
  </template>
  <script>
    Polymer({
      is: 'x-foo'
    });
  </script>
</dom-module>

In case x-bar, always causes style leak on loading.

<dom-module id="x-bar">
  <style>
    .message:after {
      content: ' style leak';
      color: red;
    }
  </style>
  <!-- without template -->
  <script>
    Polymer({
      is: 'x-bar'
    });
  </script>
</dom-module>

In case x-baz, lazy loading or normal loading with lazyRegister causes style leak. I don't know why, but sometimes doesn't without vulcanizing.

<dom-module id="x-baz">
  <style>
    .message:after {
      content: ' style leak';
      color: red;
    }
  </style>
  <template></template>
  <script>
    Polymer({
      is: 'x-baz'
    });
  </script>
</dom-module>

Many elements of this kind exist in iron-elements and paper-elements. So I think we should rewrite them as x-foo pattern, If this is a platform issue and there is no way to do in polymer.

Possible style leaks in PolymerElements.

warn:    bower_components/iron-a11y-announcer/iron-a11y-announcer.html:48:3
    Style tag is not in template
warn:    bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html:42:3
    Style tag is not in template
warn:    bower_components/iron-collapse/iron-collapse.html:55:3
    Style tag is not in template
warn:    bower_components/iron-dropdown/iron-dropdown.html:47:3
    Style tag is not in template
warn:    bower_components/iron-icon/iron-icon.html:86:3
    Style tag is not in template
warn:    bower_components/neon-animation/neon-animated-pages.html:30:3
    Style tag is not in template
warn:    bower_components/neon-animation/neon-animatable.html:30:3
    Style tag is not in template
warn:    bower_components/paper-dialog-scrollable/paper-dialog-scrollable.html:74:3
    Style tag is not in template
warn:    bower_components/paper-scroll-header-panel/paper-scroll-header-panel.html:87:3
    Style tag is not in template
warn:    bower_components/iron-overlay-behavior/iron-overlay-backdrop.html:31:3
    Style tag is not in template

@naoak Thank you for all the PR's! Yes moving the <style> into the templates is the correct way to solve the issue.

Early in Polymer 1.0 we had support for <style> outside of the template, and in that case Polymer either a.) moves the style into the template in native shadow DOM or b.) rewrites the selectors to be scoped to and not leak in shady DOM. This all happens prior to the first paint when all imports are loaded synchronously. However, when imports are async/demand-loaded, the browser can paint between when the <style> outside the template is parsed and when it is re-written for shady DOM, hence the FOUC.

It's for this reason (among others) that we now recommend <style> be placed inside the template in the docs:

Note: Prior to Polymer 1.1, the recommendation was to place <style> tags inside the <dom-module> for an element (but outside the <template>). This is still supported, but is no longer recommended.

Awesome that you took the time to fix up elements that are lagging behind the recommended practice.

@kevinpschaaf Thank you for the detailed explanation! I've seen the note before, nevertheless I was stupidly taking it as a kind of coding style. Now I've fully understood. Thanks!

Closed based on explanation.

Was this page helpful?
0 / 5 - 0 ratings