Style an RSS feed with CSS: what still works in Chrome

A CSS stylesheet linked from a feed keeps working in Chrome after XSLT is removed, as long as the server sends the feed as application/xml or text/xml. Sent as application/rss+xml, the same feed shows as raw text and the CSS is ignored. We checked this in Chromium 156 and on a WordPress test site, and the setup takes three steps.

Can you style an RSS feed with CSS once XSLT is gone?

Yes, if the server sends the feed with the right content type. Chrome’s XSLT announcement says that the <?xml-stylesheet ... ?> processing instruction remains supported with CSS, using type="text/css". Only XSLT is removed, in Chrome 158 on 17 November 2026.

That affects publishers whose feed uses an XSL stylesheet today. Chrome notes that many RSS and Atom feeds use XSLT so that people can read them when they open the feed in the browser. From 17 November, those feeds lose their layout in Chrome. A CSS stylesheet is the lighter replacement: no transformation, only rules about how each element looks.

The content-type condition comes from how Chrome handles feed media types. A feed sent as application/rss+xml or application/atom+xml opens as plain text in Chrome, and plain text gets no stylesheet at all, neither CSS nor XSL. Our guide on RSS feeds shown as plain text covers that behavior and what readers can do about it.

So, to style an RSS feed with CSS, you need two things: the stylesheet line in the feed, and a server that sends the feed as application/xml or text/xml. If your XSL-styled feed displays in Chrome today, your server already sends one of these types, and only the stylesheet line has to change.

Which content type lets Chrome apply CSS to a feed?

application/xml or text/xml. On 14 October 2026, we served a small Atom feed and a small RSS feed from a local server to Chromium 156. Each one started with this line, right after the XML declaration:

<?xml-stylesheet type="text/css" href="/feed.css"?>

The test stylesheet turned every title element into a red 28-pixel heading and hid the other elements, so that the result could be read from the computed style of the element. We ran every case twice: with Chromium’s XSLT feature on, and with it turned off, as it will be in Chrome 158. The results were the same.

Feed Type sent by the server What Chromium showed
Atom application/xml CSS applied: the titles in red
Atom text/xml CSS applied
RSS application/xml CSS applied
RSS text/xml CSS applied
Atom application/atom+xml Raw text of the feed, CSS ignored
RSS application/rss+xml Raw text of the feed, CSS ignored

In the raw text cases, the page showed the source of the feed exactly as sent, in a monospace font, stylesheet line included. In the styled cases, Chrome showed no message above the content. The hidden elements, such as id and updated, were gone from view but still present in the document.

Without any stylesheet line, the same RSS feed sent as application/xml showed Chrome’s tree view under its “no style information” message, explained in Chrome’s built-in XML tree view. A feed that links to an XSL stylesheet shows a different message once XSLT is off: “This document cannot be formatted as intended”.

Three steps.

1. Add the processing instruction. The W3C recommendation “Associating Style Sheets with XML documents” defines it. It must sit in the prolog, before the root element: right after <?xml version="1.0"?> and before <rss> or <feed>. The href pseudo-attribute is required. The others are optional: type, title, media, charset and alternate. A complete RSS feed with its stylesheet line looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/feed.css"?>
<rss version="2.0">
  <channel>
    <title>Example blog</title>
    <link>https://example.com/</link>
    <description>Latest articles</description>
    <item>
      <title>First article</title>
      <link>https://example.com/first/</link>
    </item>
  </channel>
</rss>

2. Write the CSS. In CSS, the initial value of display is inline, according to MDN. A feed has no HTML defaults, so without your own rules every element runs together on one line. Start by making the containers blocks:

rss, channel, item, feed, entry { display: block; }
title { display: block; font-size: 1.4em; margin: 1em 0 0.3em; }
link, guid, id, updated, pubDate { display: none; }

We tested this stylesheet as well: on an RSS feed, the titles were set at 1.4 times the base size and the links were hidden. In RSS, the channel and each item have their own title element. To style them differently, use channel > title and item > title, or feed > title and entry > title in Atom. A plain title selector also matches the titles of an Atom feed, whose elements belong to the Atom namespace: according to the W3C Selectors specification, a type selector matches elements in any namespace when the stylesheet declares no default namespace with @namespace.

3. Send the right content type. MDN’s list of common media types recommends application/xml for XML and notes that text/xml is still used sometimes, so prefer application/xml. The W3C Feed Validation Service will warn that this type is not specific enough for every program to identify a feed; when the type cannot be more specific, it asks for <rss or <feed within the first 512 bytes, which a feed that opens with the two lines above does.

On WordPress, two hooks handle both changes. The feed_content_type() function returns application/rss+xml for RSS and application/atom+xml for Atom unless a filter changes it, and the rss_tag_pre action fires between the XML declaration and the root element. This code, saved as a PHP file in wp-content/mu-plugins/, the folder of must-use plugins, worked on a WordPress 7.1.3 test site:

