Skip to content

Writing styles

Rob Garrison edited this page Aug 21, 2018 · 48 revisions

Writing styles

  1. Applying styles to specific sites
    1. Rule types
    2. Syntax
    3. Multiple sites
    4. Advanced matching with Regular Expressions
    5. Valid @-moz-document rules
  2. Preventing global styles
  3. Embed images in styles
  4. Selecting specific elements on a page
  5. Overwriting page styles
    1. Specificity
    2. Inline !important
    3. Replacing images in img tags

Writing styles

Writing a user style from scratch requires a working knowledge of HTML external link and CSS external link. It is also very helpful to know how to use external link your browser's DOM inspector external link (usually Ctrl + Shift + C or right-click on an element and choose "Inspect Element"). For those who have limited knowledge of CSS, it's recommended to take an existing style that does something similar to what you want, and attempt to understand and modify it to suit your needs.

There are two style formats: The classic one with plain CSS (can be uploaded to userstyles.org external link as "Mozilla Format") and the more flexible UserCSS format, which additionally allows style options, preprocessing (LESS external link / Stylus-language external link ) and self-hosting or uploading to openusercss.org external link.

Applying styles to specific sites

Styles are applied only to certain URLs defined by @-moz-document external link rules.
In Stylus, these rules are autoconverted into more convenient "applies to" fields which can be controlled via user interface and which can split the CSS code into several sections. So usually you will see the literal @-moz-document rules only in Mozilla Format (when exporting or editing on userstyles.org) or in UserCSS if you set the corresponding option.
Speaking differently, @-moz-document rules must not appear inside code sections - it's completely controlled by the "applies to" fields.

Example Mozilla Format code as you would copy and paste it Mozilla Format

The same style as shown in Stylus Stylus format

Rule types

There are four @-moz-document rule types:

  • domain for all URLs on a domain or subdomain (not including the protocol)
  • url-prefix for URLs that start with the exact string (including the protocol)
  • url for exact URLs (including the protocol)
  • regexp for advanced matching with wildcards (including the protocol)

Syntax

@-moz-document rules are specified on the "outside" of normal CSS, just like @media rules. Quotes around the URL are recommended external link. Backslashes inside RegExp must be escaped by another backslash for CSS. Make sure not to forget the closing curly bracket at the end.

A rule to turn the background of https://www.example.com/test.html green would look like this:

@-moz-document url("https://www.example.com/test.html") {
    body {
        background-color: green !important;
    }
}

Multiple sites

Just like you can create a rule in CSS for multiple selectors, you can specify multiple values per @-moz-document block by separating them with commata. For example:

