CSS MIME Type – Free, Online, Private
text/css is the type for a stylesheet. Browsers refuse to apply a cross-origin sheet served as a different type.
What .css is
A stylesheet is text. It is a sequence of rules, at-rules, and comments. The registered type is text/css. Browsers enforce that strictly for a link rel=stylesheet, especially cross-origin: a sheet served as text/plain or application/octet-stream will not apply. That check is independent of whether the bytes are valid CSS. @charset in the file is a fallback. The HTTP charset wins when you send one. Send text/css; charset=utf-8. A source map is a different file, usually application/json, referenced by a comment. It is not this type.
IANA registers text/css. The media type is text/css. Extensions that use it on this page: .css. A client compares the type, not the filename, once the response has arrived. The filename still matters on disk and in Content-Disposition, which is why a wrong extension and a wrong header are two different bugs.
What sends text/css
What sends text/css: Send text/css; charset=utf-8 for a static sheet and for a generated one. Cache far-future if the URL is fingerprinted, and do not cache at all if the URL is /theme.css and the contents depend on the user. The type is the same in both cases. The Cache-Control is not. A style element inside HTML does not use this header. The header is for the response whose body is the sheet. If you compress it, use Content-Encoding and leave the type as text/css. The file on disk is still .css. Once the response exists, a client trusts text/css, not the filename. Constructable stylesheets and CSS modules in a bundler never hit this header until you emit a file. The moment you emit a file, the header has to be text/css. A bundler that inlines CSS into JavaScript is shipping text/javascript, and the CSS is a string inside it, not a stylesheet response.
Content-Type for .css
Send text/css; charset=utf-8. The charset parameter names the encoding of the body. Leaving it off forces the client to guess, and for several text types the registered default is not UTF-8. Do not send a charset on a redirect. The header belongs on the response that contains the bytes.
Content-TypeContent-Type: text/css; charset=utf-8
nginx, Apache, and Express
These snippets map .css to text/css. nginx reads the types block when it picks a type from the URL's extension. A location that sets default_type, or an application that sets the header itself, overrides that map. Apache AddType applies in the directory context where you put it. The Express static example writes the header for files ending in .css so a stale mime database in the framework cannot disagree with the type on this page.
nginx# /etc/nginx/mime.types, inside the types { } block
text/css css;
charset utf-8;
charset_types text/css;
ApacheAddType text/css .css
AddCharset UTF-8 .css
Expressimport express from "express";
const app = express();
app.use(express.static("public", {
setHeaders(res, filePath) {
if (filePath.endsWith(".css")) {
res.setHeader("Content-Type", "text/css; charset=utf-8");
}
},
}));
Pitfalls for text/css
Pitfalls that show up for text/css, and not for a neighboring type with a similar extension: The bug after a CDN migration is a default type of application/octet-stream on .css, which disables the sheet and leaves an unstyled page with no obvious 404. Check the response header, not only the status. Another bug is a charset of utf-8 on a sheet that was saved as windows-1252, so non-ASCII content in a content property mojibakes. Another is an HTML error page returned with status 200 and text/html for a CSS URL. The browser drops it, correctly. Fix the status and the type together. A fourth is nosniff plus a wrong type, which removes the browser's willingness to guess.
- text/css is required. application/css is not registered and stylesheets will not apply as a linked resource.
- A cross-origin sheet also needs the right CORS headers if you read it from script. The type check is separate.
- @import of a URL that returns HTML imports nothing. The imported response needs text/css too.
- Minification must not change the encoding. A minifier that inserts a UTF-8 BOM can push an @charset rule off the first line, where it stops working.
Frequently asked questions
What happens if the type is wrong?
A linked stylesheet is not applied. Browsers require text/css, particularly when nosniff is set or the sheet is cross-origin.
Should I send a charset?
Yes. text/css; charset=utf-8. It beats an @charset rule inside the file.
Is application/css valid?
No. The registered type is text/css.
Does a style tag use this type?
No. The style element is part of the HTML document. This type is for a stylesheet response.