HTML and CSS course ยท Module 3: CSS Basics

CSS Prefixes

6 min read ยท
In this lesson6

In an old stylesheet you find several almost identical lines: -webkit-border-radius, -moz-border-radius, and finally a plain border-radius. It looks like a mess, but once it was the only way to make a new property work in every browser. These additions are browser prefixes (vendor prefixes).

Prefixes in CSS are used to ensure compatibility with different browsers, especially when it comes to newer or experimental properties and features. They are special prefixes added to some CSS rules to help different browsers interpret these rules. Think of the Rosetta Stone: the same decree was carved on it in three scripts - hieroglyphs, Demotic and Greek - so that anyone who knew at least one of them could read it. Prefixes work in a similar way: you write the same declaration in several "dialects", and each browser reads the one it understands.

1. Why Are Prefixes Important?

Not all browsers support all CSS properties the same way, especially when it comes to newer features. Prefixes help ensure that these properties will work correctly in different browsers. When a browser maker introduced a new, not yet standardized property, it added it with its own prefix - so it could experiment without breaking the future standard version.

Here are the most commonly used browser prefixes:

  • -webkit-: for browsers based on the WebKit engine, such as Safari, and also for Chrome and newer versions of Opera and Microsoft Edge, whose Blink engine grew out of WebKit.
  • -moz-: for browsers based on Firefox (Mozilla).
  • -o-: for older versions of Opera.
  • -ms-: for Internet Explorer and older versions of Microsoft Edge, from before the switch to the Chromium engine.

3. How to Apply Prefixes?

Prefixes are applied by adding them before the name of the CSS property. The order matters: first the prefixed versions, and the standard version at the very end. This is what a rule with the border-radius property looked like back when it was still new:

div {
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
  -ms-border-radius: 10px;
  -o-border-radius: 10px;
  border-radius: 10px; /* standard version */
}

The browser reads declarations from the top and skips those it doesn't understand. If it knows several versions of the same property, the one written lowest applies - that's why the standard version comes last and always wins over the earlier experiment. Treat this example as a lesson in order: today border-radius works without prefixes in all browsers, and the -ms- and -o- versions of this property were never needed, because Internet Explorer and Opera supported the standard notation from the start.

4. Tools and Autoprefixer

Manually adding prefixes to every new property can be tedious and inconvenient. Fortunately, there are tools like Autoprefixer that can automatically add required prefixes to your stylesheet. Look at the following code - only standard properties, without a single prefix:

.my-element {
  transform: rotate(45deg);
  animation: my-animation 5s infinite;
  box-shadow: 10px 10px 5px #888;
  border-radius: 10px;
}

@keyframes my-animation {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

This is how you write every day: once, readably, in the standard version. If you paste this code into Autoprefixer Online and set it to support very old browsers, you'll get roughly the following result:

.my-element {
  -webkit-transform: rotate(45deg); /* Chrome, Safari, Opera */
  -moz-transform: rotate(45deg);    /* Firefox */
  -ms-transform: rotate(45deg);     /* IE 9 */
  -o-transform: rotate(45deg);      /* Older Opera */
  transform: rotate(45deg);         /* Standard */

  -webkit-animation: my-animation 5s infinite; /* Chrome, Safari, Opera */
  -moz-animation: my-animation 5s infinite;    /* Firefox */
  -ms-animation: my-animation 5s infinite;     /* IE 10+ */
  -o-animation: my-animation 5s infinite;      /* Older Opera */
  animation: my-animation 5s infinite;         /* Standard */

  -webkit-box-shadow: 10px 10px 5px #888; /* Chrome, Safari, Opera */
  -moz-box-shadow: 10px 10px 5px #888;    /* Firefox */
  box-shadow: 10px 10px 5px #888;         /* Standard */

  -webkit-border-radius: 10px; /* Chrome, Safari, Opera */
  -moz-border-radius: 10px;    /* Firefox */
  border-radius: 10px;         /* Standard */
}

@-webkit-keyframes my-animation {
  from { -webkit-transform: rotate(0deg); }
  to { -webkit-transform: rotate(360deg); }
}

@-moz-keyframes my-animation {
  from { -moz-transform: rotate(0deg); }
  to { -moz-transform: rotate(360deg); }
}

@-ms-keyframes my-animation {
  from { -ms-transform: rotate(0deg); }
  to { -ms-transform: rotate(360deg); }
}

@-o-keyframes my-animation {
  from { -o-transform: rotate(0deg); }
  to { -o-transform: rotate(360deg); }
}

@keyframes my-animation {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

This is what stylesheets looked like when they had to work in browsers from more than a decade ago - the comments show which browser read which line. Not every line was actually needed: Internet Explorer 10 supported animations without a prefix, so -ms-animation and @-ms-keyframes are redundant. Autoprefixer checks the Can I use database for what the browsers listed in your configuration (Browserslist) really require, and adds only those prefixes. With today's default settings, it adds almost nothing to this code.

5. Do You Still Need Prefixes Today?

Although prefixes are useful, it's worth remembering that not all properties require them, and some may already be widely supported by most browsers. Checking documentation and using browser compatibility testing tools can help you understand when and how to apply prefixes.

Browser makers are moving away from prefixes today: they hide experimental features behind flags in the settings, and only standard versions reach websites. There are still a few properties that work only with the -webkit- prefix, though, so before using something new, check the compatibility table on MDN or on the Can I use website. My advice: don't add prefixes by hand - write standard properties and leave the prefixes to Autoprefixer.

Practice

In the editor below, an Egyptian page is waiting to be colored - fill in the missing colors according to the comments. Then add a rule for the image with border-radius: 10px in the <style> tag, without any prefix, and check that the corners of the fresco are rounded:

Code for this lesson: index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ancient Egypt</title>
    <style>
        /* Add your CSS styles here */
        /* 1. Set the h1 heading color to dark gold (#7A5C00) */
        /* 2. Set the body background color to sandy (#F4E4C1) */
        /* 3. Set the p text color to dark brown (#4A3C2A) */

        body {
            /* background-color: ??? */
            font-family: serif;
            padding: 20px;
        }

        h1 {
            /* color: ??? */
            text-align: center;
        }

        p {
            /* color: ??? */
            line-height: 1.6;
        }
    </style>
</head>
<body>
    <h1>Pyramids of Ancient Egypt</h1>
    <p>Pyramids were built as tombs of pharaohs. The largest of them - the Pyramid of Cheops - is one of the seven wonders of the ancient world.</p>
    <img src="https://placehold.co/400x200/FFD700/4A3C2A?text=Egyptian+Fresco" alt="Egyptian fresco" style="display:block;margin:20px auto;">
</body>
</html>

Remember: prefixes are the Rosetta Stone of CSS - the same notation in several dialects, with the standard version always at the end, and today Autoprefixer writes them for you.

Docs entries used in this lesson

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. Why are vendor prefixes used in CSS?

  2. 2. Which prefix is used for browsers based on the WebKit engine (Safari)?

These are 2 of 3 questions for this lesson. Solve the rest in the game.

Hands-on tasks in the game

  • Vertical ordering

    Arrange the transform declarations so the standard version comes last:

Useful articles