RSS and Atom feed stylesheet without XSLT
A styled feed page helps people who click the feed link. A CSS file gives you that without XSLT, in RSS 2.0 and Atom.
Last updated: ยท What changed: Added an accuracy table, coverage statement and Chrome 158 sourcing, and a new operator section on the About page.
The line to put in your XML file
Replace the xml-stylesheet line that points to your .xsl file with this one, and upload the CSS file to the address in href.
What the stylesheet does for a feed
Feed readers ignore stylesheets and read the items directly. The stylesheet matters only for a person who opens the feed address in a browser. With CSS the feed title becomes a heading, each item gets a divider, link and date, and the channel fields nobody needs to see are hidden.
RSS 2.0 or Atom
RSS keeps its item links as text inside a link element, so the CSS prints them as they are. Atom keeps the address in an href attribute on an empty link element, so the CSS prints it with content: attr(href) and hides links that are not the alternate page. The generator writes the right version for the type you pick.
Jekyll, Hugo and other generators
If a static site generator adds the XSL line, copy its feed template into your own site, remove the xml-stylesheet line or replace it with the CSS line, and rebuild. Run the feed address through the checker afterwards; it names the generator when it recognises it.
Render a separate feed reading page
A feed reader still needs your XML, but people can use a separate HTML archive. Run this Node script during publishing with your feed and stylesheet as arguments. Install xslt-processor in that project first and save the script as render.mjs.
// render.mjs -> node render.mjs sitemap.xml sitemap.xsl > sitemap.html
import { readFileSync } from 'node:fs';
import { Xslt, XmlParser } from 'xslt-processor';
const [xmlFile, xslFile] = process.argv.slice(2);
const parser = new XmlParser();
const html = await new Xslt().xsltProcess(
parser.xmlParse(readFileSync(xmlFile, 'utf8')),
parser.xmlParse(readFileSync(xslFile, 'utf8')),
);
process.stdout.write(html);Check that item dates, links and embedded content survive the transform. Engine support varies. To preserve an existing XSLT 1.0 feed display instead, host the polyfill yourself and insert this element inside the feed root:
<script src="/xslt-polyfill.min.js" xmlns="http://www.w3.org/1999/xhtml"></script>Before changing a public feed, review the self-hosting instructions and limitations, or compare migration routes.
Questions
Do feed readers need the stylesheet?
No. Readers and aggregators parse the items and ignore any stylesheet, so removing or replacing it does not change who can subscribe.
How do I style an RSS feed without XSLT?
Link a CSS file with an xml-stylesheet line of type text/css. The generator on this page writes the CSS and the line for RSS 2.0 and for Atom.
Why do some feed fields not show?
The CSS hides fields such as the language, the generator name and the full HTML content on purpose, so the page stays readable. Remove a hiding rule from the CSS to show a field.
Will the feed still validate?
Yes. A stylesheet line is a processing instruction in the prolog and does not change the feed data.
Can I keep the XSL and add CSS too?
You can have both lines, but the XSL line will stop working in browsers that remove XSLT. Remove it once the CSS is in place.