<?php
// Send RSS and Atom feeds as application/xml, so that Chrome applies a CSS stylesheet.
add_filter( 'feed_content_type', function ( $content_type, $type ) {
	return in_array( $type, array( 'rss2', 'atom' ), true ) ? 'application/xml' : $content_type;
}, 10, 2 );

// Print the stylesheet line between the XML declaration and the root element.
add_action( 'rss_tag_pre', function () {
	echo '<?xml-stylesheet type="text/css" href="/feed.css"?>' . "\n";
} );

On nginx, for a static feed file, empty the type map for that address and set a default type, as in the example of nginx’s types directive:

location = /feed.xml {
    types        { }
    default_type application/xml;
}

In our test with nginx 1.27, this block sent /feed.xml as application/xml, while other .xml files kept nginx’s default type, text/xml.

To check what your server sends, open the feed in Chrome, open DevTools, reload the page and select the feed request in the Network panel. In the Headers tab, content-type is listed under Response Headers. From a terminal, curl -s -o /dev/null -D - https://example.com/feed/ prints the same response headers.

Podcast feeds follow the same rules: they are RSS files, so the content type decides whether Chrome applies the CSS or shows raw text.

Keep the autodiscovery link of your HTML pages as it is. The RSS Advisory Board asks for type="application/rss+xml" in that link element. That attribute sits in your HTML page, while the Content-Type header of the feed is set separately, by the server that sends the feed.

What can’t CSS do in an RSS feed?

CSS changes how existing elements look. It does not change what they are. Three limits follow from that.

The link element of an item stays text. CSS gives it no link behavior, so readers cannot click through to the article.

HTML inside a description stays text too. In our test, escaped HTML and HTML in a CDATA section both showed their tags as characters, such as <p> and <b>. Hide the description, or keep it to plain text.

CSS cannot sort items by their data or rewrite it. A date stays in the format of the feed, and items cannot be sorted by date or title.

If you want a real page with clickable links, you need HTML, which means keeping an XSL stylesheet rather than CSS. For feeds that keep their XSL, Chrome’s announcement suggests adding one line that loads the xslt-polyfill script; according to Chrome, this should not stop feed readers from parsing the XML. The polyfill only applies an XSL stylesheet that the feed links to, and the content type matters here too: in our test with XSLT turned off, a script placed in the feed ran when the feed was sent as application/xml, and never ran as application/rss+xml, because Chrome then showed the feed as plain text. The other route is to produce the HTML yourself and publish it at a separate address, so that the feed stays XML. Our server-side XSLT examples show how.

To compare your CSS version with the XSL layout it replaces, you can open the feed in an XML viewer that applies XSL: XMLNest, available on the Chrome Web Store, applies XSL stylesheets (version 1.0) the way Chrome used to, and opens RSS and Atom feeds in a reader view.

Sources

  1. Chrome for Developers: Removing XSLT for a more secure browser (checked on 14 October 2026)
  2. W3C: Associating Style Sheets with XML documents 1.0 (Second Edition) (checked on 14 October 2026)
  3. W3C: Selectors Level 3, Type selectors and namespaces (checked on 14 October 2026)
  4. MDN: display (checked on 14 October 2026)
  5. MDN: Common media types (checked on 14 October 2026)
  6. W3C Feed Validation Service: Media type is not specific enough (checked on 14 October 2026)
  7. WordPress Developer Resources: feed_content_type() (checked on 14 October 2026)
  8. WordPress Developer Resources: rss_tag_pre (checked on 14 October 2026)
  9. WordPress Developer Resources: Must Use Plugins (checked on 14 October 2026)
  10. nginx documentation: Module ngx_http_core_module, types (checked on 14 October 2026)
  11. Chrome for Developers: Network features reference (checked on 14 October 2026)
  12. RSS Advisory Board: RSS Autodiscovery (checked on 14 October 2026)
  13. XSLT Polyfill, README of mfreed7/xslt_polyfill on GitHub (checked on 14 October 2026)
  14. Test by XMLNest : Tested by XMLNest in Chromium 156.0.8078.4 on 14 October 2026, with the XSLT feature on and then turned off: an Atom feed and an RSS feed linked to a CSS stylesheet with <?xml-stylesheet type="text/css"?> were styled when served as application/xml or text/xml; served as application/atom+xml or application/rss+xml, they showed as raw text and no stylesheet was loaded. The stylesheet shown in this article applied to an RSS feed; HTML in a description, escaped or in a CDATA section, showed its tags as text; the RSS feed without a stylesheet line showed Chrome's XML tree; with XSLT turned off, a feed linked to an XSL stylesheet showed “This document cannot be formatted as intended”, and a script element in the XHTML namespace inside it ran when the feed was sent as application/xml, not as application/rss+xml. On a WordPress 7.1.3 test site run from the official Docker image, the code of this article sent /feed/ and /feed/atom/ as application/xml with the stylesheet line, and Chromium applied the CSS; nginx 1.27 sent /feed.xml as application/xml with the location block of this article, and other .xml files as text/xml (checked on 14 October 2026)