@-moz-document domain("images.example.com"),
               domain('imagehost.com'),
               url-prefix(https://example.com/images),
               url(https://www.example.com/test.html) {
    /*
        The code in here only applies to:
            - Pages on the domains images.example.com and imagehost.com
            - Pages whose URLs start with https://example.com/images
            - The page https://www.example.com/test.html
    */
}

Often, single sites can be accessed on many different URLs and can contain many different kinds of pages. For example, a rule like:

@-moz-document url-prefix("http://www.example.com/")

would not apply to http://example.com/, https://www.example.com/ or http://www.example.com.au/.
You should keep this in mind (and try to account for it!) when writing your @-moz-document rules, especially if you intend on publishing your style for others to use.

Advanced matching with Regular Expressions

Regular Expressions external link (RegExp) offer a powerful way to specify which URLs the style should apply to. RegExp are not recommended when the url, url-prefix, and domain rule types will also do the job, as RegExp are more difficult to understand and more likely to target more than you wanted.

Although there are good external link tutorials external link and pages to test external link and analyze external link your RegExp, in most cases it is sufficient to copy and modify the following examples.

The RegExp you write must match the entirety of the URL. This means that using ^ and $ (to match the beginning and end of the string) are unnecessary.

RegExp must be escaped using CSS syntax. For example a ? is a control character in RegExp. To match a literal question mark, you would first need to escape it using RegExp rules to \?, then escape that string using CSS rules to \\?. If you are using the "applies to" field, standard RegExp escaping (\?) will be sufficient there.

Valid @-moz-document rules

Domain

Domain rules should just be the domain name, without protocol, port, or wildcards. A domain rule will affect all pages on that domain and all of its subdomains.

  • Valid examples:

    • @-moz-document domain("example.com")
    • @-moz-document domain("www.example.com")
  • Invalid examples:

    • @-moz-document domain("*.example.com")
    • @-moz-document domain("http://www.example.com/")
    • @-moz-document domain("example.com:80")

URL

URL rules should contain a URL you want to affect, including protocol. Wildcards are not permitted.

  • Valid examples:

    • @-moz-document url("http://www.example.com/page.html")
  • Invalid examples:

    • @-moz-document url("www.example.com/page.html")
    • @-moz-document url("example.com")
    • @-moz-document url("http://www.example.com/*")

Be aware of inconsistent behaviour of html anchors (#):

@-moz-document url("http://example.com/page.html#firstheading") will not match http://example.com/page.html, but
@-moz-document url("http://example.com/page.html") will match http://example.com/page.html#firstheading.

URL prefix

URL prefix rules should contain the start of URLs you want to affect, including protocol. Wildcards are not permitted.

  • Valid examples:

    • @-moz-document url-prefix("http://www.example.com/")
    • @-moz-document url-prefix("http://www.example.")
    • @-moz-document url-prefix("http:")
  • Invalid examples:

    • @-moz-document url-prefix("www.example.com/page.html")
    • @-moz-document url-prefix("example.com")
    • @-moz-document url-prefix("http://*.example.com/")

RegExp

Valid examples:
  • Alternative terms

    @-moz-document regexp("http://www\\.example\\.(com|de|org)/images/.*")

    Applies to URLs that start with:

    • http://www.example.com/images/
    • http://www.example.de/images/
    • http://www.example.org/images/
  • Optional character and an exact URL ending

    @-moz-document regexp("https?://www\\.(example|test)\\.com/")

    Applies just to these four exact URLs:

    • http://www.example.com/
    • https://www.example.com/
    • http://www.test.com/
    • https://www.test.com/
  • Negative lookahead - match everything except any pages on www.example.com

    @-moz-document regexp("(?!https?://www\\.example\\.com/).*")

  • Negative lookahead - match everything except any pages on www.aaa.com, www.bbb.com, and ccc.org

    @-moz-document regexp("(?!https://(www\\.aaa\\.com|www\\.bbb\\.com|ccc\\.org)/).*")

    You can group aaa and bbb since they share www and com:

    @-moz-document regexp("(?!https://(www\\.(aaa|bbb)\\.com|ccc\\.org)/).*")

  • Negative lookahead - match everything except a specific section of a site

    @-moz-document regexp("http://www\\.example\\.com/(?!members).*")

    Applies to all URLs on http://www.example.com/, except those beginning with http://www.example.com/members

Invalid examples:
  • @-moz-document regexp("example")

    would not match http://www.example.com/ or anything URL-like, for that matter.

Sometimes you may encounter RegExps containing URLs with unescaped dots (. instead of \\.). This is technically wrong, but practically might be acceptable because . in RegExp stands for "any character". So using www.aaa.com is unlikely to fail because you probably won't visit a site like https://wwwxaaaxcom.org or https://www.wwwfaaafcom.com.

Furthermore not escaping slashes / when using RegExp in the Stylus context is ok, too.

Preventing global styles

Global styles are styles that will be applied to all sites the user visits. Some style authors will accidentally post global styles to userstyles.org when they intend to post styles that are more specific. If you use the "applies to" controls to limit what site your style is active on, you need to export the style in "Mozilla Format" before copying and posting the code to userstyles.org.

Embed images in styles

If your style requires small images, it's often useful to embed these images inside the style. Doing so eliminates the delay and necessity in downloading the image from a server and gurantees availability.

Data URIs external link can be used to embed images in styles. These URIs include the encoded image, so are very long. To generate data URIs you can use the data URI kitchen external link.

Note that styles posted to userstyles.org are limited to 250 kB, so you will quickly run out of room if you're using large images.

Selecting specific elements on a page

User styles, just like regular stylesheets, select specific elements external link using CSS selectors external link.

When writing HTML, you can modify the markup to more easily apply CSS by including IDs and classes. When writing user styles, you of course cannot control the HTML markup. This means that sometimes you need to get creative to match the elements you want. There are a few strategies you can use:

For example, given this markup:

<table id="prices">
    <tbody>
        <tr>
            <td>Hamburger</td>
            <td>$5.00</td>
        </tr>
        <tr>
            <td>Hot dog</td>
            <td>$4.00</td>
        </tr>
        <tr>
            <td>Taco</td>
            <td>$5.25</td>
        </tr>
    </tbody>
</table>

If you wanted to right-align the second column, you could use this selector:

#prices td:nth-child(2)

Given this markup:

<div class="container">
    <p>Paragraph one</p>
    <p>Paragraph two</p>
    <p>Maybe the number of paragraphs changes per page.</p>
    <p style="float: right">A floating aside on the page.</p>
    <p>More paragraphs...</p>
</div>

If we wanted to hide the floating paragraph, a type selector with a combinator (e.g. .container p) would not work because it's the same element type as the other content (thus would hide all paragraphs).
A structural pseudo-class (e.g. .container p:nth-of-type(3)) would not work because the number of paragraphs is variable.
Instead, we can use an attribute selector:

.container p[style="float: right"] {
    display: none !important;
}

Overwriting page styles

An important consideration when writing user styles is that your style rules often need to override existing rules. Which rule wins if two rules apply to the same property of the same element is determined by CSS cascade rules external link.

It's recommended that all your declarations include the !important keyword. This will give your rules the best chance of applying without additional changes. An example of !important:

a {
    text-decoration: none !important;
}

Specificity

If two rules have the same !importance, the one with the highest specificity external link wins. You can artificially increase your specificity by writing longer selectors (also see specificity calculator external link ). As an example, consider the following HTML markup:

<div id="foo">
    <span class="bar">text</span>
</div>

And the site specifies the CSS:

span {
    color: red !important;
}

You can now make sure that you win by using a more specific selector than the given span, like div > span, .bar, div .bar, #foo .bar, div#foo > span.bar etc.

In the event of equal importance and specificity, the latest defined rule wins. That is not just inside your stylesheet, but also how and at what point the stylesheet is applied in the HTML. Stylus tries to ensure highest possible specificity for you, but things may vary depending on the browser you use. So if you encounter compability issues that are no cross-browser display errors, try to increase the specificity of the selector.

Using @namespace or AGENT_SHEET is obsolete.

Inline !important

If you stumble upon an inline style spiked !important, you have no chance of overwriting with Stylus:

<p id="notice" style="text-decoration: underline !important;">
This text will always be underlined.
</p>

In some cases you might bypass it by giving another css property that excludes the unwanted one (e.g. ditch an inline display:block !important by float:left) but in general you need JavaScript external link for that.

You can apply custom JavaScript as UserScript to sites via extensions like Tampermonkey external link or Greasemonkey external link. Something simple like

// ==UserScript==
// @name         Example.com inline important CSS overwrite
// @match        https://example.com/*
// ==/UserScript==

document.getElementById("notice").setAttribute("text-decoration", "none");

should do the job.

Replacing images in img tags

While replacing background images is easy with CSS, replacing images created with <img> tags is not. You need to do the following trick to switch <img> tag images.

#your-selector-here {
    height: 0 !important;
    width: 0 !important;
    /* these numbers match the new image's dimensions */
    padding-left: 125px !important;
    padding-top: 25px !important;
    background: url("http://example.com/your/image/here.jpg") no-repeat !important;
}

Depending on the HTML you have to deal with, other external link techniques external link may be the solution.

Clone this wiki locally