Published By Joshua Sandoval

Twitter Facebook Learn to Code: CSS At-Rules


Hello everybody it's Joshua, and welcome to the first article of 2017! I've decided to do a follow-up to the last "Learn to Code" article, this time expanding on CSS. We won't cover all the at-rules, since some are useless as there is no support, and this article will be long already (just a warning).

What is a CSS At-Rule?

Being incredibly lazy, I going to completely rip off Mozilla Docs. This is the definition of an at-rule:

An at-rule is a CSS statement beginning with an at sign, '@' (U+0040 COMMERCIAL AT), followed by an identifier and includes everything up to the next semi-colon, ';' (U+003B SEMICOLON), or the next CSS block, whichever comes first.


​Starting off all the at-rules is the "@media" rule. This will be your most frequently used CSS at-rule. No exceptions. Absolutely none. 😉

In all seriousness, media queries allow different style rules for different media types/devices.

Here's the media query syntax:

@media not|only mediatype and (media feature) { /* Media Query specific CSS */ }

We start with the "@media" rule, followed by an optional "not" or "only" value (if you read my "Don't Forget Print Stylesheets!" article you'd realise you should probably skip this value), followed by a media type and finally the media feature in parentheses.

List of useable mediatypes:

  • all (This is a declaration used for all mediatypes.)
  • print (This is a declaration used for printers.)
  • screen (This is a declaration used for computer screens, tablets, smart-phones etc.)
  • speech (This is a declaration used for screenreaders that "reads" the page out loud.)

List of useable media features:

There are many, many different types of media features, and new ones can be introduced at any time. Given the circumstances, click the link below to learn about media features before we continue into examples.

Learn more about "Media Features"

An example of how is this useful:

Let's say we want to make the font-size smaller or larger depending on the screen width, to do that we target the "screen" mediatype and the "width" media feature and adjust accordingly.

body { /* Targets anything above 600 pixels (because we override) */ font-size: 22px; }
@media screen and (max-width: 600px) /* Any screen size smaller than 600 pixels. */ { /* Media Query specific CSS */ body { /* Targets anything below 600 pixels */ font-size: 16px; } }

​This is all great, but… “where's my demonstration?” — I hear you asking. Well, making an inline demonstration on media queries isn't the easiest thing in the world… it's doable for sure, but it works well only on large screen devices, and this is a mobile friendly website, and with that comes a few lack of freedoms. Sure I could, but in any case I could think of, it wouldn't for portray what I was trying to get at… so we're stuck with explanations and not demonstrations.


The "supports" at-rule is fairly simple in what it does and how it operates. The "supports" at-rule simply allows CSS to feature check a property to see if its supported, and if said property is not supported, the developer can offer alternate CSS.

Declaration syntax:

This is the "@supports" declaration syntax. It's pretty basic, simply put, we start with the "@supports" rule, followed by parentheses containing the property and value. If the property and value within the parentheses are supported CSS in your browser, the CSS block will be active.

@supports ( property: value ) { /* Fires if the browser supports "property: value" */ }

The not operator

The not operator conditions the CSS to only fire if the statement is "not" supported by the browser.

@supports not ( property: value )

The and operator

The and operator is used to combine multiple support statements/expressions, which creates a new expression:

@supports (property: value) and (property: value)

The or operator

The or operator takes two (or more) expressions and together creates an entirely new expression consisting of a disunity of the two original expressions. — If one of the expressions (or both) in the combined expression are true, the follow-up CSS block will "activate". This is especially useful for prefixed CSS properties.

@supports (property: value) or (property: value) @supports (property: value) or (-prefix-property: value)

Combining operators and expressions

Multiple expressions/statements can be interlaced without the need of more parentheses:

@supports (property: value) and (property: value) and (property: value)

which is equivalent to:

@supports (property: value) and ( (property: value) and (property: value) )

example of combining operators:

@supports ((property: value) and (property: value)) or (property: value)

Example case of CSS supports:

Check out iOS Blur Effects in CSS for an interesting use case for the supports property.


The "font-face" rule allows a custom font-family to be added to a website. You can have multiple @font-face declarations and differenciate them by font-style, font-weight and multiple other CSS properties.

Declaration Syntax:

We start with the "@font-face" indentifier, followed by brackets and then a list of font-properties.

@font-face { font-properties }

Here's the list of font-properties:

font-family (required)

This defines the name of the font. Enclose the value in quotes.

src (required)

This defines the resource(s) where the font should be downloaded from. The parameters are "src" and "format".

font-stretch (optional)

This defines how the font should be stretched (default value is "normal").

Here is the list of properties:
  • normal
  • condensed
  • ultra-condensed
  • extra-condensed
  • semi-condensed
  • expanded
  • semi-expanded
  • extra-expanded
  • ultra-expanded

font-style (optional)

This defines how the font should be styled (default value is "normal").

Here is the list of properties:
  • normal
  • italic
  • oblique

font-weight (optional)

This defines the boldness of the font (default value is "normal").

Here is the list of properties:
  • normal
  • bold
  • 100
  • 200
  • 300
  • 400
  • 500
  • 600
  • 800
  • 900

unicode-range (optional)

This defines the range of unicode characters the font supports (default value is "U+0-10FFFF").

Defining a font with good browser support:

To get good browser support, we need to declare each of our sources, those sources being a .woff2, a .woff, and a .ttf file.

@font-face { font-family: "MyFont"; src: url("./directory/myfont.woff2") format("woff2"), url("./directory/myfont.woff") format("woff"), url("./directory/myfont.ttf") format("truetype"); }

The more types of font sources you declare, the better the browser support is, but given that these files are quite large, three really should be the maximum, and these three give the best support overall.

Defining the boldness and style of your font:

Typically, well, unless the font-file you upload includes multiple weights, you'll have to specify a separate @font-face to include your different weights and styles of font.

Here's how to define different styles of a font:

@font-face { /* Note that the font-family remains unchanged. */ font-family: "MyFont"; /* This is the property that changes the "style" of your "font". */ font-style: italic; /* Remember to change your font source. */ src: url("./directory/myfont-italic.woff2") format("woff2"), url("./directory/myfont-italic.woff") format("woff"), url("./directory/myfont-italic.ttf") format("truetype"); }

Here's how to define different weights of a font:

@font-face { /* Note that the font-family remains unchanged. */ font-family: "MyFont"; /* This is the property that changes the "weight" of your "font". */ font-weight: 600; /* Remember to change your font source. */ src: url("./directory/myfont-600.woff2") format("woff2"), url("./directory/myfont-600.woff") format("woff"), url("./directory/myfont-600.ttf") format("truetype"); }

…as you could imagine, you can combine different font-weights and font-styles to expand support.

@font-face { font-family: "MyFont"; font-style: italic; font-weight: 600; /* Remember to change your font source. */ src: url("./directory/myfont-600-italic.woff2") format("woff2"), url("./directory/myfont-600-italic.woff") format("woff"), url("./directory/myfont-600-italic.ttf") format("truetype"); }


Unlike the CSS transition property, the CSS @keyframes at-rule allows developers to control the specific steps in animating an element.

Declaration Syntax:

@keyframes identifier { from { property: value; } to { property: value; } }
/* or */
@keyframes identifier { 0% { property: value; } 100% { property: value; } }

We start with the @keyframes namespace, followed up by our custom identifier. After that, if we are dealing with a less complicated animation with only two state changes, we use a from-to syntax, otherwise we use a percentage-based syntax. And within the brackets contains whatsoever CSS properties you desire to be animated from a certain value, to another certain value.

Using your animation in a CSS block:

There are several 'animation' properties, but all is going to be shown is a basic how-to-use scenario.

@keyframes myAnimation { from { property: value; } to { property: value; } }
element { animation: myAnimation 300ms linear 50ms 1 normal none running; }
/* or… */
element { animation-name: myAnimation; animation-duration: 300ms; animation-timing-function: linear; animation-timing-delay: 50ms; animation-iteration-count: 1; animation-direction: normal; animation-fill-mode: none; animation-fill-play-state: running; }

Please note that most of these properties are optional, and also that keyframes and the animation property themselves come in various browser prefixes.

…now some final notices:

When an keyframe identifier is duplicated:

Despite it being CSS, @keyframes do not cascade. The only thing that happens when a duplicate indentifier for a keyframe is used, is that the existing keyframe is overriden and deleted.

!important in a keyframe:

Simply put, the !important declaration is ignored within keyframes.

When a keyframe is defined multiple times:

When and where a keyframe (not @keyframes) is defined multiple times, the previous keyframe will be dropped and only the properties within the new keyframe will be animated/used.

When properties are left out of some keyframes

Properties that aren't specified in every keyframe are interpolated into the remaining keyframes until changed by the developer.

…and that's it. Thanks for reading, and thanks for learning.