diff --git a/source/code-snippets/_example-use-with.html.erb b/source/code-snippets/_example-use-with.html.erb new file mode 100644 index 000000000..20cac3d3d --- /dev/null +++ b/source/code-snippets/_example-use-with.html.erb @@ -0,0 +1,34 @@ +<% example do %> + // _library.scss + $black: #000 !default; + $border-radius: 0.25rem !default; + $box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default; + + code { + border-radius: $border-radius; + box-shadow: $box-shadow; + } + --- + // style.scss + @use 'library' with ( + $black: #222, + $border-radius: 0.1rem + ); + === + // _library.sass + $black: #000 !default + $border-radius: 0.25rem !default + $box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default + + code + border-radius: $border-radius + box-shadow: $box-shadow + --- + // style.sass + @use 'library' with ($black: #222, $border-radius: 0.1rem) + === + code { + border-radius: 0.1rem; + box-shadow: 0 0.5rem 1rem rgba(#222, 0.15); + } +<% end %> diff --git a/source/documentation/at-rules/forward.html.md.erb b/source/documentation/at-rules/forward.html.md.erb index ac5b32d85..15b52d255 100644 --- a/source/documentation/at-rules/forward.html.md.erb +++ b/source/documentation/at-rules/forward.html.md.erb @@ -3,3 +3,5 @@ title: "@forward" introduction: > TODO(nweiz): Write this --- + +## Controlling Visibility diff --git a/source/documentation/at-rules/use.html.md.erb b/source/documentation/at-rules/use.html.md.erb index 552d9511c..50b44e303 100644 --- a/source/documentation/at-rules/use.html.md.erb +++ b/source/documentation/at-rules/use.html.md.erb @@ -1,9 +1,431 @@ --- title: "@use" +table_of_contents: true introduction: > - TODO(nweiz): Write this + The `@use` rule loads [mixins](mixin), [functions](function), and + [variables](../variables) from other Sass stylesheets, and combines CSS from + multiple stylesheets together. Stylesheets loaded by `@use` are called + "modules". Sass also provides [built-in modules](../functions) full of useful + functions. --- +<% content_for :before_introduction do %> + <%= partial '../snippets/module-system-status' %> +<% end %> + +The simplest `@use` rule is written `@use ""`, which loads the module at +the given URL. Any CSS in modules you load will be included exactly once in your +compiled CSS, no matter how many times they're loaded. + +<% heads_up do %> + A stylesheet's `@use` rules must come before any rules other than `@forward`, + including [style rules][]. However, you can declare variables before `@use` + rules to use when [configuring modules][]. + + [style rules]: ../style-rules + [configuring modules]: #configuring-modules +<% end %> + +<% example do %> + // foundation/_code.scss + code { + padding: .25em; + line-height: 0; + } + --- + // foundation/_lists.scss + ul, ol { + text-align: left; + + & & { + padding: { + bottom: 0; + left: 0; + } + } + } + --- + // style.scss + @use 'foundation/code'; + @use 'foundation/lists'; + === + // foundation/_code.sass + code + padding: .25em + line-height: 0 + --- + // foundation/_lists.sass + ul, ol + text-align: left + + & & + padding: + bottom: 0 + left: 0 + --- + // style.sass + @use 'foundation/code' + @use 'foundation/lists' + === + code { + padding: .25em; + line-height: 0; + } + + ul, ol { + text-align: left; + } + ul ul, ol ol { + padding-bottom: 0; + padding-left: 0; + } +<% end %> + +## Loading Members + +You can access the variables, functions, and mixins by writing +`.`, `.()`, or `@include +.()`. By default, the namespace is just the last component of +the module's URL. + +Members (variables, functions, and mixins) loaded with `@use` are only visible +in the stylesheet that loads them. Other stylesheets will need to write their +own `@use` rules if they also want to access them. This helps make it easy to +figure out exactly where each member is coming from. If you want to load members +from many files at once, you can use the [`@forward` rule][] to forward them all +from one shared file. + +[`@forward` rule]: forward + +<% fun_fact do %> + Because `@use` adds namespaces to member names, it's safe to choose very + simple names like `$radius` or `$width` when writing a stylesheet. This is + different from the old [`@import` rule][], which encouraged that users write + long names like `$mat-corner-radius` to avoid conflicts with other + libraries, and it helps keep your stylesheets clear and easy to read! + + [`@import` rule]: import +<% end %> + +<% example do %> + // src/_corners.scss + $radius: 3px; + + @mixin rounded { + border-radius: $radius; + } + --- + // style.scss + @use "src/corners"; + + .button { + @include corners.rounded; + padding: 5px + corners.$radius; + } + === + // src/_corners.sass + $radius: 5px + + @mixin rounded + border-radius: $radius + --- + // style.sass + @use "src/corners" + + .button + @include corners.rounded + padding: 5px + corners.$radius + === + .button { + border-radius: 3px; + padding: 8px; + } +<% end %> + +### Choosing a Namespace + +By default, a module's namespace is just the last component of its URL without a +file extension. However, sometimes you might want to choose a different +namespace—you might want to use a shorter name for a module you refer to a lot, +or you might be loading multiple modules with the same filename. You can do this +by writine `@use "" as `. + +<% example do %> + // src/_corners.scss + $radius: 3px; + + @mixin rounded { + border-radius: $radius; + } + --- + // style.scss + @use "src/corners" as c; + + .button { + @include c.rounded; + padding: 5px + c.$radius; + } + === + // src/_corners.sass + $radius: 5px + + @mixin rounded + border-radius: $radius + --- + // style.sass + @use "src/corners" as c + + .button + @include c.rounded + padding: 5px + c.$radius + === + .button { + border-radius: 3px; + padding: 8px; + } +<% end %> + +You can even load a module *without* a namespace by writing `@use "" as *`. +We recommend you only do this for stylesheets written by you, though; otherwise, +they may introduce new members that cause name conflicts! + +<% example do %> + // src/_corners.scss + $radius: 3px; + + @mixin rounded { + border-radius: $radius; + } + --- + // style.scss + @use "src/corners" as *; + + .button { + @include rounded; + padding: 5px + $radius; + } + === + // src/_corners.sass + $radius: 5px + + @mixin rounded + border-radius: $radius + --- + // style.sass + @use "src/corners" as * + + .button + @include rounded + padding: 5px + $radius + === + .button { + border-radius: 3px; + padding: 8px; + } +<% end %> + +### Private Members + +As a stylesheet author, you may not want all the members you define to be +available outside your stylesheet. Sass makes it easy to define a private member +by starting its name with either `-` or `_`. These members will work just like +normal within the stylesheet that defines them, but they won't be part of a +module's public API. That means stylesheets that load your module can't see +them! + +<% fun_fact do %> + If you want to make a member private to an entire *package* rather than just a + single module, just don't [forward its module][] from any of your package's + entrypoints (the stylesheets you tell your users to load to use your package). + You can even [hide that member][] while forwarding the rest of its module! + + [forward its module]: forward + [hide that member]: forward#controlling-visibility +<% end %> + +<% example(autogen_css: false) do %> + // src/_corners.scss + $-radius: 3px; + + @mixin rounded { + border-radius: $-radius; + } + --- + // style.scss + @use "src/corners"; + + .button { + @include corners.rounded; + + // This is an error! $-radius isn't visible outside of `_corners.scss`. + padding: 5px + corners.$-radius; + } + === + // src/_corners.sass + $-radius: 5px + + @mixin rounded + border-radius: $radius + --- + // style.sass + @use "src/corners" + + .button + @include corners.rounded + + // This is an error! $-radius isn't visible outside of `_corners.scss`. + padding: 5px + corners.$-radius +<% end %> + +## Configuring Modules + +A stylesheet can define variables with the [`!default` flag][] to make them +configurable. To load a module with configuration, write `@use with +(: , : )`. The configured values will override +the variables' default values. + +[`!default` flag]: ../variables#default-values + +<%= partial '../../code-snippets/example-use-with' %> + +## Finding the Module + +It wouldn't be any fun to write out absolute URLs for every stylesheet you load, +so Sass's algorithm for finding a module makes it a little easier. For starters, +you don't have to explicitly write out the extension of the file you want to +load; `@use "variables"` will automatically load `variables.scss`, +`variables.sass`, or `variables.css`. + +<% heads_up do %> + To ensure that stylesheets work on every operating system, Sass loads files by + *URL*, not by *file path*. This means you need to use forward slashes, not + backslashes, even when you're on Windows. +<% end %> + ### Load Paths +All Sass implementations allow users to provide *load paths*: paths on the +filesystem that Sass will look in when locating modules. For example, if you +pass `node_modules/susy/sass` as a load path, you can use `@use "susy"` to load +`node_modules/susy/sass/susy.scss`. + +Modules will always be loaded relative to the current file first, though. Load +paths will only be used if no relative file exists that matches the module's +URL. This ensures that you can't accidentally mess up your relative imports when +you add a new library. + +<% fun_fact do %> + Unlike some other languages, Sass doesn't require that you use `./` for + relative imports. Relative imports are always available. +<% end %> + ### Partials + +As a convention, Sass files that are only meant to be loaded as modules, not +compiled on their own, begin with `_` (as in `_code.scss`). These are called +*partials*, and they tell Sass tools not to try to compile those files on their +own. You can leave off the `_` when importing a partial. + +### Index Files + +If you write an `_index.scss` or `_index.sass` in a folder, the index file will +be loaded automatically. when you load the URL for the folder itself. + +<% example do %> + // foundation/_code.scss + code { + padding: .25em; + line-height: 0; + } + --- + // foundation/_lists.scss + ul, ol { + text-align: left; + + & & { + padding: { + bottom: 0; + left: 0; + } + } + } + --- + // foundation/_index.scss + @use 'code'; + @use 'lists'; + --- + // style.scss + @use 'foundation'; + === + // foundation/_code.sass + code + padding: .25em + line-height: 0 + --- + // foundation/_lists.sass + ul, ol + text-align: left + + & & + padding: + bottom: 0 + left: 0 + --- + // foundation/_index.sass + @use 'code' + @use 'lists' + --- + // style.sass + @use 'foundation' + === + code { + padding: .25em; + line-height: 0; + } + + ul, ol { + text-align: left; + } + ul ul, ol ol { + padding-bottom: 0; + padding-left: 0; + } +<% end %> + +## Loading CSS + +In addition to loading `.sass` and `.scss` files, Sass can load plain old `.css` +files. + +<% example do %> + // code.css + code { + padding: .25em; + line-height: 0; + } + --- + // style.scss + @use 'code'; + === + // code.css + code { + padding: .25em; + line-height: 0; + } + --- + // style.sass + @use 'code' + === + code { + padding: .25em; + line-height: 0; + } +<% end %> + +CSS files loaded as modules don't allow any special Sass features and so can't +expose any Sass variables, functions, or mixins. In order to make sure authors +don't accidentally write Sass in their CSS, all Sass features that aren't also +valid CSS will produce errors. Otherwise, the CSS will be rendered as-is. It can +even be [extended][]! + +[extended]: extend diff --git a/source/documentation/variables.html.md.erb b/source/documentation/variables.html.md.erb index a7d53c810..19dda5213 100644 --- a/source/documentation/variables.html.md.erb +++ b/source/documentation/variables.html.md.erb @@ -83,7 +83,7 @@ variable, just include it in a value. Normally when you assign a value to a variable, if that variable already had a value, its old value is overwritten. But if you're writing a Sass library, you -might want to allow your users to customize your library's variables before you +might want to allow your users to configure your library's variables before you use them to generate CSS. To make this possible, Sass provides the `!default` flag. This assigns a value @@ -92,55 +92,22 @@ Otherwise, the existing value will be used. [`null`]: values/null -### Customizing Modules +### Configuring Modules <%= partial 'snippets/module-system-status' %> -Variables defined with `!default` can be customized when loading a module with +Variables defined with `!default` can be configured when loading a module with the [`@use` rule][]. Sass libraries often use `!default` variables to allow -their users to customize the library's CSS. +their users to configure the library's CSS. [`@use` rule]: at-rules/use -To load a module with customization, write `@use with (: -, : )`. The customized values will override the +To load a module with configuration, write `@use with (: +, : )`. The configured values will override the variables' default values. Only variables written at the top level of the -stylesheet with a `!default` flag can be customized. +stylesheet with a `!default` flag can be configured. -<% example do %> - // _library.scss - $black: #000 !default; - $border-radius: 0.25rem !default; - $box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default; - - code { - border-radius: $border-radius; - box-shadow: $box-shadow; - } - --- - // style.scss - @use 'library' with ( - $black: #222, - $border-radius: 0.1rem - ); - === - // _library.sass - $black: #000 !default - $border-radius: 0.25rem !default - $box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default - - code - border-radius: $border-radius - box-shadow: $box-shadow - --- - // style.sass - @use 'library' with ($black: #222, $border-radius: 0.1rem) - === - code { - border-radius: 0.1rem; - box-shadow: 0 0.5rem 1rem rgba(#222, 0.15); - } -<% end %> +<%= partial '../code-snippets/example-use-with' %> ## Scope diff --git a/source/layouts/has_both_sidebars.haml b/source/layouts/has_both_sidebars.haml index 9afb64fb7..de6ef2a45 100644 --- a/source/layouts/has_both_sidebars.haml +++ b/source/layouts/has_both_sidebars.haml @@ -16,6 +16,7 @@ - container = current_page.data.no_container ? '' : 'sl-l-container sl-l-container--small' - container << ' sl-l-container--overview' if current_page.data.intro %div{class: container} + = yield_content :before_introduction - if current_page.data.introduction - center_introduction = current_page.data.center_introduction ? 'sl-c-introduction--center' : '' .sl-c-introduction{class: center_introduction} diff --git a/source/layouts/has_complementary.haml b/source/layouts/has_complementary.haml index c6250f3d1..2da3c0888 100644 --- a/source/layouts/has_complementary.haml +++ b/source/layouts/has_complementary.haml @@ -4,6 +4,7 @@ .sl-l-large-holy-grail__main - container = current_page.data.no_container ? '' : 'sl-l-container sl-l-container--small' %div{class: container} + = yield_content :before_introduction - if current_page.data.introduction - center_introduction = current_page.data.center_introduction ? 'sl-c-introduction--center' : '' .sl-c-introduction{class: center_introduction} diff --git a/source/layouts/has_navigation.haml b/source/layouts/has_navigation.haml index a2077668b..913878972 100644 --- a/source/layouts/has_navigation.haml +++ b/source/layouts/has_navigation.haml @@ -7,6 +7,7 @@ .sl-l-medium-holy-grail__main - container = current_page.data.no_container ? '' : 'sl-l-container sl-l-container--small' %div{class: container} + = yield_content :before_introduction - if current_page.data.introduction - center_introduction = current_page.data.center_introduction ? 'sl-c-introduction--center' : '' .sl-c-introduction{class: center_introduction} diff --git a/source/layouts/has_no_sidebars.haml b/source/layouts/has_no_sidebars.haml index 68c196a95..c508bd08d 100644 --- a/source/layouts/has_no_sidebars.haml +++ b/source/layouts/has_no_sidebars.haml @@ -1,6 +1,7 @@ = wrap_layout :layout do - container = current_page.data.no_container ? '' : 'sl-l-container sl-l-container--small' .docSearch-content{class: container} + = yield_content :before_introduction - if current_page.data.introduction - center_introduction = current_page.data.center_introduction ? 'sl-c-introduction--center' : '' .sl-c-introduction{class: center_introduction}