Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IE11 Support #11

Closed
Coly010 opened this issue Jan 6, 2020 · 6 comments
Closed

IE11 Support #11

Coly010 opened this issue Jan 6, 2020 · 6 comments
Labels
hacks needs clarification Further information is requested

Comments

@Coly010
Copy link

Coly010 commented Jan 6, 2020

Currently, as it stands, this library does not support IE11 as IE11 does not support CSS Variables.

A polyfill should fix this, and it may be more ideal to supply that polyfill with this library.

@johannesjo
Copy link
Owner

Hey there! Thanks for opening up this issue. I think the polyfill.ts offered by angular cli is a better place for that. What we should provide here however is explaining how to do it. I personally don't have any experience in making it work for IE11, but maybe somebody else could help?

@Coly010
Copy link
Author

Coly010 commented Jan 6, 2020

You are correct, it should be in polyfills.ts in the angular app, as you do not want to couple this lib with the polyfill.
I will be doing some research into potential polyfills tomorrow so will update here when I have completed that.

@johannesjo
Copy link
Owner

@Coly010 Thank you! I would very much appreciate that!

@Coly010
Copy link
Author

Coly010 commented Jan 9, 2020

Ok so I got this to work 🎉

But it's kind of hacky.

We don't need a polyfill, rather a ponyfill. The ponyfill I used was css-vars-ponyfill. It's super quick and isn't too big bundle size: 586 kB. One of the biggest reasons for using it was that it allows declaration of global css props.

We also need to rewrite the _setStyle method within MaterialCssVarsService

The main reasoning behind this is due to IE11's restriction on the {element}.style property where {element} is a reference to any DOM Element.
This restriction is that it will only allow CSS Style properties that it supports to be set as an inline style.
Here's an example:

// HTML
<myElement>
</myElement>
// =========
// Set the style in JS
myElement.style = "--primary-color: blue; font-size: 18px;";

// Output in IE
// HTML
<myElement style="font-size: 18px">
</myElement>

As we can see, we've lost the --primary-color: blue', which means a lot of alternatives polyfills fail as they simply can't find the CSS Custom Property to polyfill it.

Therefore, I rewrote the _setStyle method to handle IE11 differently. Instead of setting the style attribute, I get it to set a data attribute. Then using
NOTE: You must overwrite the singleton instance's _setStyle property!

const existingMethod = service['_setStyle'];

service['_setStyle'] = (vars: { name: string; val: string }[]) => {
    existingMethod(vars);

    const currentStyle = document.documentElement.getAttribute('data-mat-vars');

    const style = vars.reduce(
      (styleString: string, cssVar: { name: string; val: string }) => {
        styleString += `${cssVar.name}:${cssVar.val};`;
        return styleString;
      },
      currentStyle || ''
    );

    // Need to set a data attr for IE11 as it's style attr only allows for Style Attrs IE11 supports
    document.documentElement.setAttribute('data-mat-vars', style);
};

The next step is to initialise the ponyfill. This should ideally be done after we call our setPrimaryColor and setAccentColor. We want to read in our CSS Custom Props after they have been set by these methods as they will then exist in the DOM. We can read them in as a string and parse them into a key-value pair object the the css-vars-ponyfill accepts:

const documentElement = document.documentElement;

  if (documentElement.hasAttribute('data-mat-vars')) {
    const customThemePropsString = documentElement.getAttribute('data-mat-vars');
    const themeVariablesObj = {};

    // Convert from string of css vars into key-value pair
    customThemePropsString.split(';').forEach(prop => {
      const propParts = prop.split(':');
      themeVariablesObj[propParts[0]] = propParts[1];
    });

    // Let's init the ponyfill with our custom css variables
    cssVars({
      rootElement: document,
      variables: themeVariablesObj,
      watch: true
    });
  }

And voila!

The next step for improving this would be to have an Observable Subject in the service that when _setStyle is called we can run the code to re-gen the themeVariablesObj to continue to allow runtime switching of theme.

@johannesjo
Copy link
Owner

@Coly010 thank you very much for sharing!

@johannesjo johannesjo added needs clarification Further information is requested hacks labels Feb 7, 2020
@json-derulo
Copy link
Collaborator

IE11 support has been deprecated in Angular v12 and removed in Angular v13, so this hack is obsolete now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hacks needs clarification Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants