# How Markdown Here Ensures Explicit CSS Styling for Rendered Markdown in Email Clients

> Markdown Here injects explicit CSS styles into email clients safeguarding your rendering. Learn how makeStylesExplicit ensures styling survives sanitization for perfect markdown emails.

- Repository: [Adam Pritchard/markdown-here](https://github.com/adam-p/markdown-here)
- Tags: internals
- Published: 2026-03-05

---

**Markdown Here converts stylesheet rules into inline `style` attributes via the `makeStylesExplicit` function to ensure styling survives email client sanitization.**

When rendering Markdown inside email compose windows, the open-source extension **Markdown Here** (adam-p/markdown-here) faces a critical constraint: major webmail clients like Gmail strip out external `<style>` blocks. To guarantee consistent visual formatting, the tool implements a robust inline CSS conversion system that embeds styles directly into HTML elements.

## The Email Client Sanitization Challenge

Email clients aggressively sanitize HTML content to prevent security risks and ensure consistent rendering. Gmail and other providers commonly remove `<style>` tags from incoming or composed messages, which would normally break any CSS-dependent Markdown formatting. According to comments in the source at lines 94-96 of [`markdown-here.js`](https://github.com/adam-p/markdown-here/blob/main/markdown-here.js), this sanitization makes external stylesheets unreliable for email-based Markdown rendering.

## The `makeStylesExplicit` Conversion Process

At the core of the solution is the **`makeStylesExplicit`** function located in [`src/common/markdown-here.js`](https://github.com/adam-p/markdown-here/blob/main/src/common/markdown-here.js). This utility transforms stylesheet-based CSS into element-level inline styles through a systematic four-step pipeline.

### Step 1: Rendering to HTML and CSS

The process begins when the Markdown renderer produces two distinct outputs: the rendered HTML content (`mdHtml`) and the corresponding CSS rules (`mdCss`). This separation allows the system to maintain clean semantic markup while preserving stylistic information for later inline application.

### Step 2: DOM Insertion

The rendered HTML is inserted into the email compose area using the `replaceRange` function, which wraps the content in a container element. This wrapper serves as the boundary for style application, ensuring that only the Markdown content receives inline styling without affecting the rest of the email interface.

### Step 3: Stylesheet Processing

Immediately after insertion, the code calls `makeStylesExplicit(wrapper, mdCss)` at lines 496-97. This function creates a temporary `<style>` element via `getMarkdownStylesheet` (defined at lines 28-60) to parse the CSS text into accessible rules:

```javascript
function makeStylesExplicit(wrapperElem, css) {
    var stylesheet = getMarkdownStylesheet(wrapperElem, css);
    for (var i = 0; i < stylesheet.cssRules.length; i++) {
        var rule = stylesheet.cssRules[i];
        var selectorMatches = wrapperElem.parentNode.querySelectorAll(rule.selectorText);
        // Processing continues...
    }
}

```

### Step 4: Inline Style Application

For each CSS rule, the function queries for matching elements within the wrapper and applies the styles directly to the DOM:

```javascript
selectorMatches.forEach(function (elem) {
    if (!elem.closest('.markdown-here-wrapper')) return;
    var styleAttr = elem.getAttribute('style') || '';
    if (styleAttr && !/;\s*$/.test(styleAttr)) styleAttr += '; ';
    styleAttr += rule.style.cssText;
    elem.setAttribute('style', styleAttr);
});

```

This ensures that even if the email client subsequently removes all `<style>` tags, the visual formatting remains intact on each individual element.

## Key Implementation Details

The **`getMarkdownStylesheet`** helper function safely instantiates a temporary stylesheet object from the CSS text string, enabling standard DOM CSSOM methods to parse and iterate through rules. The main rendering orchestration in [`src/common/markdown-render.js`](https://github.com/adam-p/markdown-here/blob/main/src/common/markdown-render.js) coordinates this pipeline, while utility functions in [`src/common/utils.js`](https://github.com/adam-p/markdown-here/blob/main/src/common/utils.js) handle safe HTML insertion.

The conversion logic specifically checks for existing inline styles using `elem.getAttribute('style')` and intelligently appends new declarations with proper semicolon separation, preventing syntax errors when multiple rules target the same element.

## Summary

- **Markdown Here** uses the `makeStylesExplicit` function in [`src/common/markdown-here.js`](https://github.com/adam-p/markdown-here/blob/main/src/common/markdown-here.js) to convert CSS rules into inline `style` attributes
- The process involves creating a temporary stylesheet, iterating through `cssRules`, and applying each rule's `cssText` to matching elements via `setAttribute`
- This approach guarantees that rendered Markdown retains its intended appearance even when email clients like Gmail strip external `<style>` blocks
- The implementation safely handles pre-existing inline styles and ensures proper CSS syntax through semicolon separation

## Frequently Asked Questions

### Why can't Markdown Here rely on external CSS stylesheets in email clients?

Webmail providers like Gmail aggressively sanitize HTML by removing `<style>` blocks to prevent security vulnerabilities and styling conflicts with their own interfaces. As noted in the source code comments, this makes external stylesheets unreliable, necessitating the conversion to inline styles that cannot be stripped without removing the element itself.

### How does `makeStylesExplicit` preserve existing inline styles?

The function retrieves any pre-existing `style` attribute content using `getAttribute('style')`, checks for proper semicolon termination with a regex, and appends the new CSS rules while maintaining valid syntax. This ensures that elements with multiple CSS declarations receive all styles without string concatenation errors.

### Which source files contain the explicit CSS styling logic?

The primary implementation resides in **[`src/common/markdown-here.js`](https://github.com/adam-p/markdown-here/blob/main/src/common/markdown-here.js)**, specifically within the `makeStylesExplicit` and `getMarkdownStylesheet` functions. The rendering pipeline that feeds CSS into this system is orchestrated by **[`src/common/markdown-render.js`](https://github.com/adam-p/markdown-here/blob/main/src/common/markdown-render.js)**, while **[`src/common/utils.js`](https://github.com/adam-p/markdown-here/blob/main/src/common/utils.js)** provides helper functions for safe DOM manipulation.

### Does inline CSS conversion affect rendering performance?

While the conversion requires DOM traversal and attribute manipulation, it executes only once during the Markdown-to-HTML transformation process. The temporary stylesheet creation and `querySelectorAll` operations complete quickly for typical email-length content, resulting in negligible performance impact while ensuring cross-client compatibility.