mirror of
https://github.com/danog/sass-site.git
synced 2024-12-15 02:47:36 +01:00
488 lines
14 KiB
Plaintext
488 lines
14 KiB
Plaintext
---
|
|
title: "@mixin and @include"
|
|
table_of_contents: true
|
|
introduction: >
|
|
Mixins allow you to define styles that can be re-used throughout your
|
|
stylesheet. They make it easy to avoid using non-semantic classes like
|
|
`.float-left`, and to distribute collections of styles in libraries.
|
|
---
|
|
|
|
{% markdown %}
|
|
Mixins are defined using the `@mixin` at-rule, which is written `@mixin <name>
|
|
{ ... }` or `@mixin name(<arguments...>) { ... }`. A mixin's name can be any
|
|
Sass identifier, and it can contain any [statement][] other than [top-level
|
|
statements][]. They can be used to encapsulate styles that can be dropped into
|
|
a single [style rule][]; they can contain style rules of their own that can be
|
|
nested in other rules or included at the top level of the stylesheet; or they
|
|
can just serve to modify variables.
|
|
|
|
[statement]: /documentation/syntax/structure#statements
|
|
[top-level statements]: /documentation/syntax/structure#top-level-statements
|
|
[style rule]: /documentation/style-rules
|
|
|
|
Mixins are included into the current context using the `@include` at-rule,
|
|
which is written `@include <name>` or `@include <name>(<arguments...>)`, with
|
|
the name of the mixin being included.
|
|
{% endmarkdown %}
|
|
|
|
{% codeExample 'mixin-include' %}
|
|
@mixin reset-list {
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
|
|
@mixin horizontal-list {
|
|
@include reset-list;
|
|
|
|
li {
|
|
display: inline-block;
|
|
margin: {
|
|
left: -2px;
|
|
right: 2em;
|
|
}
|
|
}
|
|
}
|
|
|
|
nav ul {
|
|
@include horizontal-list;
|
|
}
|
|
===
|
|
@mixin reset-list
|
|
margin: 0
|
|
padding: 0
|
|
list-style: none
|
|
|
|
|
|
@mixin horizontal-list
|
|
@include reset-list
|
|
|
|
li
|
|
display: inline-block
|
|
margin:
|
|
left: -2px
|
|
right: 2em
|
|
|
|
|
|
|
|
|
|
nav ul
|
|
@include horizontal-list
|
|
{% endcodeExample %}
|
|
|
|
{% funFact %}
|
|
Mixin names, like all Sass identifiers, treat hyphens and underscores as
|
|
identical. This means that `reset-list` and `reset_list` both refer to the
|
|
same mixin. This is a historical holdover from the very early days of Sass,
|
|
when it *only* allowed underscores in identifier names. Once Sass added
|
|
support for hyphens to match CSS's syntax, the two were made equivalent to
|
|
make migration easier.
|
|
{% endfunFact %}
|
|
|
|
{% markdown %}
|
|
## Arguments
|
|
|
|
{% comment %}
|
|
When changing this section, don't forget to change the function arguments
|
|
section as well!
|
|
{% endcomment %}
|
|
|
|
Mixins can also take arguments, which allows their behavior to be customized
|
|
each time they're called. The arguments are specified in the `@mixin` rule
|
|
after the mixin's name, as a list of variable names surrounded by parentheses.
|
|
The mixin must then be included with the same number of arguments in the form
|
|
of [SassScript expressions][]. The values of these expression are available
|
|
within the mixin's body as the corresponding variables.
|
|
|
|
[SassScript expressions]: /documentation/syntax/structure#expressions
|
|
{% endmarkdown %}
|
|
|
|
{% codeExample 'mixin-arguments' %}
|
|
@mixin rtl($property, $ltr-value, $rtl-value) {
|
|
#{$property}: $ltr-value;
|
|
|
|
[dir=rtl] & {
|
|
#{$property}: $rtl-value;
|
|
}
|
|
}
|
|
|
|
.sidebar {
|
|
@include rtl(float, left, right);
|
|
}
|
|
===
|
|
@mixin rtl($property, $ltr-value, $rtl-value)
|
|
#{$property}: $ltr-value
|
|
|
|
[dir=rtl] &
|
|
#{$property}: $rtl-value
|
|
|
|
|
|
|
|
.sidebar
|
|
@include rtl(float, left, right)
|
|
{% endcodeExample %}
|
|
|
|
{% funFact %}
|
|
Argument lists can also have trailing commas! This makes it easier to avoid
|
|
syntax errors when refactoring your stylesheets.
|
|
{% endfunFact %}
|
|
|
|
{% markdown %}
|
|
### Optional Arguments
|
|
|
|
Normally, every argument a mixin declares must be passed when that mixin is
|
|
included. However, you can make an argument optional by defining a *default
|
|
value* which will be used if that argument isn't passed. Default values use
|
|
the same syntax as [variable declarations][]: the variable name, followed by a
|
|
colon and a [SassScript expression][]. This makes it easy to define flexible
|
|
mixin APIs that can be used in simple or complex ways.
|
|
|
|
[variable declarations]: /documentation/variables
|
|
[SassScript expression]: /documentation/syntax/structure#expressions
|
|
{% endmarkdown %}
|
|
|
|
{% codeExample 'optional-arguments' %}
|
|
@mixin replace-text($image, $x: 50%, $y: 50%) {
|
|
text-indent: -99999em;
|
|
overflow: hidden;
|
|
text-align: left;
|
|
|
|
background: {
|
|
image: $image;
|
|
repeat: no-repeat;
|
|
position: $x $y;
|
|
}
|
|
}
|
|
|
|
.mail-icon {
|
|
@include replace-text(url("/images/mail.svg"), 0);
|
|
}
|
|
===
|
|
@mixin replace-text($image, $x: 50%, $y: 50%)
|
|
text-indent: -99999em
|
|
overflow: hidden
|
|
text-align: left
|
|
|
|
background:
|
|
image: $image
|
|
repeat: no-repeat
|
|
position: $x $y
|
|
|
|
.mail-icon
|
|
@include replace-text(url("/images/mail.svg"), 0)
|
|
{% endcodeExample %}
|
|
|
|
{% funFact %}
|
|
Default values can be any SassScript expression, and they can even refer to
|
|
earlier arguments!
|
|
{% endfunFact %}
|
|
|
|
{% markdown %}
|
|
### Keyword Arguments
|
|
|
|
When a mixin is included, arguments can be passed by name in addition to
|
|
passing them by their position in the argument list. This is especially useful
|
|
for mixins with multiple optional arguments, or with [boolean][] arguments
|
|
whose meanings aren't obvious without a name to go with them. Keyword
|
|
arguments use the same syntax as [variable declarations][] and [optional
|
|
arguments][].
|
|
|
|
[variable declarations]: /documentation/variables
|
|
[boolean]: /documentation/values/booleans
|
|
[optional arguments]: #optional-arguments
|
|
{% endmarkdown %}
|
|
|
|
{% codeExample 'keyword-arguments' %}
|
|
@mixin square($size, $radius: 0) {
|
|
width: $size;
|
|
height: $size;
|
|
|
|
@if $radius != 0 {
|
|
border-radius: $radius;
|
|
}
|
|
}
|
|
|
|
.avatar {
|
|
@include square(100px, $radius: 4px);
|
|
}
|
|
===
|
|
@mixin square($size, $radius: 0)
|
|
width: $size
|
|
height: $size
|
|
|
|
@if $radius != 0
|
|
border-radius: $radius
|
|
|
|
|
|
|
|
.avatar
|
|
@include square(100px, $radius: 4px)
|
|
{% endcodeExample %}
|
|
|
|
{% headsUp %}
|
|
Because *any* argument can be passed by name, be careful when renaming a
|
|
mixin's arguments... it might break your users! It can be helpful to keep the
|
|
old name around as an [optional argument][] for a while and printing a
|
|
[warning][] if anyone passes it, so they know to migrate to the new argument.
|
|
|
|
[optional argument]: #optional-arguments
|
|
[warning]: /documentation/at-rules/warn
|
|
{% endheadsUp %}
|
|
|
|
{% markdown %}
|
|
### Taking Arbitrary Arguments
|
|
|
|
Sometimes it's useful for a mixin to be able to take any number of arguments.
|
|
If the last argument in a `@mixin` declaration ends in `...`, then all extra
|
|
arguments to that mixin are passed to that argument as a [list][]. This
|
|
argument is known as an [argument list][].
|
|
|
|
[list]: /documentation/values/lists
|
|
[argument list]: /documentation/values/lists#argument-lists
|
|
{% endmarkdown %}
|
|
|
|
{% codeExample 'arbitrary-arguments' %}
|
|
@mixin order($height, $selectors...) {
|
|
@for $i from 0 to length($selectors) {
|
|
#{nth($selectors, $i + 1)} {
|
|
position: absolute;
|
|
height: $height;
|
|
margin-top: $i * $height;
|
|
}
|
|
}
|
|
}
|
|
|
|
@include order(150px, "input.name", "input.address", "input.zip");
|
|
===
|
|
@mixin order($height, $selectors...)
|
|
@for $i from 0 to length($selectors)
|
|
#{nth($selectors, $i + 1)}
|
|
position: absolute
|
|
height: $height
|
|
margin-top: $i * $height
|
|
|
|
|
|
|
|
|
|
@include order(150px, "input.name", "input.address", "input.zip")
|
|
{% endcodeExample %}
|
|
|
|
{% markdown %}
|
|
#### Taking Arbitrary Keyword Arguments
|
|
|
|
Argument lists can also be used to take arbitrary keyword arguments. The
|
|
[`meta.keywords()` function][] takes an argument list and returns any extra
|
|
keywords that were passed to the mixin as a [map][] from argument names (not
|
|
including `$`) to those arguments' values.
|
|
|
|
[`meta.keywords()` function]: /documentation/modules/meta#keywords
|
|
[map]: /documentation/values/maps
|
|
|
|
<!-- TODO(nweiz): auto-generate this CSS once we're compiling with Dart Sass -->
|
|
{% endmarkdown %}
|
|
|
|
{% render 'code-snippets/example-mixin-arbitrary-keyword-arguments' %}
|
|
|
|
{% funFact %}
|
|
If you don't ever pass an argument list to the [`meta.keywords()` function][],
|
|
that argument list won't allow extra keyword arguments. This helps callers of
|
|
your mixin make sure they haven't accidentally misspelled any argument names.
|
|
|
|
[`meta.keywords()` function]: /documentation/modules/meta#keywords
|
|
{% endfunFact %}
|
|
|
|
{% markdown %}
|
|
#### Passing Arbitrary Arguments
|
|
|
|
Just like argument lists allow mixins to take arbitrary positional or keyword
|
|
arguments, the same syntax can be used to *pass* positional and keyword
|
|
arguments to a mixin. If you pass a list followed by `...` as the last
|
|
argument of an include, its elements will be treated as additional positional
|
|
arguments. Similarly, a map followed by `...` will be treated as additional
|
|
keyword arguments. You can even pass both at once!
|
|
{% endmarkdown %}
|
|
|
|
{% codeExample 'passing-arbitrary-arguments', false %}
|
|
$form-selectors: "input.name", "input.address", "input.zip" !default;
|
|
|
|
@include order(150px, $form-selectors...);
|
|
===
|
|
$form-selectors: "input.name", "input.address", "input.zip" !default
|
|
|
|
@include order(150px, $form-selectors...)
|
|
{% endcodeExample %}
|
|
|
|
{% funFact false %}
|
|
{% markdown %}
|
|
Because an [argument list][] keeps track of both positional and keyword
|
|
arguments, you use it to pass both at once to another mixin. That makes it
|
|
super easy to define an alias for a mixin!
|
|
|
|
[argument list]: /documentation/values/lists#argument-lists
|
|
{% endmarkdown %}
|
|
|
|
{% codeExample 'passing-arbitrary-arguments-fun-fact' %}
|
|
@mixin btn($args...) {
|
|
@warn "The btn() mixin is deprecated. Include button() instead.";
|
|
@include button($args...);
|
|
}
|
|
===
|
|
@mixin btn($args...)
|
|
@warn "The btn() mixin is deprecated. Include button() instead."
|
|
@include button($args...)
|
|
{% endcodeExample %}
|
|
{% endfunFact %}
|
|
|
|
{% markdown %}
|
|
## Content Blocks
|
|
|
|
In addition to taking arguments, a mixin can take an entire block of styles,
|
|
known as a *content block*. A mixin can declare that it takes a content block
|
|
by including the `@content` at-rule in its body. The content block is passed
|
|
in using curly braces like any other block in Sass, and it's injected in place
|
|
of the `@content` rule.
|
|
{% endmarkdown %}
|
|
|
|
{% codeExample 'content-blocks' %}
|
|
@mixin hover {
|
|
&:not([disabled]):hover {
|
|
@content;
|
|
}
|
|
}
|
|
|
|
.button {
|
|
border: 1px solid black;
|
|
@include hover {
|
|
border-width: 2px;
|
|
}
|
|
}
|
|
===
|
|
@mixin hover
|
|
&:not([disabled]):hover
|
|
@content
|
|
|
|
|
|
|
|
.button
|
|
border: 1px solid black
|
|
@include hover
|
|
border-width: 2px
|
|
{% endcodeExample %}
|
|
|
|
{% funFact %}
|
|
A mixin can include multiple `@content` at-rules. If it does, the content
|
|
block will be included separately for each `@content`.
|
|
{% endfunFact %}
|
|
|
|
{% headsUp %}
|
|
A content block is *lexically scoped*, which means it can only see [local
|
|
variables][] in the scope where the mixin is included. It can't see any
|
|
variables that are defined in the mixin it's passed to, even if they're
|
|
defined before the content block is invoked.
|
|
|
|
[local variables]: /documentation/variables#scope
|
|
{% endheadsUp %}
|
|
|
|
{{ '### Passing Arguments to Content Blocks' | markdown }}
|
|
|
|
{% # Arguments are (in order): `dart`, `libsass`, `node`, `ruby`, optional feature name, additional details within %}
|
|
{% compatibility '1.15.0', false, null, false %}{% endcompatibility %}
|
|
|
|
{% markdown %}
|
|
A mixin can pass arguments to its content block the same way it would pass
|
|
arguments to another mixin by writing `@content(<arguments...>)`. The user
|
|
writing the content block can accept arguments by writing `@include <name>
|
|
using (<arguments...>)`. The argument list for a content block works just like
|
|
a mixin's argument list, and the arguments passed to it by `@content` work
|
|
just like passing arguments to a mixin.
|
|
{% endmarkdown %}
|
|
|
|
{% headsUp %}
|
|
If a mixin passes arguments to its content block, that content block *must*
|
|
declare that it accepts those arguments. This means that it's a good idea to
|
|
only pass arguments by position (rather than by name), and it means that
|
|
passing more arguments is a breaking change.
|
|
|
|
If you want to be flexible in what information you pass to a content block,
|
|
consider passing it a [map][] that contains information it may need!
|
|
|
|
[map]: /documentation/values/maps
|
|
{% endheadsUp %}
|
|
|
|
<!-- TODO(nweiz): auto-generate this CSS once we're compiling with Dart Sass -->
|
|
{% codeExample 'passing-arguments-to-content-blocks', false %}
|
|
@mixin media($types...) {
|
|
@each $type in $types {
|
|
@media #{$type} {
|
|
@content($type);
|
|
}
|
|
}
|
|
}
|
|
|
|
@include media(screen, print) using ($type) {
|
|
h1 {
|
|
font-size: 40px;
|
|
@if $type == print {
|
|
font-family: Calluna;
|
|
}
|
|
}
|
|
}
|
|
===
|
|
@mixin media($types...)
|
|
@each $type in $types
|
|
@media #{$type}
|
|
@content($type)
|
|
|
|
|
|
|
|
|
|
@include media(screen, print) using ($type)
|
|
h1
|
|
font-size: 40px
|
|
@if $type == print
|
|
font-family: Calluna
|
|
===
|
|
@media screen {
|
|
h1 {
|
|
font-size: 40px;
|
|
}
|
|
}
|
|
@media print {
|
|
h1 {
|
|
font-size: 40px;
|
|
font-family: Calluna;
|
|
}
|
|
}
|
|
{% endcodeExample %}
|
|
|
|
{% markdown %}
|
|
## Indented Mixin Syntax
|
|
|
|
The [indented syntax][] has a special syntax for defining and using mixins, in
|
|
addition to the standard `@mixin` and `@include`. Mixins are defined using the
|
|
character `=`, and they're included using `+`. Although this syntax is terser,
|
|
it's also harder to understand at a glance and users are encouraged to avoid
|
|
it.
|
|
|
|
[indented syntax]: /documentation/syntax#the-indented-syntax
|
|
{% endmarkdown %}
|
|
|
|
{% codeExample 'indented-syntax', true, 'sass' %}
|
|
=reset-list
|
|
margin: 0
|
|
padding: 0
|
|
list-style: none
|
|
|
|
=horizontal-list
|
|
+reset-list
|
|
|
|
li
|
|
display: inline-block
|
|
margin:
|
|
left: -2px
|
|
right: 2em
|
|
|
|
nav ul
|
|
+horizontal-list
|
|
{% endcodeExample %}
|