-1

(JavaScript) I have html email template in string. How to colect all inline styles that is using in template?

for example I have input

<div style="min-width:300px;max-width:600px;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;margin:0 auto;" align="center">
  <div style="margin: 0 auto;padding: 20px;">
    <a href="/" style="text-decoration: none;">
       <img src="https://i.ibb.co/KXYtCNT/Logo-wellness-w.png" alt="" width="84px" />
    </a>
  </div>
</div>

In return I need ['min-width','max-width','overflow-wrap','word-wrap','word-break','margin','padding','text-decoration']

I think the best way use Regex but don't know how to write it. Use something like that for tags:

const tagRegex = /<\/?[\w\d]+>/gi;

and this for styles but doesn't work:

const styleRegex = /(.*?)+:[\w\d]+;/;
Marharyta
  • 3
  • 2
  • 3
    [I think the best way use Regex](https://stackoverflow.com/a/1732454/19068) – Quentin Apr 27 '23 at 09:22
  • 4
    https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString – Quentin Apr 27 '23 at 09:22
  • Just out of interest, why just listing all the inline styles? If you need to recreate proper CSS rules with selectors, then you also need to set classes or ids to the elements to retarget them. Usually, most mail readers will remove ids as they could already be in use in the e-mail web client (such as gmail.com or outlook.com). To get newsletters to render properly, it's very common to set inline CSS rules with the `style` attribute. I personally have clean CSS rules in a ` – Patrick Janser Apr 27 '23 at 13:54
  • In emails I use only inline-styles and – Marharyta Apr 27 '23 at 15:37
  • Ok! I see. Good idea to validate them :-). I think that Quentin's answer with the *DOMParser: parseFromString()* method is probably the safest. But if not, a quick regex such as `/<\s*\w+\s[^>]*style\s*=\s*(["'])(.*?)\1/g` would do the trick to extract the style attribute in the capturing group number 2 (`$2`). – Patrick Janser Apr 27 '23 at 16:35

1 Answers1

0

If you want something safe then use the DOMParser:parseFromString() method, as Quentin mentioned.

const HTML = `<div style="min-width:300px;max-width:600px;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;margin:0 auto;" align="center">
  <div style="margin: 0 auto;padding: 20px;">
    <a href="/" style="text-decoration: none;">
       <img src="https://i.ibb.co/KXYtCNT/Logo-wellness-w.png" alt="" width="84px" />
    </a>
  </div>
</div>`;

// Pattern explained here: https://regex101.com/r/K4z8M4/1
const CSS_PATTERN = /([\w-]*)\s*:\s*(.*?)(?=\s*(?:;|$))/g;

const parser = new DOMParser();
const doc = parser.parseFromString(HTML, 'text/html');
const domElements = doc.querySelectorAll('body *');

domElements.forEach((e) => {
  if (e.style.cssText != '') {
    console.log('Found style attribute on <' + e.tagName + '>');
    console.log('Inline CSS = "' + e.style.cssText + '"');
    console.log('Get CSS rules with regex:');
    // Split the inline CSS with a regex.
    const matches = e.style.cssText.matchAll(CSS_PATTERN);
    for (const match of matches) {
      console.log('  ' + match[1] + ': ' + match[2]);
    }
    
    // The style object of the DOM element has some numeric
    // attributes, which seems to be all the CSS rules applied
    // from the CSS text. This might be more precise than
    // the CSS text itself, as it may contain some errors.
    console.log('Affected style rules:');
    for (const [key, value] of Object.entries(e.style)) {
      // Check if the key is numeric.
      // Only tested on Chrome, Firefox and Edge.
      if ((key + "").match(/^\d+$/)) {
        console.log('  ' + value);
      }
    }
  }
});

As you see, I used a regular expression to match the CSS rules. This is because I noticed that the style attribute of the DOM element had some different CSS rules than the ones declared in the CSS. For example if you have margin: 1em then margin-top, margin-right, margin-bottom and margin-left are affected. But you probably want to only have the margin rule in your list.

If you need some explanation about the regular expression to split the CSS rules, you can read the description of the pattern I created here: https://regex101.com/r/K4z8M4/1

Patrick Janser
  • 3,318
  • 1
  • 16
  • 18