CSS Mixins

Contents

Creating mixins via the @mixin rule

Mixins allow document authors to define patterns of property value pairs, which can then be reused in other rulesets. The mixin name is a class selector that identifies the mixin being declared. The @mixin keyword must be followed by the mixin name and a declaration block.

The following lines define a mixin clearfix, and give it three property-value pairs:

@mixin .clearfix {
  overflow: hidden;
  _overflow: visible;
  zoom: 1;
}

Document authors may use mixins to group vendor prefixes and simplify their code during the time it takes for vendors to stabilize their implementations.

The following example groups various vendor prefixes for border-radius:

@mixin .rounded7px {
  -moz-border-radius: 7px;
  -webkit-border-radius: 7px;
  border-radius: 7px;
} 

Media dependent mixins

Authors may specify media-dependent @mixins. They are specified via comma separated media types after the URI.

The following lines illustrate how @mixins can be made media-dependent:

@variables .clearfix @media print {
  overflow: visible;
}

In the absence of any media types, the mixin rule is unconditional. Specifying 'all' for the medium has the same effect. The mixins only take effect if the target medium matches the media list. A target medium matches a media list in the same cases that it would for @import.

Referencing a mixin via the include property

The 'include' property

'include'
Value:   [<selector>] [, <selector>]*
Initial:   none
Applies to:   all
Inherited:   no
Percentages:   N/A
Media:   all
Computed value:   as specified

Include allows the property value pairs in an @mixin to be copied into the current declaration block. An include consists of the include keyword, followed by a colon (:), followed by a value. Around each of these there may be white space. The value may be a simple selector or a comma separated list of simple selectors.

Values have the following meanings:

<selector>
A simple selector which must be a class name.

The following ruleset includes the .clearfix mixin in the .mainContent declaration block:

.mainContent {
  include: .clearfix;
}

Selectors may import multiple mixins via a comma separated list of mixin names. The rulesets are imported in the order they are referenced.

The following ruleset includes both '.clearfix' and '.rounded7px':

.mainContent {
  include: .clearfix, .rounded7px;
}

Undefined mixins

If an included mixin has not been defined, user agents should ignore property value pairs according to the normal rules for invalid constructs and, if the UA provides an API to the document author, it should issue a warning.

In the following example, .mainContent includes .undefinedMixin. The user agent should ignore the include because the mixin has not previously been defined:

.mainContent {
  include: .undefinedMixin;
}

If one of the mixins is undefined, the defined mixins are included normally and only the undefined mixin is ignored.

The following example includes both the defined mixin .clearfix and the undefined mixin .undefinedMixin. The user agent should include .clearfix normally and ignore .undefinedMixin.

.mainContent {
  include: .clearfix, .undefinedMixin;
}

Processing mixins

User agents must copy the mixin declaration block into the current ruleset each time the value matches the selector of an @mixin rule. The specificity and cascading order should be interpreted as if the included declaration block was invoked within the current ruleset. Differences between declared values and imported values should be resolved via the cascade order.

The following example illustrates a difference between declared and imported values because clearfix sets overflow to hidden and the current selector sets it to scroll. The user agent should interpret the selector to overflow scroll because that declaration came after the imported ruleset: @@@rework wording@@@

.mainContent {
  include: .clearfix;
  overflow: scroll;
}

Duplication and mixins

When the include property is declared more than once, conflicts are resolved according to the normal rules for the cascade. The latter include takes precedence.

In the following example the second include, bar, overwrites the first. Therefore, only .bar property value pairs are included:

include: .foo;
include: .bar;

Mixins and pseudo classes

Once a class name has been associated with a mixin, that class may be used as a part of a complex selector.

The following example defines an empty mixin clearfix and then applies rules to the :after pseudo class of clearfix:

@mixin .clearfix {
}

.clearfix:after {
  content: ".";
  display: block;
  height: 0;
  clear: both;
  visibility: hidden;
}

.mainContent {
  include: .clearfix;
}

When mainContent includes clearfix, it also includes the rules applied to pseudo classes like :after. In effect, .mainContent:after has all the same properties as .clearfix:after.

Multinode mixins

Mixins may have sub-nodes. When a mixin name is part of a complex selector, composed of multiple simple selectors, the styles applied to the subnodes will also be applied to the subnodes of the object that included the mixin.

In the following example, we've abstracted the code necessary to insure sufficient text-contrast on dark background colors. The paragraphs inside .sale and .help will also have white text:

body {
  color: #333;
  background-color: #fff;
}
@mixin .contrastAdjust {
}
.contrastAdjust p {
  color: #fff;
}
.sale {
  background-color: red;
  include: .contrastAdjust;
}  
.help {
	background-color: blue;
  include: .contrastAdjust;
} 

Imagine that we wanted to use the mixin .rounded7px on a more complex object. This one has two subnodes; a title and a paragraph. If we wanted all three to have rounded corners, we might need to apply the mixin to its subnodes. @@@not a great example because it links container and content@@@

Consider the following snippet of HTML:

<div class="article">
<h3>Movie: The Last Unicorn (1982)</h3>
<p>I have seen very few films that have actually brought me close to tears, and most of those movies are ones I didn't like. The Last Unicorn is an especially ... (IMDB)</p>
</div>

In the following example, the mixin .rounded7px applies a border radius to both itself and a subnodes p and h3:

@mixin .rounded7px, 
.rounded7px p, .rounded7px h3 {
  -moz-border-radius: 7px;
  -webkit-border-radius: 7px;
  border-radius: 7px;
}

When .rounded7px is included in entry, post, and article, the h3 and p subnodes inherits the rules defined for .rounded7px .inner:

.entry {
  background-color: blue;

  include: .rounded7px;
}
.post {
  background-color: green;
  include: .rounded7px;
}
.article {
  background-color: red;
  include: .rounded7px;
}

User agents should interpret the following code the same way they would the example the preceeded it:

.entry {
  background-color: blue;
}
.entry p, .entry h3 {
  -moz-border-radius: 7px;
  -webkit-border-radius: 7px;
  border-radius: 7px;
}
.post {
  background-color: green;
}
.post p, .post h3 {
  -moz-border-radius: 7px;
  -webkit-border-radius: 7px;
  border-radius: 7px;
}
.article {
  background-color: red;
}
.article p, .article h3 {
  -moz-border-radius: 7px;
  -webkit-border-radius: 7px;
  border-radius: 7px;
}

An obvious advantage of using include is the reduction in code sent over the wire while at the same time allowing grouping of related code. The same could be accomplished using either a preprocessor or comma separated selectors, but those would not simultaneously achieve those two objectives.

Complex selectors

Includes may only refer to a single class name which has been declared using the @mixin rule, and may not reference a complex selector string. User agents should ignore includes that refer to a complex selector.

The following example is incorrect and should be ignored by the UA. It includes a complex selector html body .foo:

include: html body .foo;

Mixins and the cascade

The ruleset associated with a mixin is treated as though it were declared in the location where the include property was specified.

Mixins and specificity

Mixins do not impact the specificity of the ruleset in which they are invoked.