Convert remainder of docs to md

This commit is contained in:
Jonny Gerig Meyer 2023-06-22 15:11:18 -04:00
parent 69ee85ae0d
commit 9ac3302fd0
No known key found for this signature in database
22 changed files with 1230 additions and 1354 deletions

View File

@ -24,15 +24,13 @@ introduction: >
border-radius: $size * 0.5
{% endcodeExample %}
{% markdown %}
## Interpolation
## Interpolation
A property's name can include [interpolation][], which makes it possible to
dynamically generate properties as needed. You can even interpolate the entire
property name!
A property's name can include [interpolation][], which makes it possible to
dynamically generate properties as needed. You can even interpolate the entire
property name!
[interpolation]: /documentation/interpolation
{% endmarkdown %}
[interpolation]: /documentation/interpolation
{% codeExample 'interpolation' %}
@mixin prefix($property, $value, $prefixes) {
@ -57,15 +55,13 @@ introduction: >
@include prefix(filter, grayscale(50%), moz webkit)
{% endcodeExample %}
{% markdown %}
## Nesting
## Nesting
Many CSS properties start with the same prefix that acts as a kind of
namespace. For example, `font-family`, `font-size`, and `font-weight` all
start with `font-`. Sass makes this easier and less redundant by allowing
property declarations to be nested. The outer property names are added to the
inner, separated by a hyphen.
{% endmarkdown %}
Many CSS properties start with the same prefix that acts as a kind of namespace.
For example, `font-family`, `font-size`, and `font-weight` all start with
`font-`. Sass makes this easier and less redundant by allowing property
declarations to be nested. The outer property names are added to the inner,
separated by a hyphen.
{% codeExample 'nesting' %}
.enlarge {
@ -90,11 +86,9 @@ introduction: >
font-size: 36px
{% endcodeExample %}
{% markdown %}
Some of these CSS properties have shorthand versions that use the namespace as
the property name. For these, you can write both the shorthand value *and* the
more explicit nested versions.
{% endmarkdown %}
Some of these CSS properties have shorthand versions that use the namespace as
the property name. For these, you can write both the shorthand value *and* the
more explicit nested versions.
{% codeExample 'nesting-shorthand' %}
.info-page {
@ -110,16 +104,14 @@ introduction: >
top: 2px
{% endcodeExample %}
{% markdown %}
## Hidden Declarations
## Hidden Declarations
Sometimes you only want a property declaration to show up some of the time. If
a declaration's value is [`null`][] or an empty [unquoted string][], Sass
won't compile that declaration to CSS at all.
Sometimes you only want a property declaration to show up some of the time. If a
declaration's value is [`null`][] or an empty [unquoted string][], Sass won't
compile that declaration to CSS at all.
[`null`]: /documentation/values/null
[unquoted string]: /documentation/values/strings#unquoted
{% endmarkdown %}
[`null`]: /documentation/values/null
[unquoted string]: /documentation/values/strings#unquoted
{% codeExample 'hidden-declarations' %}
$rounded-corners: false;
@ -136,37 +128,34 @@ introduction: >
border-radius: if($rounded-corners, 5px, null)
{% endcodeExample %}
{% markdown %}
## Custom Properties
## Custom Properties
{% compatibility 'dart: true', 'libsass: "3.5.0"', 'ruby: "3.5.0"', 'feature: "SassScript Syntax"' %}
Older versions of LibSass and Ruby Sass parsed custom property declarations
just like any other property declaration, allowing the full range of
SassScript expressions as values. Even when using these versions, it's
recommended that you use interpolation to inject SassScript values for
forwards-compatibility.
{% compatibility 'dart: true', 'libsass: "3.5.0"', 'ruby: "3.5.0"', 'feature: "SassScript Syntax"' %}
Older versions of LibSass and Ruby Sass parsed custom property declarations
just like any other property declaration, allowing the full range of
SassScript expressions as values. Even when using these versions, it's
recommended that you use interpolation to inject SassScript values for
forwards-compatibility.
See [the breaking change page][] for more details.
See [the breaking change page][] for more details.
[the breaking change page]: /documentation/breaking-changes/css-vars
{% endcompatibility %}
[the breaking change page]: /documentation/breaking-changes/css-vars
{% endcompatibility %}
[CSS custom properties][], also known as CSS variables, have an unusual
declaration syntax: they allow almost any text at all in their declaration
values. What's more, those values are accessible to JavaScript, so any value
might potentially be relevant to the user. This includes values that would
normally be parsed as SassScript.
[CSS custom properties][], also known as CSS variables, have an unusual
declaration syntax: they allow almost any text at all in their declaration
values. What's more, those values are accessible to JavaScript, so any value
might potentially be relevant to the user. This includes values that would
normally be parsed as SassScript.
[CSS Custom Properties]: https://developer.mozilla.org/en-US/docs/Web/CSS/--*
[CSS Custom Properties]: https://developer.mozilla.org/en-US/docs/Web/CSS/--*
Because of this, Sass parses custom property declarations differently than
other property declarations. All tokens, including those that look like
SassScript, are passed through to CSS as-is. The only exception is
[interpolation][], which is the only way to inject dynamic values into a
custom property.
Because of this, Sass parses custom property declarations differently than other
property declarations. All tokens, including those that look like SassScript,
are passed through to CSS as-is. The only exception is [interpolation][], which
is the only way to inject dynamic values into a custom property.
[interpolation]: /documentation/interpolation
{% endmarkdown %}
[interpolation]: /documentation/interpolation
{% codeExample 'custom-properties' %}
$primary: #81899b;
@ -197,16 +186,14 @@ introduction: >
--consumed-by-js: $primary
{% endcodeExample %}
{% headsUp false %}
{% markdown %}
Unfortunately, [interpolation][] removes quotes from strings, which makes it
difficult to use quoted strings as values for custom properties when they
come from Sass variables. As a workaround, you can use the [`meta.inspect()`
function][] to preserve the quotes.
{% headsUp %}
Unfortunately, [interpolation][] removes quotes from strings, which makes it
difficult to use quoted strings as values for custom properties when they come
from Sass variables. As a workaround, you can use the [`meta.inspect()`
function][] to preserve the quotes.
[interpolation]: /documentation/interpolation
[`meta.inspect()` function]: /documentation/modules/meta#inspect
{% endmarkdown %}
[interpolation]: /documentation/interpolation
[`meta.inspect()` function]: /documentation/modules/meta#inspect
{% codeExample 'custom-properties-strings-meta' %}
@use "sass:meta";

View File

@ -23,14 +23,11 @@ introduction: >
border: 1px solid #e1e4e8
{% endcodeExample %}
{% markdown %}
## Nesting
## Nesting
But Sass wants to make your life easier. Rather than repeating the same
selectors over and over again, you can write one style rules inside another.
Sass will automatically combine the outer rule's selector with the inner
rule's.
{% endmarkdown %}
But Sass wants to make your life easier. Rather than repeating the same
selectors over and over again, you can write one style rules inside another.
Sass will automatically combine the outer rule's selector with the inner rule's.
{% render 'code_snippets/example-nesting' %}
@ -41,14 +38,11 @@ introduction: >
render it. Keep those selectors shallow!
{% endheadsUp %}
{% markdown %}
### Selector Lists
### Selector Lists
Nested rules are clever about handling selector lists (that is,
comma-separated selectors). Each complex selector (the ones between the
commas) is nested separately, and then they're combined back into a selector
list.
{% endmarkdown %}
Nested rules are clever about handling selector lists (that is, comma-separated
selectors). Each complex selector (the ones between the commas) is nested
separately, and then they're combined back into a selector list.
{% codeExample 'selector-lists' %}
.alert, .warning {
@ -66,15 +60,13 @@ introduction: >
padding-bottom: 0
{% endcodeExample %}
{% markdown %}
### Selector Combinators
### Selector Combinators
You can nest selectors that use [combinators][] as well. You can put the
combinator at the end of the outer selector, at the beginning of the inner
selector, or even all on its own in between the two.
You can nest selectors that use [combinators][] as well. You can put the
combinator at the end of the outer selector, at the beginning of the inner
selector, or even all on its own in between the two.
[combinators]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors#Combinators#Combinators
{% endmarkdown %}
[combinators]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors#Combinators#Combinators
{% codeExample 'selector-combinators' %}
ul > {
@ -115,27 +107,24 @@ introduction: >
opacity: 0.8
{% endcodeExample %}
{% markdown %}
### Advanced Nesting
### Advanced Nesting
If you want to do more with your nested style rules than just combine them in
order with the descendant combinator (that is, a plain space) separating them,
Sass has your back. See the [parent selector documentation][] for more
details.
If you want to do more with your nested style rules than just combine them in
order with the descendant combinator (that is, a plain space) separating them,
Sass has your back. See the [parent selector documentation][] for more details.
[parent selector documentation]: /documentation/style-rules/parent-selector
[parent selector documentation]: /documentation/style-rules/parent-selector
## Interpolation
## Interpolation
You can use [interpolation][] to inject values from [expressions][] like
variables and function calls into your selectors. This is particularly useful
when you're writing [mixins][], since it allows you to create selectors from
parameters your users pass in.
You can use [interpolation][] to inject values from [expressions][] like
variables and function calls into your selectors. This is particularly useful
when you're writing [mixins][], since it allows you to create selectors from
parameters your users pass in.
[interpolation]: /documentation/interpolation
[expressions]: /documentation/syntax/structure#expressions
[mixins]: /documentation/at-rules/mixin
{% endmarkdown %}
[interpolation]: /documentation/interpolation
[expressions]: /documentation/syntax/structure#expressions
[mixins]: /documentation/at-rules/mixin
{% codeExample 'interpolation' %}
@mixin define-emoji($name, $glyph) {
@ -167,13 +156,11 @@ introduction: >
worrying that it won't parse.
{% endfunFact %}
{% markdown %}
You can combine interpolation with the parent selector `&`, the [`@at-root`
rule][], and [selector functions][] to wield some serious power when
dynamically generating selectors. For more information, see the [parent
selector documentation][].
You can combine interpolation with the parent selector `&`, the [`@at-root`
rule][], and [selector functions][] to wield some serious power when dynamically
generating selectors. For more information, see the [parent selector
documentation][].
[`@at-root` rule]: /documentation/at-rules/at-root
[selector functions]: /documentation/modules/selector
[parent selector documentation]: /documentation/style-rules/parent-selector
{% endmarkdown %}
[`@at-root` rule]: /documentation/at-rules/at-root
[selector functions]: /documentation/modules/selector
[parent selector documentation]: /documentation/style-rules/parent-selector

View File

@ -9,11 +9,9 @@ introduction: >
or adding a selector *before* the parent.
---
{% markdown %}
When a parent selector is used in an inner selector, it's replaced with the
corresponding outer selector. This happens instead of the normal nesting
behavior.
{% endmarkdown %}
When a parent selector is used in an inner selector, it's replaced with the
corresponding outer selector. This happens instead of the normal nesting
behavior.
{% codeExample 'parent-selector' %}
.alert {
@ -66,17 +64,15 @@ introduction: >
[this GitHub issue]: https://github.com/sass/sass/issues/1425
{% endheadsUp %}
{% markdown %}
## Adding Suffixes
## Adding Suffixes
You can also use the parent selector to add extra suffixes to the outer
selector. This is particularly useful when using a methodology like [BEM][]
that uses highly structured class names. As long as the outer selector ends
with an alphanumeric name (like class, ID, and element selectors), you can use
the parent selector to append additional text.
You can also use the parent selector to add extra suffixes to the outer
selector. This is particularly useful when using a methodology like [BEM][] that
uses highly structured class names. As long as the outer selector ends with an
alphanumeric name (like class, ID, and element selectors), you can use the
parent selector to append additional text.
[BEM]: http://getbem.com/
{% endmarkdown %}
[BEM]: http://getbem.com/
{% codeExample 'parent-selector-suffixes' %}
.accordion {
@ -119,17 +115,15 @@ introduction: >
display: block
{% endcodeExample %}
{% markdown %}
## In SassScript
## In SassScript
The parent selector can also be used within SassScript. It's a special
expression that returns the current parent selector in the same format used by
[selector functions][]: a comma-separated list (the selector list) that
contains space-separated lists (the complex selectors) that contain unquoted
strings (the compound selectors).
The parent selector can also be used within SassScript. It's a special
expression that returns the current parent selector in the same format used by
[selector functions][]: a comma-separated list (the selector list) that contains
space-separated lists (the complex selectors) that contain unquoted strings (the
compound selectors).
[selector functions]: /documentation/modules/selector#selector-values
{% endmarkdown %}
[selector functions]: /documentation/modules/selector#selector-values
{% codeExample 'parent-selector-sassscript' %}
.main aside:hover,
@ -146,27 +140,23 @@ introduction: >
// (unquote(".sidebar") unquote("p")))
{% endcodeExample %}
{% markdown %}
If the `&` expression is used outside any style rules, it returns `null`.
Since `null` is [falsey][], this means you can easily use it to determine
whether a mixin is being called in a style rule or not.
If the `&` expression is used outside any style rules, it returns `null`. Since
`null` is [falsey][], this means you can easily use it to determine whether a
mixin is being called in a style rule or not.
[falsey]: /documentation/at-rules/control/if#truthiness-and-falsiness
{% endmarkdown %}
[falsey]: /documentation/at-rules/control/if#truthiness-and-falsiness
{% render 'code_snippets/example-if-parent-selector' %}
{% markdown %}
### Advanced Nesting
### Advanced Nesting
You can use `&` as a normal SassScript expression, which means you can pass it
to functions or include it in interpolation—even in other selectors! Using it
in combination with [selector functions][] and the [`@at-root` rule][] allows
you to nest selectors in very powerful ways.
You can use `&` as a normal SassScript expression, which means you can pass it
to functions or include it in interpolation—even in other selectors! Using it in
combination with [selector functions][] and the [`@at-root` rule][] allows you
to nest selectors in very powerful ways.
[selector functions]: /documentation/modules/selector#selector-values
[`@at-root` rule]: /documentation/at-rules/at-root
{% endmarkdown %}
[selector functions]: /documentation/modules/selector#selector-values
[`@at-root` rule]: /documentation/at-rules/at-root
{% render 'code_snippets/example-advanced-nesting' %}

View File

@ -10,14 +10,12 @@ introduction: >
{% render 'code_snippets/example-placeholder' %}
{% markdown %}
What's the use of a selector that isn't emitted? It can still be [extended][]!
Unlike class selectors, placeholders don't clutter up the CSS if they aren't
extended and they don't mandate that users of a library use specific class
names for their HTML.
What's the use of a selector that isn't emitted? It can still be [extended][]!
Unlike class selectors, placeholders don't clutter up the CSS if they aren't
extended and they don't mandate that users of a library use specific class names
for their HTML.
[extended]: /documentation/at-rules/extend
{% endmarkdown %}
[extended]: /documentation/at-rules/extend
{% codeExample 'extended-selector' %}
%toolbelt {
@ -58,9 +56,7 @@ introduction: >
color: #cddc39
{% endcodeExample %}
{% markdown %}
Placeholder selectors are useful when writing a Sass library where each style
rule may or may not be used. As a rule of thumb, if you're writing a
stylesheet just for your own app, it's often better to just extend a class
selector if one is available.
{% endmarkdown %}
Placeholder selectors are useful when writing a Sass library where each style
rule may or may not be used. As a rule of thumb, if you're writing a stylesheet
just for your own app, it's often better to just extend a class selector if one
is available.

View File

@ -1,141 +0,0 @@
---
title: Comments
introduction: >
The way Sass comments work differs substantially between SCSS and the indented
syntax. Both syntaxes support two types of comments: comments defined using
`/* */` that are (usually) compiled to CSS, and comments defined using `//`
that are not.
---
{% markdown %}
## In SCSS
Comments in SCSS work similarly to comments in other languages like
JavaScript. **Single-line comments** start with `//`, and go until the end of
the line. Nothing in a single-line comment is emitted as CSS; as far as Sass
is concerned, they may as well not exist. They're also called **silent
comments**, because they don't produce any CSS.
**Multi-line comments** start with `/*` and end at the next `*/`. If a
multi-line comment is written somewhere that a [statement][] is allowed, it's
compiled to a CSS comment. They're also called **loud comment**, by contrast
with silent comments. A multi-line comment that's compiled to CSS may contain
[interpolation][], which will be evaluated before the comment is compiled.
By default, multi-line comments will be stripped from the compiled CSS in
[compressed mode][]. If a comment begins with `/*!`, though, it will always be
included in the CSS output.
[statement]: /documentation/syntax/structure#statements
[interpolation]: /documentation/interpolation
[compressed mode]: /documentation/cli/dart-sass/#style
{% endmarkdown %}
{% codeExample 'scss-comment', true, 'scss' %}
// This comment won't be included in the CSS.
/* But this comment will, except in compressed mode. */
/* It can also contain interpolation:
* 1 + 1 = #{1 + 1} */
/*! This comment will be included even in compressed mode. */
p /* Multi-line comments can be written anywhere
* whitespace is allowed. */ .sans {
font: Helvetica, // So can single-line comments.
sans-serif;
}
{% endcodeExample %}
{% markdown %}
## In Sass
Comments in the indented syntax work a little differently: they're
indentation-based, just like the rest of the syntax. Like SCSS, silent
comments written with `//` are never emitted as CSS, but unlike SCSS
everything indented beneath the opening `//` is also commented out.
Indented syntax comments that start with `/*` work with indentation the same
way, except that they are compiled to CSS. Because the extent of the comment
is based on indentation, the closing `*/` is optional. Also like SCSS, `/*`
comments can contain [interpolation][] and can start with `/*!` to avoid being
stripped in compressed mode.
Comments can also be used within [expressions][] in the indented syntax. In
this case, they have exactly the same syntax as they do in SCSS.
[interpolation]: /documentation/interpolation
[expressions]: /documentation/syntax/structure#expressions
{% endmarkdown %}
{% codeExample 'sass-comment', true, 'sass' %}
// This comment won't be included in the CSS.
This is also commented out.
/* But this comment will, except in compressed mode.
/* It can also contain interpolation:
1 + 1 = #{1 + 1}
/*! This comment will be included even in compressed mode.
p .sans
font: Helvetica, /* Inline comments must be closed. */ sans-serif
{% endcodeExample %}
{% markdown %}
## Documentation Comments
When writing style libraries using Sass, you can use comments to document the
[mixins][], [functions][], [variables][], and [placeholder selectors][] that
your library provides, as well as the library itself. These comments are read
by the [SassDoc][] tool, which uses them to generate beautiful documentation.
Check out [the Susy grid engine][susy]'s documentation to see it in action!
[mixins]: /documentation/at-rules/mixin
[functions]: /documentation/at-rules/function
[variables]: /documentation/variables
[placeholder selectors]: /documentation/style-rules/placeholder-selectors
[SassDoc]: http://sassdoc.com
[susy]: http://oddbird.net/susy/docs/index.html
Documentation comments are silent comments, written with three slashes (`///`)
directly above the thing you're documenting. SassDoc parses text in the
comments as [Markdown][], and supports many useful [annotations][] to describe
it in detail.
[Markdown]: https://www.markdownguide.org/getting-started
[annotations]: http://sassdoc.com/annotations/
{% endmarkdown %}
{% codeExample 'documentation-comment' %}
/// Computes an exponent.
///
/// @param {number} $base
/// The number to multiply by itself.
/// @param {integer (unitless)} $exponent
/// The number of `$base`s to multiply together.
/// @return {number} `$base` to the power of `$exponent`.
@function pow($base, $exponent) {
$result: 1;
@for $_ from 1 through $exponent {
$result: $result * $base;
}
@return $result;
}
===
/// Computes an exponent.
///
/// @param {number} $base
/// The number to multiply by itself.
/// @param {integer (unitless)} $exponent
/// The number of `$base`s to multiply together.
/// @return {number} `$base` to the power of `$exponent`.
@function pow($base, $exponent)
$result: 1
@for $_ from 1 through $exponent
$result: $result * $base
@return $result
{% endcodeExample %}

View File

@ -0,0 +1,135 @@
---
title: Comments
introduction: >
The way Sass comments work differs substantially between SCSS and the indented
syntax. Both syntaxes support two types of comments: comments defined using
`/* */` that are (usually) compiled to CSS, and comments defined using `//`
that are not.
---
## In SCSS
Comments in SCSS work similarly to comments in other languages like JavaScript.
**Single-line comments** start with `//`, and go until the end of the line.
Nothing in a single-line comment is emitted as CSS; as far as Sass is concerned,
they may as well not exist. They're also called **silent comments**, because
they don't produce any CSS.
**Multi-line comments** start with `/*` and end at the next `*/`. If a
multi-line comment is written somewhere that a [statement][] is allowed, it's
compiled to a CSS comment. They're also called **loud comment**, by contrast
with silent comments. A multi-line comment that's compiled to CSS may contain
[interpolation][], which will be evaluated before the comment is compiled.
By default, multi-line comments will be stripped from the compiled CSS in
[compressed mode][]. If a comment begins with `/*!`, though, it will always be
included in the CSS output.
[statement]: /documentation/syntax/structure#statements
[interpolation]: /documentation/interpolation
[compressed mode]: /documentation/cli/dart-sass/#style
{% codeExample 'scss-comment', true, 'scss' %}
// This comment won't be included in the CSS.
/* But this comment will, except in compressed mode. */
/* It can also contain interpolation:
* 1 + 1 = #{1 + 1} */
/*! This comment will be included even in compressed mode. */
p /* Multi-line comments can be written anywhere
* whitespace is allowed. */ .sans {
font: Helvetica, // So can single-line comments.
sans-serif;
}
{% endcodeExample %}
## In Sass
Comments in the indented syntax work a little differently: they're
indentation-based, just like the rest of the syntax. Like SCSS, silent comments
written with `//` are never emitted as CSS, but unlike SCSS everything indented
beneath the opening `//` is also commented out.
Indented syntax comments that start with `/*` work with indentation the same
way, except that they are compiled to CSS. Because the extent of the comment is
based on indentation, the closing `*/` is optional. Also like SCSS, `/*`
comments can contain [interpolation][] and can start with `/*!` to avoid being
stripped in compressed mode.
Comments can also be used within [expressions][] in the indented syntax. In this
case, they have exactly the same syntax as they do in SCSS.
[interpolation]: /documentation/interpolation
[expressions]: /documentation/syntax/structure#expressions
{% codeExample 'sass-comment', true, 'sass' %}
// This comment won't be included in the CSS.
This is also commented out.
/* But this comment will, except in compressed mode.
/* It can also contain interpolation:
1 + 1 = #{1 + 1}
/*! This comment will be included even in compressed mode.
p .sans
font: Helvetica, /* Inline comments must be closed. */ sans-serif
{% endcodeExample %}
## Documentation Comments
When writing style libraries using Sass, you can use comments to document the
[mixins][], [functions][], [variables][], and [placeholder selectors][] that
your library provides, as well as the library itself. These comments are read by
the [SassDoc][] tool, which uses them to generate beautiful documentation. Check
out [the Susy grid engine][susy]'s documentation to see it in action!
[mixins]: /documentation/at-rules/mixin
[functions]: /documentation/at-rules/function
[variables]: /documentation/variables
[placeholder selectors]: /documentation/style-rules/placeholder-selectors
[SassDoc]: http://sassdoc.com
[susy]: http://oddbird.net/susy/docs/index.html
Documentation comments are silent comments, written with three slashes (`///`)
directly above the thing you're documenting. SassDoc parses text in the comments
as [Markdown][], and supports many useful [annotations][] to describe it in
detail.
[Markdown]: https://www.markdownguide.org/getting-started
[annotations]: http://sassdoc.com/annotations/
{% codeExample 'documentation-comment' %}
/// Computes an exponent.
///
/// @param {number} $base
/// The number to multiply by itself.
/// @param {integer (unitless)} $exponent
/// The number of `$base`s to multiply together.
/// @return {number} `$base` to the power of `$exponent`.
@function pow($base, $exponent) {
$result: 1;
@for $_ from 1 through $exponent {
$result: $result * $base;
}
@return $result;
}
===
/// Computes an exponent.
///
/// @param {number} $base
/// The number to multiply by itself.
/// @param {integer (unitless)} $exponent
/// The number of `$base`s to multiply together.
/// @return {number} `$base` to the power of `$exponent`.
@function pow($base, $exponent)
$result: 1
@for $_ from 1 through $exponent
$result: $result * $base
@return $result
{% endcodeExample %}

View File

@ -1,148 +0,0 @@
---
title: Special Functions
table_of_contents: true
introduction: >
CSS defines many functions, and most of them work just fine with Sasss normal
function syntax. Theyre parsed as function calls, resolved to [plain CSS
functions](/documentation/at-rules/function/#plain-css-functions), and compiled
as-is to CSS. There are a few exceptions, though, which have special syntax
that cant just be parsed as a [SassScript
expression](/documentation/syntax/structure#expressions). All special function
calls return [unquoted strings](/documentation/values/strings#unquoted).
---
{% markdown %}
## `url()`
The [`url()` function][] is commonly used in CSS, but its syntax is different
than other functions: it can take either a quoted *or* unquoted URL. Because
an unquoted URL isn't a valid SassScript expression, Sass needs special logic
to parse it.
[`url()` function]: https://developer.mozilla.org/en-US/docs/Web/CSS/url
If the `url()`'s argument is a valid unquoted URL, Sass parses it as-is,
although [interpolation][] may also be used to inject SassScript values. If
it's not a valid unquoted URL—for example, if it contains [variables][] or
[function calls][]—it's parsed as a normal [plain CSS function call][].
[interpolation]: /documentation/interpolation
[variables]: /documentation/variables
[function calls]: /documentation/at-rules/function
[plain CSS function call]: /documentation/at-rules/function/#plain-css-functions
{% endmarkdown %}
{% codeExample 'url' %}
$roboto-font-path: "../fonts/roboto";
@font-face {
// This is parsed as a normal function call that takes a quoted string.
src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2");
font-family: "Roboto";
font-weight: 100;
}
@font-face {
// This is parsed as a normal function call that takes an arithmetic
// expression.
src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2");
font-family: "Roboto";
font-weight: 300;
}
@font-face {
// This is parsed as an interpolated special function.
src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2");
font-family: "Roboto";
font-weight: 400;
}
===
$roboto-font-path: "../fonts/roboto"
@font-face
// This is parsed as a normal function call that takes a quoted string.
src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2")
font-family: "Roboto"
font-weight: 100
@font-face
// This is parsed as a normal function call that takes an arithmetic
// expression.
src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2")
font-family: "Roboto"
font-weight: 300
@font-face
// This is parsed as an interpolated special function.
src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2")
font-family: "Roboto"
font-weight: 400
{% endcodeExample %}
{% markdown %}
## `element()`, `progid:...()`, and `expression()`
{% compatibility 'dart: "<1.40.0"', 'libsass: false', 'ruby: false', 'feature: "calc()"' %}
LibSass, Ruby Sass, and versions of Dart Sass prior to 1.40.0 parse `calc()`
as special syntactic function like `element()`.
Dart Sass versions 1.40.0 and later parse `calc()` as a [calculation].
[calculation]: /documentation/values/calculations
{% endcompatibility %}
{% compatibility 'dart: ">=1.31.0 <1.40.0"', 'libsass: false', 'ruby: false', 'feature: "clamp()"' %}
LibSass, Ruby Sass, and versions of Dart Sass prior to 1.31.0 parse
`clamp()` as a [plain CSS function] rather than supporting special syntax
within it.
[plain CSS function]: /documentation/at-rules/function/#plain-css-functions
Dart Sass versions between 1.31.0 and 1.40.0 parse `clamp()` as special
syntactic function like `element()`.
Dart Sass versions 1.40.0 and later parse `clamp()` as a [calculation].
[calculation]: /documentation/values/calculations
{% endcompatibility %}
The [`element()`] function is defined in the CSS spec, and because its IDs
could be parsed as colors, they need special parsing.
[`element()`]: https://developer.mozilla.org/en-US/docs/Web/CSS/element
[`expression()`][] and functions beginning with [`progid:`][] are legacy
Internet Explorer features that use non-standard syntax. Although they're no
longer supported by recent browsers, Sass continues to parse them for
backwards compatibility.
[`expression()`]: https://blogs.msdn.microsoft.com/ie/2008/10/16/ending-expressions/
[`progid:`]: https://blogs.msdn.microsoft.com/ie/2009/02/19/the-css-corner-using-filters-in-ie8/
Sass allows *any text* in these function calls, including nested parentheses.
Nothing is interpreted as a SassScript expression, with the exception that
[interpolation][] can be used to inject dynamic values.
[interpolation]: /documentation/interpolation
{% endmarkdown %}
{% codeExample 'element' %}
$logo-element: logo-bg;
.logo {
background: element(##{$logo-element});
}
===
$logo-element: logo-bg
.logo
background: element(##{$logo-element})
{% endcodeExample %}

View File

@ -0,0 +1,145 @@
---
title: Special Functions
table_of_contents: true
introduction: >
CSS defines many functions, and most of them work just fine with Sasss normal
function syntax. Theyre parsed as function calls, resolved to [plain CSS
functions](/documentation/at-rules/function/#plain-css-functions), and compiled
as-is to CSS. There are a few exceptions, though, which have special syntax
that cant just be parsed as a [SassScript
expression](/documentation/syntax/structure#expressions). All special function
calls return [unquoted strings](/documentation/values/strings#unquoted).
---
## `url()`
The [`url()` function][] is commonly used in CSS, but its syntax is different
than other functions: it can take either a quoted *or* unquoted URL. Because an
unquoted URL isn't a valid SassScript expression, Sass needs special logic to
parse it.
[`url()` function]: https://developer.mozilla.org/en-US/docs/Web/CSS/url
If the `url()`'s argument is a valid unquoted URL, Sass parses it as-is,
although [interpolation][] may also be used to inject SassScript values. If it's
not a valid unquoted URL—for example, if it contains [variables][] or [function
calls][]—it's parsed as a normal [plain CSS function call][].
[interpolation]: /documentation/interpolation
[variables]: /documentation/variables
[function calls]: /documentation/at-rules/function
[plain CSS function call]: /documentation/at-rules/function/#plain-css-functions
{% codeExample 'url' %}
$roboto-font-path: "../fonts/roboto";
@font-face {
// This is parsed as a normal function call that takes a quoted string.
src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2");
font-family: "Roboto";
font-weight: 100;
}
@font-face {
// This is parsed as a normal function call that takes an arithmetic
// expression.
src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2");
font-family: "Roboto";
font-weight: 300;
}
@font-face {
// This is parsed as an interpolated special function.
src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2");
font-family: "Roboto";
font-weight: 400;
}
===
$roboto-font-path: "../fonts/roboto"
@font-face
// This is parsed as a normal function call that takes a quoted string.
src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2")
font-family: "Roboto"
font-weight: 100
@font-face
// This is parsed as a normal function call that takes an arithmetic
// expression.
src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2")
font-family: "Roboto"
font-weight: 300
@font-face
// This is parsed as an interpolated special function.
src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2")
font-family: "Roboto"
font-weight: 400
{% endcodeExample %}
## `element()`, `progid:...()`, and `expression()`
{% compatibility 'dart: "<1.40.0"', 'libsass: false', 'ruby: false', 'feature: "calc()"' %}
LibSass, Ruby Sass, and versions of Dart Sass prior to 1.40.0 parse `calc()`
as special syntactic function like `element()`.
Dart Sass versions 1.40.0 and later parse `calc()` as a [calculation].
[calculation]: /documentation/values/calculations
{% endcompatibility %}
{% compatibility 'dart: ">=1.31.0 <1.40.0"', 'libsass: false', 'ruby: false', 'feature: "clamp()"' %}
LibSass, Ruby Sass, and versions of Dart Sass prior to 1.31.0 parse `clamp()`
as a [plain CSS function] rather than supporting special syntax within it.
[plain CSS function]: /documentation/at-rules/function/#plain-css-functions
Dart Sass versions between 1.31.0 and 1.40.0 parse `clamp()` as special
syntactic function like `element()`.
Dart Sass versions 1.40.0 and later parse `clamp()` as a [calculation].
[calculation]: /documentation/values/calculations
{% endcompatibility %}
The [`element()`] function is defined in the CSS spec, and because its IDs could
be parsed as colors, they need special parsing.
[`element()`]: https://developer.mozilla.org/en-US/docs/Web/CSS/element
[`expression()`][] and functions beginning with [`progid:`][] are legacy
Internet Explorer features that use non-standard syntax. Although they're no
longer supported by recent browsers, Sass continues to parse them for backwards
compatibility.
[`expression()`]:
https://blogs.msdn.microsoft.com/ie/2008/10/16/ending-expressions/
[`progid:`]:
https://blogs.msdn.microsoft.com/ie/2009/02/19/the-css-corner-using-filters-in-ie8/
Sass allows *any text* in these function calls, including nested parentheses.
Nothing is interpreted as a SassScript expression, with the exception that
[interpolation][] can be used to inject dynamic values.
[interpolation]: /documentation/interpolation
{% codeExample 'element' %}
$logo-element: logo-bg;
.logo {
background: element(##{$logo-element});
}
===
$logo-element: logo-bg
.logo
background: element(##{$logo-element})
{% endcodeExample %}

View File

@ -25,14 +25,12 @@ introduction: >
@debug math.comparable(100px, 3in) // true
{% endcodeExample %}
{% markdown %}
You can work with booleans using [boolean operators][]. The `and` operator
returns `true` if *both* sides are `true`, and the `or` operator returns
`true` if *either* side is `true`. The `not` operator returns the opposite of
a single boolean value.
You can work with booleans using [boolean operators][]. The `and` operator
returns `true` if *both* sides are `true`, and the `or` operator returns `true`
if *either* side is `true`. The `not` operator returns the opposite of a single
boolean value.
[boolean operators]: /documentation/operators/boolean
{% endmarkdown %}
[boolean operators]: /documentation/operators/boolean
{% codeExample 'boolean-operators', false %}
@debug true and true; // true
@ -54,23 +52,19 @@ introduction: >
@debug not false // true
{% endcodeExample %}
{% markdown %}
## Using Booleans
## Using Booleans
You can use booleans to choose whether or not to do various things in Sass.
The [`@if` rule][] evaluates a block of styles if its argument is `true`:
You can use booleans to choose whether or not to do various things in Sass. The
[`@if` rule][] evaluates a block of styles if its argument is `true`:
[`@if` rule]: /documentation/at-rules/control/if
{% endmarkdown %}
[`@if` rule]: /documentation/at-rules/control/if
{% render 'code_snippets/example-if' %}
{% markdown %}
The [`if()` function][] returns one value if its argument is `true` and
another if its argument is `false`:
The [`if()` function][] returns one value if its argument is `true` and another
if its argument is `false`:
[`if()` function]: /documentation/modules#if
{% endmarkdown %}
[`if()` function]: /documentation/modules#if
{% codeExample 'if-function', false %}
@debug if(true, 10px, 30px); // 10px

View File

@ -1,253 +0,0 @@
---
title: Calculations
introduction: >
Calculations are how Sass represents the `calc()` function, as well as similar
functions like `clamp()`, `min()`, and `max()`. Sass will simplify these as
much as possible, even if they're combined with one another.
---
{% compatibility 'dart: "1.40.0"', 'libsass: false', 'ruby: false' %}
LibSass, Ruby Sass, and versions of Dart Sass prior to 1.40.0 parse `calc()`
as a [special function] like `element()`.
[special function]: /documentation/syntax/special-functions#element-progid-and-expression
LibSass, Ruby Sass, and versions of Dart Sass prior to 1.31.0 parse `clamp()`
as a [plain CSS function] rather than supporting special syntax within it.
Versions of Dart Sass between 1.31.0 and 1.40.0 parse `clamp()` as a [special
function] like `element()`.
[plain CSS function]: /documentation/at-rules/function/#plain-css-functions
{% endcompatibility %}
{% codeExample 'calculations', false %}
@debug calc(400px + 10%); // calc(400px + 10%)
@debug calc(400px / 2); // 200px
@debug min(100px, calc(1rem + 10%)); // min(100px, 1rem + 10%)
===
@debug calc(400px + 10%) // calc(400px + 10%)
@debug calc(400px / 2) // 200px
@debug min(100px, calc(1rem + 10%) ; // min(100px, 1rem + 10%)
{% endcodeExample %}
{% markdown %}
Calculations use a special syntax that's different from normal SassScript.
It's the same syntax as the CSS `calc()`, but with the additional ability to
use [Sass variables] and call [Sass functions]. This means that `/` is always
a division operator within a calculation!
[Sass variables]: /documentation/variables
[Sass functions]: /documentation/modules
{% funFact %}
The arguments to a Sass function call use the normal Sass syntax, rather
than the special calculation syntax!
{% endfunFact %}
You can also use [interpolation] in a calculation. However, if you do, nothing
in the parentheses that surround that interpolation will be simplified or
type-checked, so it's easy to end up with extra verbose or even invalid CSS.
Rather than writing `calc(10px + #{$var})`, just write `calc(10px + $var)`!
[interpolation]: /documentation/interpolation
## Simplification
Sass will simplify adjacent operations in calculations if they use units that
can be combined at compile-time, such as `1in + 10px` or `5s * 2`. If
possible, it'll even simplify the whole calculation to a single number—for
example, `clamp(0px, 30px, 20px)` will return `20px`.
{% headsUp %}
This means that a calculation expression won't necessarily always return a
calculation! If you're writing a Sass library, you can always use the
[`meta.type-of()`] function to determine what type you're dealing with.
[`meta.type-of()`]: /documentation/modules/meta#type-of
{% endheadsUp %}
Calculations will also be simplified within other calculations. In particular,
if a `calc()` end up inside any other calculation, the function call will be
removed and it'll be replaced by a plain old operation.
{% endmarkdown %}
{% codeExample 'simplification' %}
$width: calc(400px + 10%);
.sidebar {
width: $width;
padding-left: calc($width / 4);
}
===
$width: calc(400px + 10%)
.sidebar
width: $width
padding-left: calc($width / 4)
{% endcodeExample %}
{% markdown %}
## Operations
You can't use calculations with normal SassScript operations like `+` and `*`.
If you want to write some math functions that allow calculations just write
them within their own `calc()` expressions—if they're passed a bunch of
numbers with compatible units, they'll return plain numbers as well, and if
they're passed calculations they'll return calculations.
This restriction is in place to make sure that if calculations *aren't*
wanted, they throw an error as soon as possible. Calculations can't be used
everywhere plain numbers can: they can't be injected into CSS identifiers
(such as `.item-#{$n}`), for example, and they can't be passed to Sass's
built-in [math functions]. Reserving SassScript operations for plain numbers
makes it clear exactly where calculations are allowed and where they aren't.
[math functions]: /documentation/modules/math
{% endmarkdown %}
{% codeExample 'calc-operations', false %}
$width: calc(100% + 10px);
@debug $width * 2; // Error!
@debug calc($width * 2); // calc((100% + 10px) * 2);
===
$width: calc(100% + 10px);
@debug $width * 2; // Error!
@debug calc($width * 2); // calc((100% + 10px) * 2);
{% endcodeExample %}
{% markdown %}
## Constants
{% compatibility 'dart: "1.60.0"','libsass: false', 'ruby: false' %}{% endcompatibility %}
Calculations can also contain constants, which are written as CSS identifiers.
For forwards-compatibility with future CSS specs, *all* identifiers are
allowed, and by default they're just treated as unquoted strings that are
passed-through as-is.
{% endmarkdown %}
{% codeExample 'calc-constants', false %}
@debug calc(h + 30deg); // calc(h + 30deg);
===
@debug calc(h + 30deg) // calc(h + 30deg);
{% endcodeExample %}
{% markdown %}
Sass automatically resolves a few special constant names that are specified in
CSS to unitless numbers:
* `pi` is a shorthand for the [mathematical constant *π*].
[mathematical constant *π*]: https://en.wikipedia.org/wiki/Pi
* `e` is a shorthand for the [mathematical constant *e*].
[mathematical constant *e*]: https://en.wikipedia.org/wiki/E_(mathematical_constant)
* `infinity`, `-infinity`, and `NaN` represent the corresponding
floating-point values.
{% endmarkdown %}
{% codeExample 'unitless-numbers', false %}
@use 'sass:math';
@debug calc(pi); // 3.1415926536
@debug calc(e); // 2.7182818285
@debug calc(infinity) > math.$max-number; // true
@debug calc(-infinity) < math.$min-number; // true
===
@use 'sass:math'
@debug calc(pi) // 3.1415926536
@debug calc(e) // 2.7182818285
@debug calc(infinity) > math.$max-number // true
@debug calc(-infinity) < math.$min-number // true
{% endcodeExample %}
{% markdown %}
## `min()` and `max()`
{% compatibility 'dart: ">=1.11.0 <1.42.0"', 'libsass: false', 'ruby: false', 'feature: "Special function syntax"' %}
LibSass, Ruby Sass, and versions of Dart Sass prior to 1.11.0 *always* parse
`min()` and `max()` as Sass functions. To create a plain CSS `min()` or
`max()` call for those implementations, you can write something like
`unquote("min(#{$padding}, env(safe-area-inset-left))")` instead.
Versions of Dart Sass between 1.11.0 and 1.40.0, and between 1.40.1 and
1.42.0 parse `min()` and `max()` functions as [special functions] if they're
valid plain CSS, but parse them as Sass functions if they contain Sass
features other than interpolation, like variables or function calls.
Dart Sass 1.41.0 parses `min()` and `max()` functions as calculations, but
doesn't allow unitless numbers to be combined with numbers with units. This
was backwards-incompatible with the global `min()` and `max()` functions, so
that behavior was reverted.
[special functions]: /documentation/syntax/special-functions
{% endcompatibility %}
CSS added support for [`min()` and `max()` functions] in Values and Units
Level 4, from where they were quickly adopted by Safari [to support the
iPhoneX]. But Sass supported its own [`min()`] and [`max()`] functions long
before this, and it needed to be backwards-compatible with all those existing
stylesheets. This led to the need for extra-special syntactic cleverness.
[`min()` and `max()` functions]: https://drafts.csswg.org/css-values-4/#calc-notation
[to support the iPhoneX]: https://webkit.org/blog/7929/designing-websites-for-iphone-x/
[`min()`]: /documentation/modules/math#min
[`max()`]: /documentation/modules/math#max
If a `min()` or `max()` function call is a valid calculation expression, it
will be parsed as a calculation. But as soon as any part of the call contains
a SassScript feature that isn't supported in a calculation, like the [modulo
operator], it's parsed as a call to Sass's core `min()` or `max()` function
instead.
Since calculations are simplified to numbers when possible anyway, the only
substantive difference is that the Sass functions only support units that can
be combined at build time, so `min(12px % 10, 10%)` will throw an error.
[modulo operator]: /documentation/operators/numeric
{% endmarkdown %}
{% headsUp %}
Other calculations don't allow unitless numbers to be added to, subtracted
from, or compared to numbers with units. `min()` and `max()` are different,
though: for backwards-compatibility with the global Sass `min()` and `max()`
functions which allow unit/unitless mixing for historical reasons, these units
can be mixed as long as they're contained directly within a `min()` or `max()`
calculation.
{% endheadsUp %}
{% codeExample 'min-max' %}
$padding: 12px;
.post {
// Since these max() calls are valid calculation expressions, they're
// parsed as calculations.
padding-left: max($padding, env(safe-area-inset-left));
padding-right: max($padding, env(safe-area-inset-right));
}
.sidebar {
// Since these use the SassScript-only modulo operator, they're parsed as
// SassScript function calls.
padding-left: max($padding % 10, 20px);
padding-right: max($padding % 10, 20px);
}
===
$padding: 12px
.post
// Since these max() calls are valid calculation expressions, they're
// parsed as calculations.
padding-left: max($padding, env(safe-area-inset-left))
padding-right: max($padding, env(safe-area-inset-right))
.sidebar
// Since these use the SassScript-only modulo operator, they're parsed as
// SassScript function calls.
padding-left: max($padding % 10, 20px)
padding-right: max($padding % 10, 20px)
{% endcodeExample %}

View File

@ -0,0 +1,243 @@
---
title: Calculations
introduction: >
Calculations are how Sass represents the `calc()` function, as well as similar
functions like `clamp()`, `min()`, and `max()`. Sass will simplify these as
much as possible, even if they're combined with one another.
---
{% compatibility 'dart: "1.40.0"', 'libsass: false', 'ruby: false' %}
LibSass, Ruby Sass, and versions of Dart Sass prior to 1.40.0 parse `calc()`
as a [special function] like `element()`.
[special function]: /documentation/syntax/special-functions#element-progid-and-expression
LibSass, Ruby Sass, and versions of Dart Sass prior to 1.31.0 parse `clamp()`
as a [plain CSS function] rather than supporting special syntax within it.
Versions of Dart Sass between 1.31.0 and 1.40.0 parse `clamp()` as a [special
function] like `element()`.
[plain CSS function]: /documentation/at-rules/function/#plain-css-functions
{% endcompatibility %}
{% codeExample 'calculations', false %}
@debug calc(400px + 10%); // calc(400px + 10%)
@debug calc(400px / 2); // 200px
@debug min(100px, calc(1rem + 10%)); // min(100px, 1rem + 10%)
===
@debug calc(400px + 10%) // calc(400px + 10%)
@debug calc(400px / 2) // 200px
@debug min(100px, calc(1rem + 10%) ; // min(100px, 1rem + 10%)
{% endcodeExample %}
Calculations use a special syntax that's different from normal SassScript. It's
the same syntax as the CSS `calc()`, but with the additional ability to use
[Sass variables] and call [Sass functions]. This means that `/` is always a
division operator within a calculation!
[Sass variables]: /documentation/variables
[Sass functions]: /documentation/modules
{% funFact %}
The arguments to a Sass function call use the normal Sass syntax, rather than
the special calculation syntax!
{% endfunFact %}
You can also use [interpolation] in a calculation. However, if you do, nothing
in the parentheses that surround that interpolation will be simplified or
type-checked, so it's easy to end up with extra verbose or even invalid CSS.
Rather than writing `calc(10px + #{$var})`, just write `calc(10px + $var)`!
[interpolation]: /documentation/interpolation
## Simplification
Sass will simplify adjacent operations in calculations if they use units that
can be combined at compile-time, such as `1in + 10px` or `5s * 2`. If possible,
it'll even simplify the whole calculation to a single number—for example,
`clamp(0px, 30px, 20px)` will return `20px`.
{% headsUp %}
This means that a calculation expression won't necessarily always return a
calculation! If you're writing a Sass library, you can always use the
[`meta.type-of()`] function to determine what type you're dealing with.
[`meta.type-of()`]: /documentation/modules/meta#type-of
{% endheadsUp %}
Calculations will also be simplified within other calculations. In particular,
if a `calc()` end up inside any other calculation, the function call will be
removed and it'll be replaced by a plain old operation.
{% codeExample 'simplification' %}
$width: calc(400px + 10%);
.sidebar {
width: $width;
padding-left: calc($width / 4);
}
===
$width: calc(400px + 10%)
.sidebar
width: $width
padding-left: calc($width / 4)
{% endcodeExample %}
## Operations
You can't use calculations with normal SassScript operations like `+` and `*`.
If you want to write some math functions that allow calculations just write them
within their own `calc()` expressions—if they're passed a bunch of numbers with
compatible units, they'll return plain numbers as well, and if they're passed
calculations they'll return calculations.
This restriction is in place to make sure that if calculations *aren't* wanted,
they throw an error as soon as possible. Calculations can't be used everywhere
plain numbers can: they can't be injected into CSS identifiers (such as
`.item-#{$n}`), for example, and they can't be passed to Sass's built-in [math
functions]. Reserving SassScript operations for plain numbers makes it clear
exactly where calculations are allowed and where they aren't.
[math functions]: /documentation/modules/math
{% codeExample 'calc-operations', false %}
$width: calc(100% + 10px);
@debug $width * 2; // Error!
@debug calc($width * 2); // calc((100% + 10px) * 2);
===
$width: calc(100% + 10px);
@debug $width * 2; // Error!
@debug calc($width * 2); // calc((100% + 10px) * 2);
{% endcodeExample %}
## Constants
{% compatibility 'dart: "1.60.0"','libsass: false', 'ruby: false' %}{% endcompatibility %}
Calculations can also contain constants, which are written as CSS identifiers.
For forwards-compatibility with future CSS specs, *all* identifiers are allowed,
and by default they're just treated as unquoted strings that are passed-through
as-is.
{% codeExample 'calc-constants', false %}
@debug calc(h + 30deg); // calc(h + 30deg);
===
@debug calc(h + 30deg) // calc(h + 30deg);
{% endcodeExample %}
Sass automatically resolves a few special constant names that are specified in
CSS to unitless numbers:
* `pi` is a shorthand for the [mathematical constant *π*].
[mathematical constant *π*]: https://en.wikipedia.org/wiki/Pi
* `e` is a shorthand for the [mathematical constant *e*].
[mathematical constant *e*]: https://en.wikipedia.org/wiki/E_(mathematical_constant)
* `infinity`, `-infinity`, and `NaN` represent the corresponding floating-point
values.
{% codeExample 'unitless-numbers', false %}
@use 'sass:math';
@debug calc(pi); // 3.1415926536
@debug calc(e); // 2.7182818285
@debug calc(infinity) > math.$max-number; // true
@debug calc(-infinity) < math.$min-number; // true
===
@use 'sass:math'
@debug calc(pi) // 3.1415926536
@debug calc(e) // 2.7182818285
@debug calc(infinity) > math.$max-number // true
@debug calc(-infinity) < math.$min-number // true
{% endcodeExample %}
## `min()` and `max()`
{% compatibility 'dart: ">=1.11.0 <1.42.0"', 'libsass: false', 'ruby: false', 'feature: "Special function syntax"' %}
LibSass, Ruby Sass, and versions of Dart Sass prior to 1.11.0 *always* parse
`min()` and `max()` as Sass functions. To create a plain CSS `min()` or
`max()` call for those implementations, you can write something like
`unquote("min(#{$padding}, env(safe-area-inset-left))")` instead.
Versions of Dart Sass between 1.11.0 and 1.40.0, and between 1.40.1 and 1.42.0
parse `min()` and `max()` functions as [special functions] if they're valid
plain CSS, but parse them as Sass functions if they contain Sass features
other than interpolation, like variables or function calls.
Dart Sass 1.41.0 parses `min()` and `max()` functions as calculations, but
doesn't allow unitless numbers to be combined with numbers with units. This
was backwards-incompatible with the global `min()` and `max()` functions, so
that behavior was reverted.
[special functions]: /documentation/syntax/special-functions
{% endcompatibility %}
CSS added support for [`min()` and `max()` functions] in Values and Units Level
4, from where they were quickly adopted by Safari [to support the iPhoneX]. But
Sass supported its own [`min()`] and [`max()`] functions long before this, and
it needed to be backwards-compatible with all those existing stylesheets. This
led to the need for extra-special syntactic cleverness.
[`min()` and `max()` functions]: https://drafts.csswg.org/css-values-4/#calc-notation
[to support the iPhoneX]: https://webkit.org/blog/7929/designing-websites-for-iphone-x/
[`min()`]: /documentation/modules/math#min
[`max()`]: /documentation/modules/math#max
If a `min()` or `max()` function call is a valid calculation expression, it will
be parsed as a calculation. But as soon as any part of the call contains a
SassScript feature that isn't supported in a calculation, like the [modulo
operator], it's parsed as a call to Sass's core `min()` or `max()` function
instead.
Since calculations are simplified to numbers when possible anyway, the only
substantive difference is that the Sass functions only support units that can be
combined at build time, so `min(12px % 10, 10%)` will throw an error.
[modulo operator]: /documentation/operators/numeric
{% headsUp %}
Other calculations don't allow unitless numbers to be added to, subtracted
from, or compared to numbers with units. `min()` and `max()` are different,
though: for backwards-compatibility with the global Sass `min()` and `max()`
functions which allow unit/unitless mixing for historical reasons, these units
can be mixed as long as they're contained directly within a `min()` or `max()`
calculation.
{% endheadsUp %}
{% codeExample 'min-max' %}
$padding: 12px;
.post {
// Since these max() calls are valid calculation expressions, they're
// parsed as calculations.
padding-left: max($padding, env(safe-area-inset-left));
padding-right: max($padding, env(safe-area-inset-right));
}
.sidebar {
// Since these use the SassScript-only modulo operator, they're parsed as
// SassScript function calls.
padding-left: max($padding % 10, 20px);
padding-right: max($padding % 10, 20px);
}
===
$padding: 12px
.post
// Since these max() calls are valid calculation expressions, they're
// parsed as calculations.
padding-left: max($padding, env(safe-area-inset-left))
padding-right: max($padding, env(safe-area-inset-right))
.sidebar
// Since these use the SassScript-only modulo operator, they're parsed as
// SassScript function calls.
padding-left: max($padding % 10, 20px)
padding-right: max($padding % 10, 20px)
{% endcodeExample %}

View File

@ -1,81 +0,0 @@
---
title: Colors
---
{% compatibility 'dart: "1.14.0"', 'libsass: "3.6.0"', 'ruby: "3.6.0"', 'feature: "Level 4 Syntax"' %}
LibSass and older versions of Dart or Ruby Sass don't support [hex colors with
an alpha channel][].
[hex colors with an alpha channel]: https://drafts.csswg.org/css-color/#hex-notation
{% endcompatibility %}
{% markdown %}
Sass has built-in support for color values. Just like CSS colors, they
represent points in the [sRGB color space][], although many Sass [color
functions][] operate using [HSL coordinates][] (which are just another way of
expressing sRGB colors). Sass colors can be written as hex codes (`#f2ece4` or
`#b37399aa`), [CSS color names][] (`midnightblue`, `transparent`), or the
functions [`rgb()`][], [`rgba()`][], [`hsl()`][], and [`hsla()`][].
[sRGB color space]: https://en.wikipedia.org/wiki/SRGB
[color functions]: /documentation/modules/color
[HSL coordinates]: https://en.wikipedia.org/wiki/HSL_and_HSV
[CSS color names]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#Color_keywords
[`rgb()`]: /documentation/modules#rgb
[`rgba()`]: /documentation/modules#rgba
[`hsl()`]: /documentation/modules#hsl
[`hsla()`]: /documentation/modules#hsla
{% endmarkdown %}
{% codeExample 'colors', false %}
@debug #f2ece4; // #f2ece4
@debug #b37399aa; // rgba(179, 115, 153, 67%)
@debug midnightblue; // #191970
@debug rgb(204, 102, 153); // #c69
@debug rgba(107, 113, 127, 0.8); // rgba(107, 113, 127, 0.8)
@debug hsl(228, 7%, 86%); // #dadbdf
@debug hsla(20, 20%, 85%, 0.7); // rgb(225, 215, 210, 0.7)
===
@debug #f2ece4 // #f2ece4
@debug #b37399aa // rgba(179, 115, 153, 67%)
@debug midnightblue // #191970
@debug rgb(204, 102, 153) // #c69
@debug rgba(107, 113, 127, 0.8) // rgba(107, 113, 127, 0.8)
@debug hsl(228, 7%, 86%) // #dadbdf
@debug hsla(20, 20%, 85%, 0.7) // rgb(225, 215, 210, 0.7)
{% endcodeExample %}
{% funFact %}
No matter how a Sass color is originally written, it can be used with both
HSL-based and RGB-based functions!
{% endfunFact %}
{% markdown %}
CSS supports many different formats that can all represent the same color: its
name, its hex code, and [functional notation][]. Which format Sass chooses to
compile a color to depends on the color itself, how it was written in the
original stylesheet, and the current output mode. Because it can vary so much,
stylesheet authors shouldn't rely on any particular output format for colors
they write.
[functional notation]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value
Sass supports many useful [color functions][] that can be used to create new
colors based on existing ones by [mixing colors together][] or [scaling their
hue, saturation, or lightness][].
[mixing colors together]: /documentation/modules/color#mix
[scaling their hue, saturation, or lightness]: /documentation/modules/color#scale
{% endmarkdown %}
{% codeExample 'color-formats', false %}
$venus: #998099;
@debug scale-color($venus, $lightness: +15%); // #a893a8
@debug mix($venus, midnightblue); // #594d85
===
$venus: #998099
@debug scale-color($venus, $lightness: +15%) // #a893a8
@debug mix($venus, midnightblue) // #594d85
{% endcodeExample %}

View File

@ -0,0 +1,77 @@
---
title: Colors
---
{% compatibility 'dart: "1.14.0"', 'libsass: "3.6.0"', 'ruby: "3.6.0"', 'feature: "Level 4 Syntax"' %}
LibSass and older versions of Dart or Ruby Sass don't support [hex colors with
an alpha channel][].
[hex colors with an alpha channel]: https://drafts.csswg.org/css-color/#hex-notation
{% endcompatibility %}
Sass has built-in support for color values. Just like CSS colors, they represent
points in the [sRGB color space][], although many Sass [color functions][]
operate using [HSL coordinates][] (which are just another way of expressing sRGB
colors). Sass colors can be written as hex codes (`#f2ece4` or `#b37399aa`),
[CSS color names][] (`midnightblue`, `transparent`), or the functions
[`rgb()`][], [`rgba()`][], [`hsl()`][], and [`hsla()`][].
[sRGB color space]: https://en.wikipedia.org/wiki/SRGB
[color functions]: /documentation/modules/color
[HSL coordinates]: https://en.wikipedia.org/wiki/HSL_and_HSV
[CSS color names]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#Color_keywords
[`rgb()`]: /documentation/modules#rgb
[`rgba()`]: /documentation/modules#rgba
[`hsl()`]: /documentation/modules#hsl
[`hsla()`]: /documentation/modules#hsla
{% codeExample 'colors', false %}
@debug #f2ece4; // #f2ece4
@debug #b37399aa; // rgba(179, 115, 153, 67%)
@debug midnightblue; // #191970
@debug rgb(204, 102, 153); // #c69
@debug rgba(107, 113, 127, 0.8); // rgba(107, 113, 127, 0.8)
@debug hsl(228, 7%, 86%); // #dadbdf
@debug hsla(20, 20%, 85%, 0.7); // rgb(225, 215, 210, 0.7)
===
@debug #f2ece4 // #f2ece4
@debug #b37399aa // rgba(179, 115, 153, 67%)
@debug midnightblue // #191970
@debug rgb(204, 102, 153) // #c69
@debug rgba(107, 113, 127, 0.8) // rgba(107, 113, 127, 0.8)
@debug hsl(228, 7%, 86%) // #dadbdf
@debug hsla(20, 20%, 85%, 0.7) // rgb(225, 215, 210, 0.7)
{% endcodeExample %}
{% funFact %}
No matter how a Sass color is originally written, it can be used with both
HSL-based and RGB-based functions!
{% endfunFact %}
CSS supports many different formats that can all represent the same color: its
name, its hex code, and [functional notation][]. Which format Sass chooses to
compile a color to depends on the color itself, how it was written in the
original stylesheet, and the current output mode. Because it can vary so much,
stylesheet authors shouldn't rely on any particular output format for colors
they write.
[functional notation]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value
Sass supports many useful [color functions][] that can be used to create new
colors based on existing ones by [mixing colors together][] or [scaling their
hue, saturation, or lightness][].
[mixing colors together]: /documentation/modules/color#mix
[scaling their hue, saturation, or lightness]: /documentation/modules/color#scale
{% codeExample 'color-formats', false %}
$venus: #998099;
@debug scale-color($venus, $lightness: +15%); // #a893a8
@debug mix($venus, midnightblue); // #594d85
===
$venus: #998099
@debug scale-color($venus, $lightness: +15%) // #a893a8
@debug mix($venus, midnightblue) // #594d85
{% endcodeExample %}

View File

@ -1,19 +0,0 @@
---
title: Functions
---
{% render 'doc_snippets/call-impl-status' %}
{% markdown %}
[Functions][] can be values too! You can't directly write a function as a
value, but you can pass a function's name to the [`meta.get-function()`
function][] to get it as a value. Once you have a function value, you can pass
it to the [`meta.call()` function][] to call it. This is useful for writing
*higher-order functions* that call other functions.
[Functions]: /documentation/at-rules/function
[`meta.get-function()` function]: /documentation/modules/meta#get-function
[`meta.call()` function]: /documentation/modules/meta#call
{% endmarkdown %}
{% render 'code_snippets/example-first-class-function' %}

View File

@ -0,0 +1,17 @@
---
title: Functions
---
{% render 'doc_snippets/call-impl-status' %}
[Functions][] can be values too! You can't directly write a function as a value,
but you can pass a function's name to the [`meta.get-function()` function][] to
get it as a value. Once you have a function value, you can pass it to the
[`meta.call()` function][] to call it. This is useful for writing *higher-order
functions* that call other functions.
[Functions]: /documentation/at-rules/function
[`meta.get-function()` function]: /documentation/modules/meta#get-function
[`meta.call()` function]: /documentation/modules/meta#call
{% render 'code_snippets/example-first-class-function' %}

View File

@ -1,222 +0,0 @@
---
title: Lists
table_of_contents: true
---
{% compatibility 'dart: true', 'libsass: "3.5.0"', 'ruby: "3.5.0"', 'feature: "Square Brackets"' %}
Older implementations of LibSass and Ruby Sass didn't support lists with
square brackets.
{% endcompatibility %}
{% markdown %}
Lists contain a sequence of other values. In Sass, elements in lists can be
separated by commas (`Helvetica, Arial, sans-serif`), spaces (`10px 15px 0
0`), or [slashes] as long as it's consistent within the list. Unlike most
other languages, lists in Sass don't require special brackets; any
[expressions] separated with spaces or commas count as a list. However, you're
allowed to write lists with square brackets (`[line1 line2]`), which is useful
when using [`grid-template-columns`].
[slashes]: #slash-separated-lists
[expressions]: /documentation/syntax/structure#expressions
[`grid-template-columns`]: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
Sass lists can contain one or even zero elements. A single-element list can be
written either `(<expression>,)` or `[<expression>]`, and a zero-element list
can be written either `()` or `[]`. Also, all [list functions][] will treat
individual values that aren't in lists as though they're lists containing that
value, which means you rarely need to explicitly create single-element lists.
[list functions]: /documentation/modules/list
{% headsUp %}
Empty lists without brackets aren't valid CSS, so Sass won't let you use one
in a property value.
{% endheadsUp %}
## Slash-Separated Lists
Lists in Sass can be separated by slashes, to represent values like the `font:
12px/30px` shorthand for setting `font-size` and `line-height` or the `hsl(80
100% 50% / 0.5)` syntax for creating a color with a given opacity value.
However, **slash-separated lists can't currently be written literally.** Sass
historically used the `/` character to indicate division, so while existing
stylesheets transition to using [`math.div()`] slash-separated lists can only
be written using [`list.slash()`].
[`math.div()`]: /documentation/modules/math#div
[`list.slash()`]: /documentation/modules/list#slash
For more details, see [Breaking Change: Slash as Division].
[Breaking Change: Slash as Division]: /documentation/breaking-changes/slash-div
## Using Lists
Sass provides a handful of [functions][] that make it possible to use lists to
write powerful style libraries, or to make your app's stylesheet cleaner and
more maintainable.
[functions]: /documentation/modules/list
### Indexes
Many of these functions take or return numbers, called *indexes*, that refer
to the elements in a list. The index 1 indicates the first element of the
list. Note that this is different than many programming languages where
indexes start at 0! Sass also makes it easy to refer to the end of a list. The
index -1 refers to the last element in a list, -2 refers to the
second-to-last, and so on.
### Access an Element
Lists aren't much use if you can't get values out of them. You can use the
[`list.nth($list, $n)` function][] to get the element at a given index in a
list. The first argument is the list itself, and the second is the index of
the value you want to get out.
[`list.nth($list, $n)` function]: /documentation/modules/list#nth
{% endmarkdown %}
{% render 'code_snippets/example-list-nth' %}
{% markdown %}
### Do Something for Every Element
This doesn't actually use a function, but it's still one of the most common
ways to use lists. The [`@each` rule][] evaluates a block of styles for each
element in a list, and assigns that element to a variable.
[`@each` rule]: /documentation/at-rules/control/each
{% endmarkdown %}
{% render 'code_snippets/example-each-list' %}
{% markdown %}
### Add to a List
It's also useful to add elements to a list. The [`list.append($list, $val)`
function][] takes a list and a value, and returns a copy of the list with the
value added to the end. Note that because Sass lists are [immutable][], it
doesn't modify the original list.
[`list.append($list, $val)` function]: /documentation/modules/list#append
[immutable]: #immutability
{% endmarkdown %}
{% codeExample 'lists', false %}
@debug append(10px 12px 16px, 25px); // 10px 12px 16px 25px
@debug append([col1-line1], col1-line2); // [col1-line1, col1-line2]
===
@debug append(10px 12px 16px, 25px) // 10px 12px 16px 25px
@debug append([col1-line1], col1-line2) // [col1-line1, col1-line2]
{% endcodeExample %}
{% markdown %}
### Find an Element in a List
If you need to check if an element is in a list or figure out what index it's
at, use the [`list.index($list, $value)` function][]. This takes a list and a
value to locate in that list, and returns the index of that value.
[`list.index($list, $value)` function]: /documentation/modules/list#index
{% endmarkdown %}
{% render 'code_snippets/example-list-index' %}
{% markdown %}
If the value isn't in the list at all, `list.index()` returns [`null`][].
Because `null` is [falsey][], you can use `list.index()` with [`@if`][] or
[`if()`][] to check whether a list does or doesn't contain a given value.
[`null`]: /documentation/values/null
[falsey]: /documentation/at-rules/control/if#truthiness-and-falsiness
[`@if`]: /documentation/at-rules/control/if
[`if()`]: /documentation/modules#if
{% endmarkdown %}
{% codeExample 'list-index', false %}
@use "sass:list";
$valid-sides: top, bottom, left, right;
@mixin attach($side) {
@if not list.index($valid-sides, $side) {
@error "#{$side} is not a valid side. Expected one of #{$valid-sides}.";
}
// ...
}
===
@use "sass:list"
$valid-sides: top, bottom, left, right
@mixin attach($side)
@if not list.index($valid-sides, $side)
@error "#{$side} is not a valid side. Expected one of #{$valid-sides}."
// ...
{% endcodeExample %}
{% markdown %}
## Immutability
Lists in Sass are *immutable*, which means that the contents of a list value
never changes. Sass's list functions all return new lists rather than
modifying the originals. Immutability helps avoid lots of sneaky bugs that can
creep in when the same list is shared across different parts of the
stylesheet.
You can still update your state over time by assigning new lists to the same
variable, though. This is often used in functions and mixins to collect a
bunch of values into one list.
{% endmarkdown %}
{% codeExample 'immutability', false %}
@use "sass:list";
@use "sass:map";
$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms);
@function prefixes-for-browsers($browsers) {
$prefixes: ();
@each $browser in $browsers {
$prefixes: list.append($prefixes, map.get($prefixes-by-browser, $browser));
}
@return $prefixes;
}
@debug prefixes-for-browsers("firefox" "ie"); // moz ms
===
@use "sass:list"
@use "sass:map"
$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms)
@function prefixes-for-browsers($browsers)
$prefixes: ()
@each $browser in $browsers
$prefixes: list.append($prefixes, map.get($prefixes-by-browser, $browser))
@return $prefixes
@debug prefixes-for-browsers("firefox" "ie") // moz ms
{% endcodeExample %}
{% markdown %}
## Argument Lists
When you declare a mixin or function that takes [arbitrary arguments][], the
value you get is a special list known as an *argument list*. It acts just like
a list that contains all the arguments passed to the mixin or function, with
one extra feature: if the user passed keyword arguments, they can be accessed
as a map by passing the argument list to the [`meta.keywords()` function][].
[arbitrary arguments]: /documentation/at-rules/mixin#taking-arbitrary-arguments
[`meta.keywords()` function]: /documentation/modules/meta#keywords
{% endmarkdown %}
{% render 'code_snippets/example-mixin-arbitrary-keyword-arguments' %}

View File

@ -0,0 +1,206 @@
---
title: Lists
table_of_contents: true
---
{% compatibility 'dart: true', 'libsass: "3.5.0"', 'ruby: "3.5.0"', 'feature: "Square Brackets"' %}
Older implementations of LibSass and Ruby Sass didn't support lists with
square brackets.
{% endcompatibility %}
Lists contain a sequence of other values. In Sass, elements in lists can be
separated by commas (`Helvetica, Arial, sans-serif`), spaces (`10px 15px 0 0`),
or [slashes] as long as it's consistent within the list. Unlike most other
languages, lists in Sass don't require special brackets; any [expressions]
separated with spaces or commas count as a list. However, you're allowed to
write lists with square brackets (`[line1 line2]`), which is useful when using
[`grid-template-columns`].
[slashes]: #slash-separated-lists
[expressions]: /documentation/syntax/structure#expressions
[`grid-template-columns`]: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
Sass lists can contain one or even zero elements. A single-element list can be
written either `(<expression>,)` or `[<expression>]`, and a zero-element list
can be written either `()` or `[]`. Also, all [list functions][] will treat
individual values that aren't in lists as though they're lists containing that
value, which means you rarely need to explicitly create single-element lists.
[list functions]: /documentation/modules/list
{% headsUp %}
Empty lists without brackets aren't valid CSS, so Sass won't let you use one
in a property value.
{% endheadsUp %}
## Slash-Separated Lists
Lists in Sass can be separated by slashes, to represent values like the `font:
12px/30px` shorthand for setting `font-size` and `line-height` or the `hsl(80
100% 50% / 0.5)` syntax for creating a color with a given opacity value.
However, **slash-separated lists can't currently be written literally.** Sass
historically used the `/` character to indicate division, so while existing
stylesheets transition to using [`math.div()`] slash-separated lists can only be
written using [`list.slash()`].
[`math.div()`]: /documentation/modules/math#div
[`list.slash()`]: /documentation/modules/list#slash
For more details, see [Breaking Change: Slash as Division].
[Breaking Change: Slash as Division]: /documentation/breaking-changes/slash-div
## Using Lists
Sass provides a handful of [functions][] that make it possible to use lists to
write powerful style libraries, or to make your app's stylesheet cleaner and
more maintainable.
[functions]: /documentation/modules/list
### Indexes
Many of these functions take or return numbers, called *indexes*, that refer to
the elements in a list. The index 1 indicates the first element of the list.
Note that this is different than many programming languages where indexes start
at 0! Sass also makes it easy to refer to the end of a list. The index -1 refers
to the last element in a list, -2 refers to the second-to-last, and so on.
### Access an Element
Lists aren't much use if you can't get values out of them. You can use the
[`list.nth($list, $n)` function][] to get the element at a given index in a
list. The first argument is the list itself, and the second is the index of the
value you want to get out.
[`list.nth($list, $n)` function]: /documentation/modules/list#nth
{% render 'code_snippets/example-list-nth' %}
### Do Something for Every Element
This doesn't actually use a function, but it's still one of the most common ways
to use lists. The [`@each` rule][] evaluates a block of styles for each element
in a list, and assigns that element to a variable.
[`@each` rule]: /documentation/at-rules/control/each
{% render 'code_snippets/example-each-list' %}
### Add to a List
It's also useful to add elements to a list. The [`list.append($list, $val)`
function][] takes a list and a value, and returns a copy of the list with the
value added to the end. Note that because Sass lists are [immutable][], it
doesn't modify the original list.
[`list.append($list, $val)` function]: /documentation/modules/list#append
[immutable]: #immutability
{% codeExample 'lists', false %}
@debug append(10px 12px 16px, 25px); // 10px 12px 16px 25px
@debug append([col1-line1], col1-line2); // [col1-line1, col1-line2]
===
@debug append(10px 12px 16px, 25px) // 10px 12px 16px 25px
@debug append([col1-line1], col1-line2) // [col1-line1, col1-line2]
{% endcodeExample %}
### Find an Element in a List
If you need to check if an element is in a list or figure out what index it's
at, use the [`list.index($list, $value)` function][]. This takes a list and a
value to locate in that list, and returns the index of that value.
[`list.index($list, $value)` function]: /documentation/modules/list#index
{% render 'code_snippets/example-list-index' %}
If the value isn't in the list at all, `list.index()` returns [`null`][].
Because `null` is [falsey][], you can use `list.index()` with [`@if`][] or
[`if()`][] to check whether a list does or doesn't contain a given value.
[`null`]: /documentation/values/null
[falsey]: /documentation/at-rules/control/if#truthiness-and-falsiness
[`@if`]: /documentation/at-rules/control/if
[`if()`]: /documentation/modules#if
{% codeExample 'list-index', false %}
@use "sass:list";
$valid-sides: top, bottom, left, right;
@mixin attach($side) {
@if not list.index($valid-sides, $side) {
@error "#{$side} is not a valid side. Expected one of #{$valid-sides}.";
}
// ...
}
===
@use "sass:list"
$valid-sides: top, bottom, left, right
@mixin attach($side)
@if not list.index($valid-sides, $side)
@error "#{$side} is not a valid side. Expected one of #{$valid-sides}."
// ...
{% endcodeExample %}
## Immutability
Lists in Sass are *immutable*, which means that the contents of a list value
never changes. Sass's list functions all return new lists rather than modifying
the originals. Immutability helps avoid lots of sneaky bugs that can creep in
when the same list is shared across different parts of the stylesheet.
You can still update your state over time by assigning new lists to the same
variable, though. This is often used in functions and mixins to collect a bunch
of values into one list.
{% codeExample 'immutability', false %}
@use "sass:list";
@use "sass:map";
$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms);
@function prefixes-for-browsers($browsers) {
$prefixes: ();
@each $browser in $browsers {
$prefixes: list.append($prefixes, map.get($prefixes-by-browser, $browser));
}
@return $prefixes;
}
@debug prefixes-for-browsers("firefox" "ie"); // moz ms
===
@use "sass:list"
@use "sass:map"
$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms)
@function prefixes-for-browsers($browsers)
$prefixes: ()
@each $browser in $browsers
$prefixes: list.append($prefixes, map.get($prefixes-by-browser, $browser))
@return $prefixes
@debug prefixes-for-browsers("firefox" "ie") // moz ms
{% endcodeExample %}
## Argument Lists
When you declare a mixin or function that takes [arbitrary arguments][], the
value you get is a special list known as an *argument list*. It acts just like a
list that contains all the arguments passed to the mixin or function, with one
extra feature: if the user passed keyword arguments, they can be accessed as a
map by passing the argument list to the [`meta.keywords()` function][].
[arbitrary arguments]: /documentation/at-rules/mixin#taking-arbitrary-arguments
[`meta.keywords()` function]: /documentation/modules/meta#keywords
{% render 'code_snippets/example-mixin-arbitrary-keyword-arguments' %}

View File

@ -1,191 +0,0 @@
---
title: Maps
table_of_contents: true
---
{% markdown %}
Maps in Sass hold pairs of keys and values, and make it easy to look up a
value by its corresponding key. They're written `(<expression>: <expression>,
<expression>: <expression>)`. The
[expression](/documentation/syntax/structure#expressions) before the `:` is
the key, and the expression after is the value associated with that key. The
keys must be unique, but the values may be duplicated. Unlike
[lists](/documentation/values/lists), maps *must* be written with parentheses
around them. A map with no pairs is written `()`.
{% funFact %}
Astute readers may note that an empty map, `()`, is written the same as an
empty list. That's because it counts as both a map and a list. In fact,
*all* maps count as lists! Every map counts as a list that contains a
two-element list for each key/value pair. For example, `(1: 2, 3: 4)` counts
as `(1 2, 3 4)`.
{% endfunFact %}
Maps allow any Sass values to be used as their keys. The [`==` operator][] is
used to determine whether two keys are the same.
[`==` operator]: /documentation/operators/equality
{% headsUp %}
Most of the time, it's a good idea to use [quoted strings][] rather than
[unquoted strings][] for map keys. This is because some values, such as
color names, may *look* like unquoted strings but actually be other types.
To avoid confusing problems down the line, just use quotes!
[quoted strings]: /documentation/values/strings#quoted
[unquoted strings]: /documentation/values/strings#unquoted
{% endheadsUp %}
## Using Maps
Since maps aren't valid CSS values, they don't do much of anything on their
own. That's why Sass provides a bunch of [functions][] to create maps and
access the values they contain.
[functions]: /documentation/modules/map
### Look Up a Value
Maps are all about associating keys and values, so naturally there's a way to
get the value associated with a key: the [`map.get($map, $key)` function][]!
This function returns the value in the map associated with the given key. It
returns [`null`][] if the map doesn't contain the key.
[`map.get($map, $key)` function]: /documentation/modules/map#get
[`null`]: /documentation/values/null
{% endmarkdown %}
{% render 'code_snippets/example-map-get' %}
{% markdown %}
### Do Something for Every Pair
This doesn't actually use a function, but it's still one of the most common
ways to use maps. The [`@each` rule][] evaluates a block of styles for each
key/value pair in a map. The key and the value are assigned to variables so
they can easily be accessed in the block.
[`@each` rule]: /documentation/at-rules/control/each
{% endmarkdown %}
{% render 'code_snippets/example-each-map' %}
{% markdown %}
### Add to a Map
It's also useful to add new pairs to a map, or to replace the value for an
existing key. The [`map.set($map, $key, $value)` function][] does this: it
returns a copy of `$map` with the value at `$key` set to `$value`.
[`map.set($map, $key, $value)` function]: /documentation/modules/map#set
{% endmarkdown %}
{% codeExample 'maps', false %}
@use "sass:map";
$font-weights: ("regular": 400, "medium": 500, "bold": 700);
@debug map.set($font-weights, "extra-bold", 900);
// ("regular": 400, "medium": 500, "bold": 700, "extra-bold": 900)
@debug map.set($font-weights, "bold", 900);
// ("regular": 400, "medium": 500, "bold": 900)
===
@use "sass:map"
$font-weights: ("regular": 400, "medium": 500, "bold": 700)
@debug map.set($font-weights, "extra-bold": 900)
// ("regular": 400, "medium": 500, "bold": 700, "extra-bold": 900)
@debug map.set($font-weights, "bold", 900)
// ("regular": 400, "medium": 500, "bold": 900)
{% endcodeExample %}
{% markdown %}
Instead of setting values one-by-one, you can also merge two existing maps
using [`map.merge($map1, $map2)`][].
[`map.merge($map1, $map2)`]: /documentation/modules/map#merge
{% endmarkdown %}
{% codeExample 'map-merge', false %}
@use "sass:map";
$light-weights: ("lightest": 100, "light": 300);
$heavy-weights: ("medium": 500, "bold": 700);
@debug map.merge($light-weights, $heavy-weights);
// ("lightest": 100, "light": 300, "medium": 500, "bold": 700)
===
@use "sass:map"
$light-weights: ("lightest": 100, "light": 300)
$heavy-weights: ("medium": 500, "bold": 700)
@debug map.merge($light-weights, $heavy-weights)
// ("lightest": 100, "light": 300, "medium": 500, "bold": 700)
{% endcodeExample %}
{% markdown %}
If both maps have the same keys, the second map's values are used in the map
that gets returned.
{% endmarkdown %}
{% codeExample 'map-same-keys', false %}
@use "sass:map";
$weights: ("light": 300, "medium": 500);
@debug map.merge($weights, ("medium": 700));
// ("light": 300, "medium": 700)
===
@use "sass:map";
$weights: ("light": 300, "medium": 500)
@debug map.merge($weights, ("medium": 700))
// ("light": 300, "medium": 700)
{% endcodeExample %}
{% markdown %}
Note that because Sass maps are [immutable][], `map.set()` and `map.merge()`
do not modify the original list.
[immutable]: #immutability
## Immutability
Maps in Sass are *immutable*, which means that the contents of a map value
never changes. Sass's map functions all return new maps rather than modifying
the originals. Immutability helps avoid lots of sneaky bugs that can creep in
when the same map is shared across different parts of the stylesheet.
You can still update your state over time by assigning new maps to the same
variable, though. This is often used in functions and mixins to track
configuration in a map.
{% endmarkdown %}
{% codeExample 'immutability', false %}
@use "sass:map";
$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms);
@mixin add-browser-prefix($browser, $prefix) {
$prefixes-by-browser: map.merge($prefixes-by-browser, ($browser: $prefix)) !global;
}
@include add-browser-prefix("opera", o);
@debug $prefixes-by-browser;
// ("firefox": moz, "safari": webkit, "ie": ms, "opera": o)
===
@use "sass:map"
$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms)
@mixin add-browser-prefix($browser, $prefix)
$prefixes-by-browser: map.merge($prefixes-by-browser, ($browser: $prefix)) !global
@include add-browser-prefix("opera", o)
@debug $prefixes-by-browser
// ("firefox": moz, "safari": webkit, "ie": ms, "opera": o)
{% endcodeExample %}

View File

@ -0,0 +1,179 @@
---
title: Maps
table_of_contents: true
---
Maps in Sass hold pairs of keys and values, and make it easy to look up a value
by its corresponding key. They're written `(<expression>: <expression>,
<expression>: <expression>)`. The
[expression](/documentation/syntax/structure#expressions) before the `:` is the
key, and the expression after is the value associated with that key. The keys
must be unique, but the values may be duplicated. Unlike
[lists](/documentation/values/lists), maps *must* be written with parentheses
around them. A map with no pairs is written `()`.
{% funFact %}
Astute readers may note that an empty map, `()`, is written the same as an
empty list. That's because it counts as both a map and a list. In fact, *all*
maps count as lists! Every map counts as a list that contains a two-element
list for each key/value pair. For example, `(1: 2, 3: 4)` counts as `(1 2, 3
4)`.
{% endfunFact %}
Maps allow any Sass values to be used as their keys. The [`==` operator][] is
used to determine whether two keys are the same.
[`==` operator]: /documentation/operators/equality
{% headsUp %}
Most of the time, it's a good idea to use [quoted strings][] rather than
[unquoted strings][] for map keys. This is because some values, such as color
names, may *look* like unquoted strings but actually be other types. To avoid
confusing problems down the line, just use quotes!
[quoted strings]: /documentation/values/strings#quoted
[unquoted strings]: /documentation/values/strings#unquoted
{% endheadsUp %}
## Using Maps
Since maps aren't valid CSS values, they don't do much of anything on their own.
That's why Sass provides a bunch of [functions][] to create maps and access the
values they contain.
[functions]: /documentation/modules/map
### Look Up a Value
Maps are all about associating keys and values, so naturally there's a way to
get the value associated with a key: the [`map.get($map, $key)` function][]!
This function returns the value in the map associated with the given key. It
returns [`null`][] if the map doesn't contain the key.
[`map.get($map, $key)` function]: /documentation/modules/map#get
[`null`]: /documentation/values/null
{% render 'code_snippets/example-map-get' %}
### Do Something for Every Pair
This doesn't actually use a function, but it's still one of the most common ways
to use maps. The [`@each` rule][] evaluates a block of styles for each key/value
pair in a map. The key and the value are assigned to variables so they can
easily be accessed in the block.
[`@each` rule]: /documentation/at-rules/control/each
{% render 'code_snippets/example-each-map' %}
### Add to a Map
It's also useful to add new pairs to a map, or to replace the value for an
existing key. The [`map.set($map, $key, $value)` function][] does this: it
returns a copy of `$map` with the value at `$key` set to `$value`.
[`map.set($map, $key, $value)` function]: /documentation/modules/map#set
{% codeExample 'maps', false %}
@use "sass:map";
$font-weights: ("regular": 400, "medium": 500, "bold": 700);
@debug map.set($font-weights, "extra-bold", 900);
// ("regular": 400, "medium": 500, "bold": 700, "extra-bold": 900)
@debug map.set($font-weights, "bold", 900);
// ("regular": 400, "medium": 500, "bold": 900)
===
@use "sass:map"
$font-weights: ("regular": 400, "medium": 500, "bold": 700)
@debug map.set($font-weights, "extra-bold": 900)
// ("regular": 400, "medium": 500, "bold": 700, "extra-bold": 900)
@debug map.set($font-weights, "bold", 900)
// ("regular": 400, "medium": 500, "bold": 900)
{% endcodeExample %}
Instead of setting values one-by-one, you can also merge two existing maps using
[`map.merge($map1, $map2)`][].
[`map.merge($map1, $map2)`]: /documentation/modules/map#merge
{% codeExample 'map-merge', false %}
@use "sass:map";
$light-weights: ("lightest": 100, "light": 300);
$heavy-weights: ("medium": 500, "bold": 700);
@debug map.merge($light-weights, $heavy-weights);
// ("lightest": 100, "light": 300, "medium": 500, "bold": 700)
===
@use "sass:map"
$light-weights: ("lightest": 100, "light": 300)
$heavy-weights: ("medium": 500, "bold": 700)
@debug map.merge($light-weights, $heavy-weights)
// ("lightest": 100, "light": 300, "medium": 500, "bold": 700)
{% endcodeExample %}
If both maps have the same keys, the second map's values are used in the map
that gets returned.
{% codeExample 'map-same-keys', false %}
@use "sass:map";
$weights: ("light": 300, "medium": 500);
@debug map.merge($weights, ("medium": 700));
// ("light": 300, "medium": 700)
===
@use "sass:map";
$weights: ("light": 300, "medium": 500)
@debug map.merge($weights, ("medium": 700))
// ("light": 300, "medium": 700)
{% endcodeExample %}
Note that because Sass maps are [immutable][], `map.set()` and `map.merge()` do
not modify the original list.
[immutable]: #immutability
## Immutability
Maps in Sass are *immutable*, which means that the contents of a map value never
changes. Sass's map functions all return new maps rather than modifying the
originals. Immutability helps avoid lots of sneaky bugs that can creep in when
the same map is shared across different parts of the stylesheet.
You can still update your state over time by assigning new maps to the same
variable, though. This is often used in functions and mixins to track
configuration in a map.
{% codeExample 'immutability', false %}
@use "sass:map";
$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms);
@mixin add-browser-prefix($browser, $prefix) {
$prefixes-by-browser: map.merge($prefixes-by-browser, ($browser: $prefix)) !global;
}
@include add-browser-prefix("opera", o);
@debug $prefixes-by-browser;
// ("firefox": moz, "safari": webkit, "ie": ms, "opera": o)
===
@use "sass:map"
$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms)
@mixin add-browser-prefix($browser, $prefix)
$prefixes-by-browser: map.merge($prefixes-by-browser, ($browser: $prefix)) !global
@include add-browser-prefix("opera", o)
@debug $prefixes-by-browser
// ("firefox": moz, "safari": webkit, "ie": ms, "opera": o)
{% endcodeExample %}

View File

@ -22,12 +22,9 @@ introduction: >
@debug & // null
{% endcodeExample %}
{% markdown %}
If a [list][] contains a `null`, that `null` is omitted from the generated
CSS.
If a [list][] contains a `null`, that `null` is omitted from the generated CSS.
[list]: /documentation/values/lists
{% endmarkdown %}
[list]: /documentation/values/lists
{% codeExample 'null-lists' %}
$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas");
@ -42,9 +39,7 @@ introduction: >
font: 18px bold map-get($fonts, "sans")
{% endcodeExample %}
{% markdown %}
If a property value is `null`, that property is omitted entirely.
{% endmarkdown %}
If a property value is `null`, that property is omitted entirely.
{% codeExample 'null-value-omitted' %}
$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas");
@ -66,15 +61,13 @@ introduction: >
family: map-get($fonts, "sans")
{% endcodeExample %}
{% markdown %}
`null` is also [*falsey*][], which means it counts as `false` for any rules or
[operators][] that take booleans. This makes it easy to use values that can be
`null` as conditions for [`@if`][] and [`if()`][].
`null` is also [*falsey*][], which means it counts as `false` for any rules or
[operators][] that take booleans. This makes it easy to use values that can be
`null` as conditions for [`@if`][] and [`if()`][].
[*falsey*]: /documentation/at-rules/control/if#truthiness-and-falsiness
[operators]: /documentation/operators/boolean
[`@if`]: /documentation/at-rules/control/if
[`if()`]: /documentation/modules#if
{% endmarkdown %}
[*falsey*]: /documentation/at-rules/control/if#truthiness-and-falsiness
[operators]: /documentation/operators/boolean
[`@if`]: /documentation/at-rules/control/if
[`if()`]: /documentation/modules#if
{% render 'code_snippets/example-if-parent-selector' %}

View File

@ -19,14 +19,12 @@ introduction: >
@debug 5px * 2px // 10px*px (read "square pixels")
{% endcodeExample %}
{% markdown %}
Sass numbers support the same formats as CSS numbers, including [scientific
notation][], which is written with an `e` between the number and its power
of 10. Because support for scientific notation in browsers has historically
been spotty, Sass always compiles it to fully expanded numbers.
Sass numbers support the same formats as CSS numbers, including [scientific
notation][], which is written with an `e` between the number and its power of
10. Because support for scientific notation in browsers has historically been
spotty, Sass always compiles it to fully expanded numbers.
[scientific notation]: https://en.wikipedia.org/wiki/Scientific_notation
{% endmarkdown %}
[scientific notation]: https://en.wikipedia.org/wiki/Scientific_notation
{% codeExample 'scientific-notation', false %}
@debug 5.2e3; // 5200
@ -44,34 +42,32 @@ introduction: >
{% render 'doc_snippets/number-units' %}
{% markdown %}
## Precision
## Precision
{% compatibility 'dart: true', 'libsass: false', 'ruby: "3.5.0"', 'feature: "10 Digit Default"' %}
LibSass and older versions of Ruby Sass default to 5 digits of numeric
precision, but can be configured to use a different number. It's recommended
that users configure them for 10 digits for greater accuracy and
forwards-compatibility.
{% endcompatibility %}
{% compatibility 'dart: true', 'libsass: false', 'ruby: "3.5.0"', 'feature: "10 Digit Default"' %}
LibSass and older versions of Ruby Sass default to 5 digits of numeric
precision, but can be configured to use a different number. It's recommended
that users configure them for 10 digits for greater accuracy and
forwards-compatibility.
{% endcompatibility %}
Sass numbers are represented internally as 64-bit floating point values. They
support up to 10 digits of precision after the decimal point when serialized
to CSS and for the purposes of equality. This means a few different things:
Sass numbers are represented internally as 64-bit floating point values. They
support up to 10 digits of precision after the decimal point when serialized to
CSS and for the purposes of equality. This means a few different things:
* Only the first ten digits of a number after the decimal point will be
included in the generated CSS.
* Only the first ten digits of a number after the decimal point will be included
in the generated CSS.
* Operations like [`==`][] and [`>=`][] will consider two numbers equivalent
if they're the same up to the tenth digit after the decimal point.
* Operations like [`==`][] and [`>=`][] will consider two numbers equivalent if
they're the same up to the tenth digit after the decimal point.
* If a number is less than `0.0000000001` away from an integer, it's
considered to be an integer for the purposes of functions like
[`list.nth()`][] that require integer arguments.
* If a number is less than `0.0000000001` away from an integer, it's considered
to be an integer for the purposes of functions like [`list.nth()`][] that
require integer arguments.
[`==`]: /documentation/operators/equality
[`>=`]: /documentation/operators/relational
[`list.nth()`]: /documentation/modules/list#nth
{% endmarkdown %}
[`==`]: /documentation/operators/equality
[`>=`]: /documentation/operators/relational
[`list.nth()`]: /documentation/modules/list#nth
{% codeExample 'precision', false %}
@debug 0.012345678912345; // 0.0123456789

View File

@ -10,15 +10,13 @@ introduction: >
these cover the different kinds of text that appear in CSS.
---
{% funFact false %}
{% markdown %}
You can convert a quoted string to an unquoted string using the
[`string.unquote()` function][], and you can convert an unquoted string to a
quoted string using the [`string.quote()` function][].
{% funFact %}
You can convert a quoted string to an unquoted string using the
[`string.unquote()` function][], and you can convert an unquoted string to a
quoted string using the [`string.quote()` function][].
[`string.unquote()` function]: /documentation/modules/string#unquote
[`string.quote()` function]: /documentation/modules/string#quote
{% endmarkdown %}
[`string.unquote()` function]: /documentation/modules/string#unquote
[`string.quote()` function]: /documentation/modules/string#quote
{% codeExample 'fun-fact-strings', false %}
@use "sass:string";
@ -33,25 +31,22 @@ introduction: >
{% endcodeExample %}
{% endfunFact %}
{% markdown %}
## Escapes
## Escapes
All Sass strings support the standard CSS [escape codes][]:
All Sass strings support the standard CSS [escape codes][]:
[escape codes]: https://developer.mozilla.org/en-US/docs/Web/CSS/string#Syntax
[escape codes]: https://developer.mozilla.org/en-US/docs/Web/CSS/string#Syntax
* Any character other than a letter from A to F or a number from 0 to 9 (even
a newline!) can be included as part of a string by writing `\` in front of
it.
* Any character other than a letter from A to F or a number from 0 to 9 (even a
newline!) can be included as part of a string by writing `\` in front of it.
* Any character can be included as part of a string by writing `\` followed by
its [Unicode code point number][] written in [hexadecimal][]. You can
optionally include a space after the code point number to indicate where the
Unicode number ends.
* Any character can be included as part of a string by writing `\` followed by
its [Unicode code point number][] written in [hexadecimal][]. You can
optionally include a space after the code point number to indicate where the
Unicode number ends.
[Unicode code point number]: https://en.wikipedia.org/wiki/List_of_Unicode_characters
[hexadecimal]: https://en.wikipedia.org/wiki/Hexadecimal
{% endmarkdown %}
[Unicode code point number]: https://en.wikipedia.org/wiki/List_of_Unicode_characters
[hexadecimal]: https://en.wikipedia.org/wiki/Hexadecimal
{% codeExample 'escapes', false %}
@debug "\""; // '"'
@ -72,29 +67,27 @@ introduction: >
escape produces exactly the same string as writing the character itself.
{% endfunFact %}
{% markdown %}
## Quoted
## Quoted
Quoted strings are written between either single or double quotes, as in
`"Helvetica Neue"`. They can contain [interpolation][], as well as any
unescaped character except for:
Quoted strings are written between either single or double quotes, as in
`"Helvetica Neue"`. They can contain [interpolation][], as well as any unescaped
character except for:
[interpolation]: /documentation/interpolation
[interpolation]: /documentation/interpolation
* `\`, which can be escaped as `\\`;
* `'` or `"`, whichever was used to define that string, which can be escaped
as `\'` or `\"`;
* newlines, which can be escaped as `\a ` (including a trailing space).
* `\`, which can be escaped as `\\`;
* `'` or `"`, whichever was used to define that string, which can be escaped as
`\'` or `\"`;
* newlines, which can be escaped as `\a ` (including a trailing space).
Quoted strings are guaranteed to be compiled to CSS strings that have the same
contents as the original Sass strings. The exact format may vary based on the
implementation or configuration—a string containing a double quote may be
compiled to `"\""` or `'"'`, and a non-[ASCII][] character may or may not be
escaped. But that should be parsed the same in any standards-compliant CSS
implementation, including all browsers.
Quoted strings are guaranteed to be compiled to CSS strings that have the same
contents as the original Sass strings. The exact format may vary based on the
implementation or configuration—a string containing a double quote may be
compiled to `"\""` or `'"'`, and a non-[ASCII][] character may or may not be
escaped. But that should be parsed the same in any standards-compliant CSS
implementation, including all browsers.
[ASCII]: https://en.wikipedia.org/wiki/ASCII
{% endmarkdown %}
[ASCII]: https://en.wikipedia.org/wiki/ASCII
{% codeExample 'quoted', false %}
@debug "Helvetica Neue"; // "Helvetica Neue"
@ -123,15 +116,13 @@ introduction: >
[its quotes are removed]: /documentation/interpolation#quoted-strings
{% endfunFact %}
{% markdown %}
## Unquoted
## Unquoted
Unquoted strings are written as CSS [identifiers][], following the syntax
diagram below. They may include [interpolation][] anywhere.
Unquoted strings are written as CSS [identifiers][], following the syntax
diagram below. They may include [interpolation][] anywhere.
[identifiers]: https://drafts.csswg.org/css-syntax-3/#ident-token-diagram
[interpolation]: /documentation/interpolation
{% endmarkdown %}
[identifiers]: https://drafts.csswg.org/css-syntax-3/#ident-token-diagram
[interpolation]: /documentation/interpolation
<figure>
<object type="image/svg+xml" data="/assets/img/illustrations/identifier-diagram.svg"></object>
@ -173,31 +164,28 @@ introduction: >
strings.
{% endheadsUp %}
{% markdown %}
### Escapes in Unquoted Strings
### Escapes in Unquoted Strings
{% compatibility 'dart: "1.11.0"', 'libsass: false', 'ruby: false', 'feature: "Normalization"' %}
LibSass, Ruby Sass, and older versions of Dart Sass don't normalize escapes
in identifiers. Instead, the text in the unquoted string is the exact text
the user wrote. For example, `\1F46D` and `👭` are not considered
equivalent.
{% endcompatibility %}
{% compatibility 'dart: "1.11.0"', 'libsass: false', 'ruby: false', 'feature: "Normalization"' %}
LibSass, Ruby Sass, and older versions of Dart Sass don't normalize escapes in
identifiers. Instead, the text in the unquoted string is the exact text the
user wrote. For example, `\1F46D` and `👭` are not considered equivalent.
{% endcompatibility %}
When an unquoted string is parsed, the literal text of escapes are parsed as
part of the string. For example, `\a ` is parsed as the characters `\`, `a`,
and space. In order to ensure that unquoted strings that have the same
meanings in CSS are parsed the same way, though, these escapes are
*normalized*. For each code point, whether it's escaped or unescaped:
When an unquoted string is parsed, the literal text of escapes are parsed as
part of the string. For example, `\a ` is parsed as the characters `\`, `a`, and
space. In order to ensure that unquoted strings that have the same meanings in
CSS are parsed the same way, though, these escapes are *normalized*. For each
code point, whether it's escaped or unescaped:
* If it's a valid identifier character, it's included unescaped in the
unquoted string. For example, `\1F46D` returns the unquoted string `👭`.
* If it's a valid identifier character, it's included unescaped in the unquoted
string. For example, `\1F46D` returns the unquoted string `👭`.
* If it's a printable character other than a newline or a tab, it's included
after a `\`. For example, `\21 ` returns the unquoted string `\!`.
* If it's a printable character other than a newline or a tab, it's included
after a `\`. For example, `\21 ` returns the unquoted string `\!`.
* Otherwise, the lowercase Unicode escape is included with a trailing space.
For example, `\7Fx` returns the unquoted string `\7f x`.
{% endmarkdown %}
* Otherwise, the lowercase Unicode escape is included with a trailing space. For
example, `\7Fx` returns the unquoted string `\7f x`.
{% codeExample 'normalization', false %}
@use "sass:string";
@ -215,18 +203,16 @@ introduction: >
@debug string.length(\7Fx) // 5
{% endcodeExample %}
{% markdown %}
## String Indexes
## String Indexes
Sass has a number of [string functions][] that take or return numbers, called
*indexes*, that refer to the characters in a string. The index 1 indicates the
first character of the string. Note that this is different than many
programming languages where indexes start at 0! Sass also makes it easy to
refer to the end of a string. The index -1 refers to the last character in a
string, -2 refers to the second-to-last, and so on.
Sass has a number of [string functions][] that take or return numbers, called
*indexes*, that refer to the characters in a string. The index 1 indicates the
first character of the string. Note that this is different than many programming
languages where indexes start at 0! Sass also makes it easy to refer to the end
of a string. The index -1 refers to the last character in a string, -2 refers to
the second-to-last, and so on.
[string functions]: /documentation/modules/string
{% endmarkdown %}
[string functions]: /documentation/modules/string
{% codeExample 'string-indexes', false %}
@use "sass:string";