Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically convert Style Sheets to inline style

Don't have to worry about linked style or hover style.

I want to automatically convert files like this

<html> <body> <style> body{background:#FFC} p{background:red} body, p{font-weight:bold} </style> <p>...</p> </body> </html> 

to files like this

<html> <body style="background:red;font-weight:bold"> <p style="background:#FFC;font-weight:bold">...</p> </body> </html> 

I would be even more interested if there was an HTML parser that would do this.

The reason I want to do this is so I can display emails that use global style sheets without their style sheets messing up the rest of my web page. I also would like to send the resulting style to web based rich text editor for reply and original message.

like image 841
700 Software Avatar asked Dec 23 '10 18:12

700 Software


People also ask

What is a CSS Inliner?

Inlining is the process of prepping an HTML email for delivery to email clients. Some email clients strip out your email's styles unless they are written inline with style tags. Here's what the inliner does: Inlining CSS: All of your CSS is embedded directly into the HTML as style attributes on each tag.

Which is better inline styles or external style sheets Why?

The main difference between inline CSS and external CSS is that inline CSS is processed faster as it only requires the browser to download 1 file while using external CSS will require downloading HTML and CSS files separately.

Are inline styles faster than CSS?

An inline CSS will load faster if the CSS content size downloads faster than your server would respond to an external CSS file request (considering DNS time, server latency, etc).

Do inline styles override stylesheets?

Inline styles added to an element (e.g., style="font-weight: bold;" ) always overwrite any normal styles in author stylesheets, and therefore, can be thought of as having the highest specificity.


2 Answers

Here is a solution on java, I made it with the JSoup Library: http://jsoup.org/download

import java.io.IOException; import java.util.StringTokenizer;  import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements;  public class AutomaticCssInliner {     /**      * Hecho por Grekz, http://grekz.wordpress.com      */     public static void main(String[] args) throws IOException {         final String style = "style";         final String html = "<html>" + "<body> <style>"                 + "body{background:#FFC} \n p{background:red}"                 + "body, p{font-weight:bold} </style>"                 + "<p>...</p> </body> </html>";         // Document doc = Jsoup.connect("http://mypage.com/inlineme.php").get();         Document doc = Jsoup.parse(html);         Elements els = doc.select(style);// to get all the style elements         for (Element e : els) {             String styleRules = e.getAllElements().get(0).data().replaceAll(                     "\n", "").trim(), delims = "{}";             StringTokenizer st = new StringTokenizer(styleRules, delims);             while (st.countTokens() > 1) {                 String selector = st.nextToken(), properties = st.nextToken();                 Elements selectedElements = doc.select(selector);                 for (Element selElem : selectedElements) {                     String oldProperties = selElem.attr(style);                     selElem.attr(style,                             oldProperties.length() > 0 ? concatenateProperties(                                     oldProperties, properties) : properties);                 }             }             e.remove();         }         System.out.println(doc);// now we have the result html without the         // styles tags, and the inline css in each         // element     }      private static String concatenateProperties(String oldProp, String newProp) {         oldProp = oldProp.trim();         if (!newProp.endsWith(";"))            newProp += ";";         return newProp + oldProp; // The existing (old) properties should take precedence.     } } 
like image 139
Grekz Avatar answered Oct 10 '22 13:10

Grekz


Using jsoup + cssparser:

private static final String STYLE_ATTR = "style"; private static final String CLASS_ATTR = "class";  public String inlineStyles(String html, File cssFile, boolean removeClasses) throws IOException {     Document document = Jsoup.parse(html);     CSSOMParser parser = new CSSOMParser(new SACParserCSS3());     InputSource source = new InputSource(new FileReader(cssFile));     CSSStyleSheet stylesheet = parser.parseStyleSheet(source, null, null);      CSSRuleList ruleList = stylesheet.getCssRules();     Map<Element, Map<String, String>> allElementsStyles = new HashMap<>();     for (int ruleIndex = 0; ruleIndex < ruleList.getLength(); ruleIndex++) {         CSSRule item = ruleList.item(ruleIndex);         if (item instanceof CSSStyleRule) {             CSSStyleRule styleRule = (CSSStyleRule) item;             String cssSelector = styleRule.getSelectorText();             Elements elements = document.select(cssSelector);             for (Element element : elements) {                 Map<String, String> elementStyles = allElementsStyles.computeIfAbsent(element, k -> new LinkedHashMap<>());                 CSSStyleDeclaration style = styleRule.getStyle();                 for (int propertyIndex = 0; propertyIndex < style.getLength(); propertyIndex++) {                     String propertyName = style.item(propertyIndex);                     String propertyValue = style.getPropertyValue(propertyName);                     elementStyles.put(propertyName, propertyValue);                 }             }         }     }      for (Map.Entry<Element, Map<String, String>> elementEntry : allElementsStyles.entrySet()) {         Element element = elementEntry.getKey();         StringBuilder builder = new StringBuilder();         for (Map.Entry<String, String> styleEntry : elementEntry.getValue().entrySet()) {             builder.append(styleEntry.getKey()).append(":").append(styleEntry.getValue()).append(";");         }         builder.append(element.attr(STYLE_ATTR));         element.attr(STYLE_ATTR, builder.toString());         if (removeClasses) {             element.removeAttr(CLASS_ATTR);         }     }      return document.html(); } 
like image 29
jnr Avatar answered Oct 10 '22 13:10

jnr