diff --git a/Gemfile b/Gemfile index f71d47dc2..333219bff 100644 --- a/Gemfile +++ b/Gemfile @@ -2,9 +2,10 @@ source "https://rubygems.org" ruby "2.5.3" gem "builder", "~> 3.2.2" -gem "html-proofer", "~> 3.10" +gem "html-proofer", "~> 3.13" gem "middleman", "~> 3.4.1" gem "middleman-autoprefixer", "~> 2.6.2" +gem "middleman-blog", "~> 3.5.3" gem "middleman-livereload", "~> 3.4.5" gem "middleman-minify-html", "~> 3.4.1" gem "middleman-syntax", "~> 2.0.0" diff --git a/Gemfile.lock b/Gemfile.lock index 1b40a35c8..eeff52d28 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,8 +6,7 @@ GEM minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - addressable (2.5.2) - public_suffix (>= 2.0.2, < 4.0) + addressable (2.3.8) autoprefixer-rails (6.2.3) execjs json @@ -23,7 +22,6 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - colorize (0.8.1) compass (1.0.3) chunky_png (~> 1.2) compass-core (~> 1.0.2) @@ -40,7 +38,7 @@ GEM eventmachine (>= 0.12.9) http_parser.rb (~> 0.6.0) erubis (2.7.0) - ethon (0.11.0) + ethon (0.12.0) ffi (>= 1.3.0) eventmachine (1.2.7) execjs (2.7.0) @@ -51,13 +49,12 @@ GEM hike (1.2.3) hooks (0.4.1) uber (~> 0.0.14) - html-proofer (3.10.0) - activesupport (>= 4.2, < 6.0) + html-proofer (3.13.0) addressable (~> 2.3) - colorize (~> 0.8) - mercenary (~> 0.3.2) - nokogiri (~> 1.9) + mercenary (~> 0.3) + nokogiri (~> 1.10) parallel (~> 1.3) + rainbow (~> 3.0) typhoeus (~> 1.3) yell (~> 2.0) htmlcompressor (0.2.0) @@ -84,6 +81,10 @@ GEM middleman-autoprefixer (2.6.3) autoprefixer-rails (~> 6.2.1) middleman-core (>= 3.3.3) + middleman-blog (3.5.3) + addressable (~> 2.3.5) + middleman-core (~> 3.2) + tzinfo (>= 0.3.0) middleman-core (3.4.1) activesupport (~> 4.1) bundler (~> 1.1) @@ -127,8 +128,7 @@ GEM tilt (>= 1.4.1, < 3) padrino-support (0.12.9) activesupport (>= 3.1) - parallel (1.12.1) - public_suffix (3.0.3) + parallel (1.18.0) puma (3.12.0) rack (1.6.11) rack-conditional (0.3.1) @@ -142,6 +142,7 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) + rainbow (3.0.0) rake (12.3.2) rb-fsevent (0.10.3) rb-inotify (0.10.0) @@ -181,16 +182,17 @@ GEM json (>= 1.8.0) xpath (2.1.0) nokogiri (~> 1.3) - yell (2.0.7) + yell (2.2.0) PLATFORMS ruby DEPENDENCIES builder (~> 3.2.2) - html-proofer (~> 3.10) + html-proofer (~> 3.13) middleman (~> 3.4.1) middleman-autoprefixer (~> 2.6.2) + middleman-blog (~> 3.5.3) middleman-livereload (~> 3.4.5) middleman-minify-html (~> 3.4.1) middleman-syntax (~> 2.0.0) diff --git a/Rakefile b/Rakefile index b31e77108..2e8266e2c 100644 --- a/Rakefile +++ b/Rakefile @@ -10,11 +10,16 @@ task :test_without_rebuild do HTMLProofer.check_directory("build", url_ignore: [ "https://www.drupal.org/dcoc", # This doesn't allow automated requests. - "http://sass.logdown.com/posts/7081811", # This times out occasionally. + # These are linked to from older blog posts. They redirect to updated + # pages. + %r{/documentation/file.SASS_REFERENCE.html(#.*)?}, + %r{/documentation/file.SASS_CHANGELOG.html(#.*)?}, + %r{/documentation/Sass/Script/Functions.html(#.*)?}, "#", ], - url_swap: {%r{^/blog/} => "http://sass.logdown.com/"}, assume_extension: true, + # These have the same links as blog posts + file_ignore: ["blog.html", %r{blog/page/.*}], # Lots of external URLs fail flakily on Travis, so we just don't check them # there. disable_external: ENV["TRAVIS"] == "true" diff --git a/config.rb b/config.rb index 55bb0b6d5..1bc976152 100644 --- a/config.rb +++ b/config.rb @@ -12,9 +12,19 @@ activate :livereload activate :syntax +activate :blog do |blog| + blog.prefix = "blog" + blog.default_extension = ".md" + blog.sources = "{id}-{title}.html" + blog.permalink = "/{title}.html" + blog.paginate = true + blog.summary_length = 1000 +end + set :markdown, fenced_code_blocks: true, autolink: true, smartypants: true, + footnotes: true, with_toc_data: true Haml::Filters::Markdown.options.merge! fenced_code_blocks: true, autolink: true @@ -38,6 +48,7 @@ page '/libsass.html', :layout => :has_both_sidebars page '/styleguide/*', :layout => :section_styleguide page '/documentation/*', :layout => :section_reference +page '/blog/*', :layout => :blog configure :development do config[:host] = 'http://localhost:4567' diff --git a/config.ru b/config.ru index 7221bdae5..d5955e3a3 100644 --- a/config.ru +++ b/config.ru @@ -31,7 +31,16 @@ use Rack::Rewrite do r301 %r{/(.+)/$}, '/$1' r301 %r{/(.+)/index\.html$}, '/$1' - r301 %r{/blog/(.*)}, 'http://sass.logdown.com/$1' + # We used to redirect Logdown URLs to the sass.logdown.com, but now we + # redirect them to the local site's corresponding blog URLs. + r301 %r{/blog/posts/\d+-(.*)}, '/blog/$1' + + # Some blog posts didn't have slugs in Logdown. + r301 %r{/blog/posts/560719}, '/blog/dropping-support-for-old-ruby-versions' + r301 %r{/blog/posts/1305238}, '/blog/dart-sass-is-on-chocolatey' + r301 %r{/blog/posts/1404451}, '/blog/sass-and-browser-compatibility' + r301 %r{/blog/posts/1909151}, '/blog/dart-sass-is-in-beta' + r301 %r{/blog/posts/7081811}, '/blog/ruby-sass-is-deprecated' # Provide short links for breaking changes so that they can be tersely # referenced from warning and errors. diff --git a/helpers/sass_helpers.rb b/helpers/sass_helpers.rb index 66ed06f99..635b5825b 100644 --- a/helpers/sass_helpers.rb +++ b/helpers/sass_helpers.rb @@ -51,6 +51,10 @@ def pages_for_group(group_name) pages.flatten end + def without_html(page) + url_for(page).sub(/\.html$/, '') + end + def documentation_toc _toc_level(nil, data.documentation.toc) end diff --git a/source/assets/css/components/_attribution.scss b/source/assets/css/components/_attribution.scss new file mode 100644 index 000000000..ec8dc0003 --- /dev/null +++ b/source/assets/css/components/_attribution.scss @@ -0,0 +1,10 @@ +.sl-c-attribution { + font-weight: $sl-font-weight--light; + font-size: $sl-font-size--small; + + &:first-child { + text-align: center; + margin-top: -3em; + margin-bottom: 2em; + } +} diff --git a/source/assets/css/sass.css.scss b/source/assets/css/sass.css.scss index 8763ca1f7..af0b42f62 100755 --- a/source/assets/css/sass.css.scss +++ b/source/assets/css/sass.css.scss @@ -23,6 +23,7 @@ 'layout/sections', 'components/alerts', + 'components/attribution', 'components/buttons', 'components/callouts', 'components/navigation', diff --git a/source/assets/img/blog/006-sass-visitors.png b/source/assets/img/blog/006-sass-visitors.png new file mode 100644 index 000000000..0f4509aad Binary files /dev/null and b/source/assets/img/blog/006-sass-visitors.png differ diff --git a/source/assets/img/blog/020-goodbye.gif b/source/assets/img/blog/020-goodbye.gif new file mode 100644 index 000000000..c657aca71 Binary files /dev/null and b/source/assets/img/blog/020-goodbye.gif differ diff --git a/source/assets/img/blog/021-function-docs.png b/source/assets/img/blog/021-function-docs.png new file mode 100644 index 000000000..80e666c37 Binary files /dev/null and b/source/assets/img/blog/021-function-docs.png differ diff --git a/source/assets/img/blog/021-functions-math.png b/source/assets/img/blog/021-functions-math.png new file mode 100644 index 000000000..89af8a88e Binary files /dev/null and b/source/assets/img/blog/021-functions-math.png differ diff --git a/source/assets/img/blog/021-search.png b/source/assets/img/blog/021-search.png new file mode 100644 index 000000000..ea6807202 Binary files /dev/null and b/source/assets/img/blog/021-search.png differ diff --git a/source/assets/img/blog/021-syntax-switcher.png b/source/assets/img/blog/021-syntax-switcher.png new file mode 100644 index 000000000..f57a50c3e Binary files /dev/null and b/source/assets/img/blog/021-syntax-switcher.png differ diff --git a/source/blog.html.haml b/source/blog.html.haml new file mode 100644 index 000000000..2600c1f46 --- /dev/null +++ b/source/blog.html.haml @@ -0,0 +1,17 @@ +--- +title: Sass Blog +pageable: true +per_page: 5 +--- + +- if paginate && num_pages > 1 + %p Page #{page_number} of #{num_pages} + %p= link_to 'Previous page', without_html(prev_page) if prev_page + +- page_articles.each_with_index do |article, i| + %h2= link_to article.title, without_html(article) + = partial 'layouts/components/attribution', locals: {page: article} + = article.summary + +- if paginate + %p= link_to 'Next page', without_html(next_page) if next_page diff --git a/source/blog/001-how-extend-works.html.md b/source/blog/001-how-extend-works.html.md new file mode 100644 index 000000000..4e8b5692e --- /dev/null +++ b/source/blog/001-how-extend-works.html.md @@ -0,0 +1,204 @@ +--- +title: How @extend Works +author: Natalie Weizenbaum +date: 2013-11-22 16:57 PST +--- + +_This was originally published as [a gist](https://gist.github.com/nex3/7609394)_. + +[Aaron Leung](https://github.com/akhleung) is working on +[hcatlin/libsass](http://github.com/hcatlin/libsass) and was wondering how +`@extend` is implemented in the Ruby implementation of Sass. Rather than just +tell him, I thought I'd write up a public document about it so anyone who's +porting Sass or is just curious about how it works can see. + +Note that this explanation is simplified in numerous ways. It's intended to +explain the most complex parts of a basic correct `@extend` transformation, but +it leaves out numerous details that will be important if full Sass compatibility +is desired. This should be considered an explication of the groundwork for +`@extend`, upon which full support can be built. For a complete understanding of +`@extend`, there's no substitute for consulting the [Ruby Sass +code](http://github.com/sass/ruby-sass/tree/master/lib/sass) and [its +tests](https://github.com/sass/ruby-sass/blob/master/test/sass/extend_test.rb). + +This document assumes familiarity with the selector terminology defined in the +[Selectors Level 4](http://dev.w3.org/csswg/selectors4/#syntax) spec. Throughout +the document, selectors will be treated interchangeably with lists or sets of +their components. For example, a complex selector may be treated as a list of +compound selectors or a list of lists of simple selectors. + +## Primitives + +Following are a set of primitive objects, definitions, and operations that are +necessary for implementing `@extend`. Implementing these is left as an exercise +for the reader. + +* A selector object is obviously necessary, since `@extend` is all about + selectors. Selectors will need to be parsed thoroughly and semantically. It's + necessary for the implementation to know a fair amount of the meaning behind + the various different forms of selectors. + +* A custom data structure I call a "subset map" is also necessary. A subset map + has two operations: `Map.set(Set, Object)` and `Map.get(Set) => [Object]`. The + former associates a value with a set of keys in the map. The latter looks up + all values that are associated with *subsets* of a set of keys. For example: + + map.set([1, 2], 'value1') + map.set([2, 3], 'value2) + map.set([3, 4], 'value3') + map.get([1, 2, 3]) => ['value1', 'value2'] + +* A selector `S1` is a "superselector" of a selector `S2` if every element + matched by `S2` is also matched by `S1`. For example, `.foo` is a + superselector of `.foo.bar`, `a` is a superselector of `div a`, and `*` is a + superselector of everything. The inverse of a superselector is a + "subselector". + +* An operation `unify(Compound Selector, Compound Selector) => Compound + Selector` that returns a selector that matches exactly those elements matched + by both input selectors. For example, `unify(.foo, .bar)` returns `.foo.bar`. + This only needs to work for compound or simpler selectors. This operation can + fail (e.g. `unify(a, h1)`), in which case it should return `null`. + +* An operation `trim([Selector List]) => Selector List` that removes complex + selectors that are subselectors of other complex selectors in the input. It + takes the input as multiple selector lists and only checks for subselectors + across these lists since the prior `@extend` process won't produce intra-list + subselectors. For example, if it's passed `[[a], [.foo a]]` it would return + `[a]` since `.foo a` is a subselector of `a`. + +* An operation `paths([[Object]]) => [[Object]]` that returns a list of all + possible paths through a list of choices for each step. For example, + `paths([[1, 2], [3], [4, 5, 6]])` returns `[[1, 3, 4], [1, 3, 5], [1, 3, 6], + [2, 3, 4], [2, 3, 5], [2, 3, 6]]`. + +## The Algorithm + +The `@extend` algorithm requires two passes: one to record the `@extend`s that +are declared in the stylesheet, and another to transform selectors using those +`@extend`s. This is necessary, since `@extend`s can affect selectors earlier in +the stylesheet as well. + +### Recording Pass + +In pseudocode, this pass can be described as follows: + +``` +let MAP be an empty subset map from simple selectors to (complex selector, compound selector) pairs +for each @extend in the document: + let EXTENDER be the complex selector of the CSS rule containing the @extend + let TARGET be the compound selector being @extended + MAP.set(TARGET, (EXTENDER, TARGET)) +``` + +### Transformation Pass + +The transformation pass is more complicated than the recording pass. It's +described in pseudocode below: + +``` +let MAP be the subset map from the recording pass + +define extend_complex(COMPLEX, SEEN) to be: + let CHOICES be an empty list of lists of complex selectors + for each compound selector COMPOUND in COMPLEX: + let EXTENDED be extend_compound(COMPOUND, SEEN) + if no complex selector in EXTENDED is a superselector of COMPOUND: + add a complex selector composed only of COMPOUND to EXTENDED + add EXTENDED to CHOICES + + let WEAVES be an empty list of selector lists + for each list of complex selectors PATH in paths(CHOICES): + add weave(PATH) to WEAVES + return trim(WEAVES) + +define extend_compound(COMPOUND, SEEN) to be: + let RESULTS be an empty list of complex selectors + for each (EXTENDER, TARGET) in MAP.get(COMPOUND): + if SEEN contains TARGET, move to the next iteration + + let COMPOUND_WITHOUT_TARGET be COMPOUND without any of the simple selectors in TARGET + let EXTENDER_COMPOUND be the last compound selector in EXTENDER + let UNIFIED be unify(EXTENDER_COMPOUND, COMPOUND_WITHOUT_TARGET) + if UNIFIED is null, move to the next iteration + + let UNIFIED_COMPLEX be EXTENDER with the last compound selector replaced with UNIFIED + with TARGET in SEEN: + add each complex selector in extend_complex(UNIFIED_COMPLEX, SEEN) to RESULTS + return RESULTS + +for each selector COMPLEX in the document: + let SEEN be an empty set of compound selectors + let LIST be a selector list comprised of the complex selectors in extend_complex(COMPLEX, SEEN) + replace COMPLEX with LIST +``` + +A keen reader will have noticed an undefined function used in this pseudocode: +`weave`. `weave` is much more complicated than the other primitive operations, +so I wanted to explain it in detail. + +### Weave + +At a high level, the "weave" operation is pretty easy to understand. It's best +to think of it as expanding a "parenthesized selector". Imagine you could write +`.foo (.bar a)` and it would match every `a` element that has both a `.foo` +parent element *and* a `.bar` parent element. `weave` makes this happen. + +In order to match this `a` element, you need to expand `.foo (.bar a)` into the +following selector list: `.foo .bar a, .foo.bar a, .bar .foo a`. This matches +all possible ways that `a` could have both a `.foo` parent and a `.bar` parent. +However, `weave` does not in fact emit `.foo.bar a`; including merged selectors +like it would cause exponential output size and provide very little utility. + +This parenthesized selector is passed in to `weave` as a list of complex +selectors. For example, `.foo (.bar a)` would be passed in as `[.foo, .bar a]`. +Similarly, `(.foo div) (.bar a) (.baz h1 span)` would be passed in as `[.foo +div, .bar a, .baz h1 span]`. + +`weave` works by moving left-to-right through the parenthesized selector, +building up a list of all possible prefixes and adding to this list as each +parenthesized component is encountered. Here's the pseudocode: + +``` +let PAREN_SELECTOR be the argument to weave(), a list of complex selectors +let PREFIXES be an empty list of complex selectors + +for each complex selector COMPLEX in PAREN_SELECTOR: + if PREFIXES is empty: + add COMPLEX to PREFIXES + move to the next iteration + + let COMPLEX_SUFFIX be the final compound selector in COMPLEX + let COMPLEX_PREFIX be COMPLEX without COMPLEX_SUFFIX + let NEW_PREFIXES be an empty list of complex selectors + for each complex selector PREFIX in PREFIXES: + let WOVEN be subweave(PREFIX, COMPLEX_PREFIX) + if WOVEN is null, move to the next iteration + for each complex selector WOVEN_COMPLEX in WOVEN: + append COMPLEX_SUFFIX to WOVEN_COMPLEX + add WOVEN_COMPLEX to NEW_PREFIXES + let PREFIXES be NEW_PREFIXES + +return PREFIXES +``` + +This includes yet another undefined function, `subweave`, which contains most of +the logic of weaving together selectors. It's one of the most complicated pieces +of logic in the entire `@extend` algorithm -- it handles selector combinators, +superselectors, subject selectors, and more. However, the semantics are +extremely simple, and writing a baseline version of it is very easy. + +Where `weave` weaves together many complex selectors, `subweave` just weaves +two. The complex selectors it weaves together are considered to have an implicit +identical trailing compound selector; for example, if it's passed `.foo .bar` +and `.x .y .z`, it weaves them together as though they were `.foo .bar E` and +`.x .y .z E`. In addition, it doesn't merge the two selectors in most cases, so +it would just return `.foo .bar .x .y .z, .x .y .z .foo .bar` in this case. An +extremely naive implementation could just return the two orderings of the two +arguments and be correct a majority of the time. + +Delving into the full complexity of `subweave` is out of scope here, since it +falls almost entirely into the category of advanced functionality that this +document is intentionally avoiding. The code for it is located in +[`lib/sass/selector/sequence.rb`](https://github.com/sass/ruby-sass/blob/master/lib/sass/selector/sequence.rb) +and should be consulted when attempting a serious implementation. diff --git a/source/blog/002-a-change-in-plans-for-sass-33.html.md b/source/blog/002-a-change-in-plans-for-sass-33.html.md new file mode 100644 index 000000000..12ff26e3d --- /dev/null +++ b/source/blog/002-a-change-in-plans-for-sass-33.html.md @@ -0,0 +1,123 @@ +--- +title: A Change in Plans for Sass 3.3 +author: Natalie Weizenbaum +date: 2013-12-19 20:05 PST +--- + +_This was originally published as [a gist](https://gist.github.com/nex3/8050187)._ + +Sass 3.3 is coming soon, and along with it several major new features. It +supports source maps, SassScript maps, and the use of `&` in SassScript. In +preparation for its release, we've put out a couple of release candidates to be +sure that everything was set and ready to go. Unfortunately, it wasn't. + +Release candidates often turn up small bugs and inconsistencies in new features, +but it's rare that they find anything truly damning. In this case, though, +several users noticed an issue with using `&` in SassScript that rendered a +sizable chunk of our plan for that section of 3.3 unworkable. It's not a fatal +issue, and we think we have a good plan for dealing with it (I'll get to that in +a bit), but it is a problem. + +## The Background + +To understand what's wrong, first you need to understand the reason we decided +to make `&` accessible to SassScript in the first place. One thing users want to +do pretty often is to add suffixes to classes. Sometimes this takes the place of +nesting selectors, sometimes it's just to make a new class based on the old ones +-- the reason doesn't matter much to this discussion. When people tried to do +this, they'd write something like `.foo { &-suffix { ... } }`, and it wouldn't +work. The reason is that `&` has the same syntactic function as a type selector +(e.g. `h1`) or a universal selector (`*`), since it could be replaced by any of +those. It doesn't make sense to write `*-suffix` in a selector, so `&-suffix` +wasn't allowed either. + +This didn't stop people from wanting to do it, though. So we decided, "all +right, we already use interpolation (`#{}`) to support injecting text into +selectors -- let's just use that". We decided to add `&` as a sort of special +variable in SassScript that contained a parsed representation of the current +selector. You could then mimic `&-suffix` by doing `@at-root #{&}-suffix` +instead[^1]. Life was peachy, until our intrepid users discovered the problem. + +## The Problem + +Here's a small snippet of SCSS that demonstrates the issue. See if you can +figure it out: + +```scss +.foo, .bar { + @at-root #{&}-suffix { + color: blue; + } +} +``` + +Did you get it? That's right: `&` in this example is `.foo, .bar`, which means +the selector compiles to `.foo, .bar-suffix`. Since `#{}` injects plain old +text, there's no chance for Sass to figure out how it should split up the +selector. + +[Chris](https://github.com/chriseppstein) and I talked and talked about how to +fix this. We considered adding a function to add the suffix, but that was too +verbose. We considered making `&` split the compilation of the CSS rule into +several parallel rules which each had a single selector for `&`, but that was +too complicated and fell down in too many edge cases. We eventually concluded +that there was no way for SassScript `&` to cleanly support the use case we +designed it for. + +## The Solution + +We knew we wanted to support the `&-suffix` use case, and our clever plan for +doing so had failed. We put our heads together and discussed, and decided that +the best way to support it was the most straightforward: we'd just allow +`&-suffix`. This was, after all, what most people tried first when they wanted +this behavior, and with the `&` embedded directly in the selector, we can handle +selector lists easily. + +This means that **`&-suffix` will be supported in Sass 3.3**, without needing +`#{}` or `@at-root`. I've created [issue +1055](https://github.com/nex3/sass/issues/1055) to track it. When compiling +these selectors, if the parent selector is one that would result in an invalid +selector (e.g. `*-suffix` or `:nth-child(1)-suffix`), we'll throw an error there +describing why that selector was generated. + +We are still worried about cases where people write mixins using `&-suffix` that +will then fail to work with certain parent selectors, but in this case we +determined that this would be the least of all available evils. + +## The Future of `&` in SassScript + +In addition to supporting `&-suffix`, **we've decided to pull SassScript `&` +from the 3.3 release**. Rest assured that it will return -- we recognize that it +has other good use cases, and we intend to bring it back for the next big +release (likely 3.4). In addition, it will come with a suite of functions for +manipulating the selectors it makes available, so it will be more powerful than +ever. + +There are two reasons that we want to hold off on using `&` in SassScript for +now. The first is that we want some time to create the functions that will go +along with it and put them through their paces. This may require changing the +way it works in various ways, and we don't want to have to make +backwards-incompatible changes to do so. + +The second reason is that we've spent a fair amount of energy talking up `#{&}` +as a solution to the `&-suffix` problem. This is our own fault, clearly, but +it's true and it's something we need to deal with. Making `&-suffix` work is +great, but if everyone is using `#{&}` anyway because that's what we told them +about a few months ago, then it's not doing everything it can. Having a release +where `&-suffix` works but `#{&}` doesn't will help guide users towards the best +way to solve their problem, before we make the more advanced functionality +available. + +`@at-root` will still be included in Sass 3.3. + +## Releasing 3.3 + +Unfortunately, this change will delay the release of 3.3, but hopefully not by +too much. I anticipate this being relatively straightforward to implement; the +major hurdle was figuring out what to do about it, and that part's done. I plan +to devote a large chunk of time to getting 3.3 out the door after I come back +from winter vacation, so hopefully (no promises) it'll be released some time in +January. + +[^1]: The `@at-root` is necessary since Sass can't reliably figure out whether + `&` was used in the selector like it can when `&` is used without `#{}`. diff --git a/source/blog/003-sass-33-is-released.html.md b/source/blog/003-sass-33-is-released.html.md new file mode 100644 index 000000000..83e609a08 --- /dev/null +++ b/source/blog/003-sass-33-is-released.html.md @@ -0,0 +1,158 @@ +--- +title: Sass 3.3 is Released +author: Natalie Weizenbaum +date: 2014-03-07 16:40 PST +--- + +After ironing out a bunch of bugs in numerous release candidates, we're finally +ready to release Sass 3.3.0, codename Maptastic Maple, for public consumption. +This release has a lot of exciting new features that you can read about in full +in [the changelog](/documentation/file.SASS_CHANGELOG.html), but there are three +that I want to draw your attention to in particular. + +# Maps in SassScript + +As language designers, most of our job is to listen to feedback from users and +act upon it. This is tricker than it sounds: users are very good at knowing the +precise thing that they want to accomplish, but they tend not to have a sense of +how that fits into the big picture. So we take a large volume of user requests, +try to distill the core needs that aren't being met, and see if we can come up +with features that hit as many of those as possible as simply as possible. + +SassScript maps are a great example of this. We had a lot of users requesting +things like variable interpolation, so they could write things like +`$#{$theme-name}-background-color`. Other users wanted built-in functions that +worked with lists of pairs, or a way to get the name of a variable that was +passed to a function. We eventually realized the underlying feature that people +actually wanted: a way to associate values with names. + +Most programming languages have a notion of maps[^1], which are associations +from "key" objects to "value" objects. Sass 3.3 adds support for these as a +first-class data structure. The syntax is designed to be very similar to that +used for `@media` queries. They look like this: + +```scss +$map: (key1: value1, key2: value2, key3: value3); +``` + +Unlike lists, maps must always be surrounded by parentheses. `()`, which +previously referred to an empty list, now _also_ refers to an empty map; both +list and map operations will work on it. + +Maps can't be used as CSS values, since they aren't valid CSS syntax. However, +there are a number of [new built-in +functions](/documentation/Sass/Script/Functions.html#map_functions) that allow +user-defined mixins and functions to use them. Here are a few particularly +useful ones: + +* `map-get($map, $key)` looks up a value in a map using its key. For example, + using the example above, `map-get($map, key2)` would return `value2`. + +* `map-merge($map1, $map2)` merges two maps together. The keys in `$map2` + overwrite those in `$map1`, so this is also a good way to add values to a map. + For example, `map-merge($map, (key1: new-value))` would return `(key1: + new-value, key2: value2, key3: value3)`. + +* `map-remove($map, $key)` removes a value in a map. For example, + `map-remove($map, $key)` would return `(key: value2, key3: value3)`. + +In addition to the new map functions, all the existing list functions also work +on maps. The list functions will see each map as a list of pairs. For example, +`nth($map, 1)` will return `(key1 value1)`. Not only that, but `@each` has new +syntax for working with both maps and lists of pairs. For example: + +```scss +@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) { + #{$header} { + font-size: $size; + } +} +``` + +produces: + +```css +h1 { + font-size: 2em; +} + +h2 { + font-size: 1.5em; +} + +h3 { + font-size: 1.2em; +} +``` + +# Source Maps + +Continuing the map theme, Sass 3.3 comes with support for generating source maps +when compiling to CSS. Source maps are a standard format for telling browsers +how files they consume got generated. For Sass, this means that browsers' +development tools can now tell you exactly which line of your Sass source file +each style rule came from. Currently this is only well-supported in Chrome, but +hopefully other browsers will add support soon. + +When compiling Sass from the command line, all you need to do to generate source +maps is pass the `--sourcemap` flag. Sass will automatically generate a +`.css.map` file next to the generated `.css` file. All you have to do then is +make sure your `.scss` or `.sass` file is visible to the browser, and you'll be +good to go. + +# More Flexible `&` + +When we released Sass 3.0, we added support for SCSS, which meant we had to +actually parse all the selectors in the document. This meant that you couldn't +just plop the parent selector, `&`, anywhere in a selector. Overall this was an +improvement: it caught more errors and encouraged users to write more flexible +mixins. + +Unfortunately, it also made one important use-case harder. With the rise in +popularity of [BEM](http://gembem.com/), [OOCSS](http://oocss.org/), and +[SMACSS](http://smacss.com/), people became more and more interested in adding +suffixes to classes. When using Sass, they wanted to write mixins to do this, +and the restrictions on `&` made that very hard to do. + +In Sass 3.3, we're loosening these restrictions. You can now write `&-suffix` +(or `&_suffix`, or even `&suffix` if you really want) and Sass will make it +work. If this fails to apply—for example, if `&` is `*`—Sass will +print a helpful error message. + +# Deprecation: Variable Scope and `!global` + +We don't always get everything right the first time, and in order to make Sass +the best language it can be we occasionally have to change old behavior. +Sometimes this happens in ways that might make existing stylesheets stop +functioning, so we have a policy of printing warnings for stylesheets that are +going to change in the future. + +Sass 3.3 adds a number of deprecations, but the biggest one by far has to do +with the way variable scope works. Up until now, when you wrote `$var: value` in +a function, mixin, or CSS rule in Sass, it could do one of two things. If there +was a global variable named `$var`, it would overwrite that variable. Otherwise, +it would create a local variable that was only visible within the current set of +curly braces. + +This was a pretty big problem, since any given variable assignment could +potentially be modifying a variable that it had no way of knowing existed. We +want to migrate to a better system where assigning to a variable in a local +scope won't overwrite a global variable unless the assignment explicitly says to +do so, as in `$var: value !global`. + +In order to avoid breaking existing stylesheets, we haven't made this change +yet. Instead, if a global variable is overwritten by a local declaration, we now +print a deprecation warning suggesting that the user add `!global`. Right now, +`!global` doesn't do much other than make the warning go away, but in a future +release it will work as I described above. + +# That's All + +Actually, there's a lot more, but that's all I have room for in this post. If +you want to see the full assortment of new features, check out [the +changelog](/documentation/file.SASS_CHANGELOG.html#330_7_March_2014). You can +also play with the new features on [SassMeister](http://sassmeister.com/) or on +your own computer by running `gem update sass`. Enjoy! + +[^1]: Some languages call them "hashes", "dictionaries", or "associative + arrays". JavaScript calls them "objects" for weird historical reasons. diff --git a/source/blog/004-sass-34-is-released.html.md b/source/blog/004-sass-34-is-released.html.md new file mode 100644 index 000000000..c30a49a8c --- /dev/null +++ b/source/blog/004-sass-34-is-released.html.md @@ -0,0 +1,90 @@ +--- +title: Sass 3.4 is Released +author: Natalie Weizenbaum +date: 2014-08-18 16:38 PST +--- + +We've been trying to increase the pace of Sass releases, and it looks like we've +succeeded. A mere five months after the release of [Sass +3.3](/blog/sass-33-is-released), we're announcing the release of Sass 3.4.0, +codename Selective Steve. Faster releases mean fewer major features per release, +so there are only two big new things to talk about (although there are plenty of +little improvements you can read about in [the +changelog](/documentation/file.SASS_CHANGELOG.html)). As the version name +suggests, both of these features have to do with selectors. + +# Using `&` in SassScript + +"SassScript" is what we call the mini-language Sass uses for variables, property +values, and so forth. It's mostly just CSS values, but it also supports custom +functions, arithmetic, and so forth. In Sass 3.4, we added support for something +new: the parent selector, `&`. + +Most Sass users will probably recognize `&` from its previous appearances in +selectors around the world, where it's used to explicitly refer to the parent +selector. For example, in `.parent { .child & { ... } }`, `&` refers to +`.parent`, and this compiles to `.child .parent { ... }`. + +Now `&` works much the same way in SassScript. It refers to the same parent +selector, but instead of just being dropped in it's exposed as a list of lists +to make it easy for functions to inspect and manipulate it. For example, if you +write `.foo .bar, .baz { $selector: & }`, `$selector` will be `((".foo" ".bar"), +(".baz",))`. + +We had originally slated this feature for version 3.3, but we took it out when +we realized [it was really hard to use these selectors in a way that didn't +break when they contained commas](/blog/a-change-in-plans-for-sass-33). +Because of that, we decided to delay it for a version to give us time to come up +with its compantion feature: selector functions. + +# Selector Functions + +The problem with just exposing `&` was that the only way to use it with other +selectors was by glomming them together as strings. This works okay in simple +cases, but when you write `#{$selector} .child` and `$selector` is `.foo, .bar`, +you want `.foo .child, .bar .child` but you get `.foo, .bar .child`. This is no +good at all. + +To solve this, we added a slew of functions that use Sass's powerful built-in +selector logic to do the right thing. For example, you can now write +**`selector-nest(".foo, .bar", ".child")`** and get exactly what you want. These +functions all return the same sort of nested-list representation that `&` +uses,but they're very liberal in what they accept: anything from nested lists to +plain old strings. + +If you want to see every selector function we thought up, check out [the +changelog](/documentation/file.SASS_CHANGELOG.html). I do want to highlight a +few that I'm particularly fond of, though. You've already seen +`selector-nest()`, and **`selector-append()`** is a close relative. The +difference between them is whitespace: `selector-nest()` adds a space between +its selectors, where `selector-append()` doesn't. This means that +`selector-append(".foo, .bar", "-suffix")` returns `.foo-suffix, .bar-suffix`. + +Another function I like a lot is **`selector-replace()`**. This does a +search-and-replace of one selector within another, but it's a lot more clever +than your basic string replace. It uses Sass's `@extend` logic to replace +selectors *semantically*, as though every element matched by the replacement +selector was also matched by the replaced selector. For example, +`selector-replace(".foo.bar.baz", ".foo.baz", ".qux")` returns `.bar.qux`. + +The last really powerful function I want to draw your attention to is +**`selector-unify()`**. This takes two selectors and returns a new selector that +matches only elements that are matched by *both* input selectors. This is an +operation Sass uses a lot internally, and now users can access it as well. For +example, `selector-unify(".foo.bar", ".bar.baz")` will return `.foo.bar.baz`. + +# What's Next? + +I won't rule out the possibility of Sass 3.5 existing, but +[Chris](https://twitter.com/chriseppstein) and I plan to focus pretty hard on +Sass 4.0. The big feature for 4.0 is going to be `@import`, or rather the lack +thereof. Our current import system is beginning to show its age in a major way, +and we intend to replace it wholesale, up to and including the name. As of 4.0, +the recommended way of pulling in other Sass files will be `@use`. + +Among the features we're planning for `@use` are two that have been widely +requested. You'll be able to import CSS stylesheets directly into your Sass +ones, and each stylesheet will only be run once, no matter how many times it's +imported. + +Until then, though, run `gem update sass` and enjoy Selective Steve! diff --git a/source/blog/005-cleaning-up-interpolation.html.md b/source/blog/005-cleaning-up-interpolation.html.md new file mode 100644 index 000000000..1e2404d05 --- /dev/null +++ b/source/blog/005-cleaning-up-interpolation.html.md @@ -0,0 +1,153 @@ +--- +title: Cleaning Up Interpolation +author: Natalie Weizenbaum +date: 2015-12-09 15:20 PST +--- + +Interpolation—the ability to add variables and other snippets using `#{...}`—is +one of the handiest all-purpose features of Sass. You can use it just about +everywhere you might need to inject a variable, a function call, or some other +expression. In most of those places it just plops the value into the surrounding +text. It's straightforward, easy to understand, and useful, which is exactly +what we want from a feature. + +Unfortunately, that's only true in *most places*. For complicated historical +reasons, there's one place where interpolation goes a little bit bananas: inside +an expression but outside quotes. Most of the time, it makes sense; if you write +`display: -#{$prefix}-box`, you'll get what you expect. But if any operators +like `+` are used next to the interpolation, you start to get weird output. For +example, `$name + #{$counter + 1}` might return an unquoted string containing +the text `name + 3`. + +This is really weird behavior. Why does `+` behave differently here than it does +everywhere else? Why is it treated as plain text when `$name` gets evaluated +normally? This behavior is confusing, inconsistent, and not particularly useful, +which are very much *not* things we want in a feature. So why do they exist in +the first place? + +## Complicated Historical Reasons + +*If you don't care for a history lesson, skip on down to [A Brave New +World](#a-brave-new-world).* + +Way back in the dawn of time, when the indented syntax was the only syntax, Sass +had a distinction between "static" and "dynamic" properties. A static property +was basically plain CSS; it was declared using `property: value`, and the value +was used as-is without any further processing. If you wanted to use a variable +or a function, you had to use a dynamic property, which was declared using +`property= value`. A You'd see a lot of stylesheets like this: + +```sass +.border + border-width: 4px + border-style: solid + border-color= !background_color +``` + +Also, in the dawn of time, variables used `!` instead of `$` and couldn't +include hyphens. The dawn of time kind of sucked. But it was in this context +that we first added interpolation. We wanted to allow properties like `border` +with multiple values to be partially dynamic, so we decided to follow in Ruby's +footsteps and allow `#{}` to be used to drop in values. Soon stylesheets started +looking like this: + +```sass +.border + border: 4px solid #{!background_color} +``` + +That's so much better! And for a while, all was calm. + +### Then Came SCSS + +It eventually became clear that users really strongly wanted their stylesheets +to look like CSS, so we sat down and started work on the syntax that would +become SCSS in the release that would become Sass 3. As part of this work, we +decided to get rid of the distinction between static and dynamic properties +altogether. Having all properties work the same way was obviously great for +users, but it meant we had to figure out how to merge the two syntaxes with a +minimum of pain. + +This was mostly straightforward, since the old expression syntax was pretty much +universally invalid CSS or something that emitted its CSS value anyway. But +interpolation proved tricky. Backwards compatibility is really important to us, +so we wanted to be sure that all the places interpolation was used—or *could +theoretically be used*—in Sass 2 would continue to work in Sass 3, even though +everything around them was now fully parsed. + +Our solution was to make basically anything around `#{}` that wasn't obviously +part of a plain-CSS expression turn into a string. That way, hopefully any weird +corner cases that people had would keep working when they upgraded. This led to +the weird behavior I described above, but at the time our top priority was +making it as easy as possible for users to migrate to Sass 3. We decided the +weirdness was worth it, and shipped it. + +## A Brave New World + +Flash forward to today. We're now starting work on the next major release, Sass +4, and (I dearly hope) no one's written any Sass 2 stylesheets in years. A major +release is a great opportunity to clean up this bit of historical cruft, and +after [discussing it extensively on the issue +tracker](https://github.com/sass/sass/issues/1778) we decided to make the +change. + +There are three major steps in a backwards-incompatible change like this. The +first is to design the new syntax, which was pretty easy here, since it's +basically just "do what everyone thought it did already." We just had to take +that general notion and suss out the specifics. + +We ended up framing it as `#{}` being, syntactically, part of an identifier. +When you write `-#{$prefix}-box`, Sass parses it as a single identifier +containing `"-"` followed by the value of `$prefix` followed by `"-box"`. Even +if you write `#{$font}` all on its own, it's parsed as an identifier that only +contains the value of `$font`. This way, interpolation doesn't have weird +behavior around operators any more than identifiers ever did. + +Once we had a design, the second step was to deprecate the old behavior. The +meat of deprecation is figuring out when to print a warning, and that was pretty +tough here. We didn't want to warn for situations that would continue to work, +even when they involved operators—for example, `12px/#{$line-height}` will print +the right thing in the old and new worlds (although for slightly different +reasons), but `12px+#{$line-height}` won't. + +I won't go into the gory details of how we got deprecation working here; that's +what the [GitHub issue](https://github.com/sass/sass/issues/1778) is for. +Suffice it to say that it involved a lot of special cases, including some where +a deprecation warning can be printed based on how a value is *used* rather than +how it's *written*. I'm pretty happy with where it ended up, though; I suspect +it'll catch 99% of cases that will actually break in practice. + +Another exciting bonus was the ability to automatically update code. This +doesn't always work when introducing backwards-incompatibilities, but in this +case we were able to make `sass-convert` convert deprecated uses of +interpolation into Sass 4-compatible code. It has some false negatives—it only +converts cases it can prove will be incompatible—but it's enough to get users a +long way there. + +The final step once the deprecation was in place was to move to [the `master` +branch](https://github.com/sass/sass/commits/master) (which will eventually +become Sass 4), rip out all the old behavior, and implement the new. And it was +*wonderful*. Deleting gross code and replacing it with something clean feels +like taking a shower after spending a day hiking through dust under a hot sun. +And after working on this feature for weeks, I was happy to see the other end of +it. + +## Checking it Out + +Sass 3.4.20, released today, was the first release to include the deprecation +warnings for the old syntax. If you want to check whether you've got any +deprecated interpolations lurking in your stylesheets, just `gem install sass` +and recompile your stylesheet. And if you do find some, try running +`sass-convert --recursive --in-place .` to fix a bunch automatically. + +If you want to try out the new syntax, 4.0.0.alpha.1 was also released today. +You can get it with `gem install sass --prerelease`. But beware: it is alpha +software, so it may change in the future. We generally try to keep even our +prereleases pretty stable, but there's also a chance you'll run into a bug. + +If you do find a bug, please file it on [the issue +tracker](https://github.com/sass/sass/issues). Even if it's something as simple +as a typo, we want to know. If we've deprecated something that should be valid, +we *especially* want to know. And if you just have a question, feel free to +tweet at [@SassCSS](https://twitter.com/SassCSS) or post it on the [mailing +list](https://groups.google.com/forum/#!forum/sass-lang). diff --git a/source/blog/006-dropping-support-for-old-ruby-versions.html.md b/source/blog/006-dropping-support-for-old-ruby-versions.html.md new file mode 100644 index 000000000..114b6bbfb --- /dev/null +++ b/source/blog/006-dropping-support-for-old-ruby-versions.html.md @@ -0,0 +1,59 @@ +--- +title: Dropping Support For Old Ruby Versions +author: Natalie Weizenbaum +date: 2016-02-29 14:25 PST +--- + +As of version 3.5, Ruby Sass will drop support for Ruby 1.8.7 and Ruby 1.9.3. We +will continue to support Ruby 2.0.0 and higher. + +Ruby 1.8.7 was retired by the Ruby maintainers in [June +2013](https://www.ruby-lang.org/en/news/2013/06/30/we-retire-1-8-7/), and Ruby +1.9.3 was retired in [February +2015](https://www.ruby-lang.org/en/news/2015/02/23/support-for-ruby-1-9-3-has-ended/). +Despite that, we continued to maintain support for older versions because Ruby +1.8.7 was installed by default on Mac OS X through Mountain Lion (which was +released in July 2012). + +There are many users of Sass who aren't independently users of Ruby. We wanted +to minimize the amount of work these users need to do to use Sass, which means +letting it run on their machine without also requiring them to install a new +language. + +That decision wasn't without costs, though. Most seriously, recent versions of +the [listen package](https://github.com/guard/listen) didn't support older Ruby +versions, and older versions of RubyGems weren't clever enough to avoid +downloading them on incompatible Ruby versions. To work around this, we bundled +an older version of `listen` with Sass and used it for users who didn't have a +compatible version installed elsewhere, but this produced constant compatibility +headaches. + +These headaches led us to reevaluate our policy for supporting older Ruby +versions. We still cared a lot about users' built-in Ruby versions, but we +couldn't support them forever. We needed a way to determine when the benefit of +dropping support outweighed the costs. + +We decided to use the analytics data for sass-lang.com to approximate the +proportion of our user base that was still using operating systems that shipped +with old Ruby versions. Before we looked at the data, we decided that we would +drop support for a Ruby version if it had been retired by the Ruby maintainers, +*and* less than 2% of our visitors across the previous month were using an OS +that shipped it by default. + +Once we did that, we looked at the data. 34.3% of our visitors were using OS X, +and 1.4% of OS X users were using Mountain Lion or earlier. We were clearly able +to drop support for 1.8.7. In addition, 1.9.3 was never shipped with OS X so we +were able to drop it as well. Ruby 2.0.0, despite retired [last +week](https://www.ruby-lang.org/en/news/2016/02/24/support-plan-of-ruby-2-0-0-and-2-1/), +was shipped with the most recent OS X version—we won't be dropping support for +it any time soon. + +sass-lang.com visitors by operating system + +For Sass 3.4, we're just planning on printing deprecation messages for users of +deprecated Ruby versions. But once 3.5 releases, support will be fully dropped +and we'll switch to using `listen` as a proper gem dependency. If you're on an +older version of OS X and you haven't upgraded your Ruby version, there are some +simple instructions [on the Ruby +site](https://www.ruby-lang.org/en/documentation/installation/#homebrew) for how +to do so easily using Homebrew. diff --git a/source/blog/007-thank-you-marcel.html.md b/source/blog/007-thank-you-marcel.html.md new file mode 100644 index 000000000..40fdf4c3c --- /dev/null +++ b/source/blog/007-thank-you-marcel.html.md @@ -0,0 +1,31 @@ +--- +title: Dropping Support For Old Ruby Versions +author: Natalie Weizenbaum +date: 2016-05-24 14:41 PST +--- + +You may not know [Marcel Greter](https://github.com/mgreter), but you almost +certainly know his work. For more than two years, he has been the #1 contributor +on LibSass and is the #2 contributor for the history of the project. His +monumental efforts, together with [Michael Mifsud](https://github.com/xzyfer), +are what has kept LibSass thriving recently and why it has reached feature +parity with Ruby Sass and is now used by more users than Ruby Sass every day. + +Presently, as we are pivoting to a new development model and release cadence, +Marcel has decided it is the best time for him to exit the LibSass core team. We +are truly sad to see him go, but we wish him well in all his new endeavors. +Please join us in thanking him for all his hard work. You can follow and tweet +him [@mgreter](https://twitter.com/mgreter). + +--- + +Unfortunately, this leaves the LibSass project with some big shoes to fill. +LibSass is a popular project that has more than 1.5 Million downloads a month +and as of right now, it is in desparate need of new contributors. + +We have a bunch of new features planned for Sass 3.5 that need to be implemented +in LibSass and we want to do a coordinated release of both Ruby Sass and LibSass +as soon as we can. If you can write production quality C++ and want to build +parsers and compilers, we would love to help you become a contributor. If you +don't have free time, but still want to contribute, consider asking your +workplace to support the project by donating a percentage of your time. diff --git a/source/blog/008-sass-35-release-candidate.html.md b/source/blog/008-sass-35-release-candidate.html.md new file mode 100644 index 000000000..ccee5c2ec --- /dev/null +++ b/source/blog/008-sass-35-release-candidate.html.md @@ -0,0 +1,155 @@ +--- +title: Sass 3.5 Release Candidate +author: Natalie Weizenbaum +date: 2016-08-30 15:00 PST +--- + +I've just pushed the button to release Sass 3.5.0-rc.1. If it seems like it's +been a while since the last release, that's true! But there's a good reason. We +decided to enter feature freeze after the 3.5 release to give +[libsass](/libsass), the super-speedy C++ implementation of Sass, time to reach +feature parity with Sass 3.4. Libsass is much younger than Sass, and C++ is +generally a slower language to work in than Ruby, so this took some time. But it +paid off: libsass is now almost 100% compatible with Ruby Sass, differing only +in a few small bugs. + +After the feature freeze lifted, we were primarily focused on designing the new +module system that will be the central feature of Sass 4.0. But we also found +some time to add some new features, which are the focus of this release. + + +## CSS Custom Property Support + +Sass 3.5 now fully supports [CSS custom +properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables). +These posed a particular challenge for us, since the custom property syntax is +*extremely* broad. You can put just about anything on the right-hand side. For +example, this is totally valid, meaningful CSS: + +```css +.wacky-property { + --property: .%(#@$~`^[^_+]<;:"}"|?)*+ +} +``` + +In particular, this means that SassScript expressions are *also* valid CSS, +which poses a problem for our goal of CSS compatibility. Wherever possible, we +want valid CSS to mean the same thing in Sass as it does in CSS. So treating +custom properties just like normal properties—which we did in 3.4—wasn't a good +solution. Not only was some valid CSS interpreted differently, some of it wasn't +even possible. The following CSS, taken straight from the Polymer docs, was next +to impossible to represent in Sass: + +```css +:host { + --my-toolbar-theme: { + background-color: green; + border-radius: 4px; + border: 1px solid gray; + }; +} +``` + +On the other hand, we needed *some* way of including dynamic SassScript values +in custom properties. So we decided on a compromise: we'd treat custom +properties like we do selectors and at-rule values, and only allow `#{}` as a +means of including Sass values. While technically this is plain CSS, it's a very +small surface area and it's very easy to escape, so we're not too worried. This +means that in 3.5 you can write: + +```scss +:host { + --my-toolbar-theme: { + background-color: #{$toolbar-background}; + border-radius: 4px; + border: 1px solid gray; + }; +} +``` + +## New Data Type: First-Class Functions + +In preparation for the module system that's coming in Sass 4.0, 3.5 adds a new +data type: first-class functions. This is just a way of referring to a function +that's more specific than just its name. You can get a first-class function by +passing its name to `get-function($name)`, and you can pass it to `call()` where +you used to pass the function name. + +You might be wondering, "Why is this useful? I could already just pass the +function name." Well, right now, Sass has global scope. All functions (as well +as variables, mixins, and selectors) are visible to any code that's executing +later on. This makes some things, like `call()`, simple, but it also causes a +lot of problems. It's way too easy to accidentally overwrite a variable or +function that was defined elsewhere, and it's way too hard to figure out where +any given name was originally defined. + +We aren't quite ready to talk widely about our plans for the 4.0 module system, +but one of the things we're sure of is that it won't use global scope. Each Sass +file will only be able to see a limited number of the names that have been +defined, and Sass libraries in particular won't be able to see anything defined +by the end-user stylesheets that import them. First-class functions allow users +to pass functions they define to libraries. + +Any stylesheets that are currently passing around function names as strings +should switch to passing first-class functions instead. To this end, calling +`call()` with a string has been deprecated. It won't actually break until 4.0, +when it won't be much use anyway, but we strongly encourage users to switch to +`get-function()` immediately. + +## New Syntax: Bracketed Lists + +The new [CSS Grid +Layout](https://css-tricks.com/snippets/css/complete-guide-grid/) module added a +new type of syntax: identifiers surrounded by square brackets. We're always +striving to be totally compatible with CSS, which meant we needed to support +these brackets as well. Here's what they look like in CSS: + +```css +.container { + grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end]; + grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line]; +} +``` + +The solution was clear: Sass already has a [list data +type](/documentation/file.SASS_REFERENCE.html#lists), so we'd just allow lists +to have square brackets. So `[first]` is just a list containing the unquoted +string `first`. Like all Sass lists, bracketed lists can either be +space-separated or comma-separated: `[foo bar baz]` and `[foo, bar, baz]` are +both lists containing three elements. + +We've also added function support for bracketed lists. The `is-bracketed($list)` +function returns whether a list is bracketed or not, and `join()` has a new +`$bracketed` parameter that allows the caller to choose whether or not the +resulting list will have brackets (by default, the result is bracketed if the +first list is). + +## Smaller Features + +We've added a `content-exists()` function that returns whether or not a content +block was passed to the current mixin. This allows mixins to optionally take a +content block, rather than having to define one mixin that takes content and one +that does not. + +We've added the ability to add a trailing comma to argument lists. This matches +the behavior of lists and maps. + +We've added a `$weight` parameter to the `invert()` function. This is a +percentage between 0% and 100% that indicates how inverted the resulting color +should be. It defaults to 100%. + +## The Road to Release + +This is just a release candidate, but it's in a place that we'd be happy +shipping it as the final release. We're not doing so because, now that we've +reached feature compatibility with libsass, we're committed to staying there. + +Unfortunately, since [Marcel Greter moved on from the +project](/blog/thank-you-marcel), libsass has been moving pretty slowly lately. +If you or anyone you know would be interested in working on a project that would +benefit thousands of people, we're still looking for new contributors! + +Until we have libsass compatibility, 3.5 will stay at a release candidate level. +But don't let that stop you from trying it out and letting us know what you +think! We're always interested in hearing feedback on [the mailing +list](https://groups.google.com/forum/#!forum/sass-lang)! diff --git a/source/blog/009-announcing-dart-sass.html.md b/source/blog/009-announcing-dart-sass.html.md new file mode 100644 index 000000000..fb23d4212 --- /dev/null +++ b/source/blog/009-announcing-dart-sass.html.md @@ -0,0 +1,175 @@ +--- +title: Announcing Dart Sass +author: Natalie Weizenbaum +date: 2016-10-31 13:28 PST +--- + +Over the past few months, I've been quietly working on a new project. Today I'm +ready to announce [Dart Sass](https://github.com/sass/dart-sass) to the world. +It's a totally new implementation of Sass, designed to be fast, easy to install, +and easy to hack on. It's not yet complete—I'm steadily working my way through +[sass-spec](https://github.com/sass/sass-spec)—so today I'm just releasing +version 1.0.0-alpha.1. But it's solid enough for you to download, play with, and +[start filing issues](https://github.com/sass/dart-sass/issues). + +You can download a standalone archive [from the release +page](https://github.com/sass/dart-sass/releases/tag/1.0.0-alpha.1)—just extract +it, add the folder to your path, and run `dart-sass`. Dart also compiles to +JavaScript, so if you have [npm](https://www.npmjs.com/) installed you can +install the JS version by running `npm install -g dart-sass`. And, if you happen +to be a Dart user yourself, you can install it using `pub global install sass`. + +## Why Rewrite Sass? + +Over the past few years, there have been two primary implementations of Sass. +[Ruby Sass](https://github.com/sass/sass) was the original, written mostly by me +with substantial help from [Chris](https://twitter.com/chriseppstein). It's +high-level and easy to hack on, so it's where we iterate on new features and +where they first get released. Then there's +[LibSass](https://github.com/sass/libsass), the C++ implementation, originally +created by [Aaron](https://github.com/akhleung) and +[Hampton](https://github.com/hcatlin) and now maintained by +[Marcel](https://github.com/mgreter) and [Michael](https://github.com/xzyfer). +It's low-level, which makes it very fast and easy to install and embed in other +languages. In particular, its [Node.js +bindings](https://github.com/sass/node-sass) are a very popular way to use Sass +in the JavaScript world. + +Each implementation's strengths complement the other's weaknesses. Where LibSass +is fast and portable, Ruby Sass is slow and difficult for non-Ruby-users to +install. Where Ruby Sass is easy to iterate on, LibSass's low-level language +makes it substantially harder to add new features. A complementary relationship +can be healthy, but it can also mean that neither solution is as good as it +needs to be. That's what we found when, in May, [Marcel officially left the +LibSass team](http://blog.sass-lang.com/posts/734390-thank-you-marcel)[^1]. + +[^1]: I say "officially" because he's still contributing to the project when he + can, just not in an official maintainer capacity. + +Without two people's worth of effort, we were no longer sure that LibSass could +keep pace with the speed Chris and I wanted to introduce changes into the +language. And it had been clear for a long time that Ruby Sass was far too slow +for use cases involving large stylesheets. We needed a new implementation, one +that could generate CSS quickly *and* add new features quickly. + +## Why Dart? + +We considered a number of possible languages, and ended up deciding on Dart for +a number of reasons. First, it's *really fast*—the Dart VM is generally much +faster than JavaScript VMs, and [early +benchmarks](https://github.com/sass/dart-sass/blob/master/perf.md)[^2] indicate +that, for large stylesheets, Dart Sass is 5-10x faster than Ruby Sass and only +about 1.5x slower than LibSass. I'll hazard a guess that it would be about +1.5-2x faster than an idiomatic JS implementation, but I can't say for sure. And +Dart's performance continues to get better all the time. + +[^2]: Caveats apply: I'm not a benchmarking expert, and these tests were *ad + hoc* and run against non-representative source stylesheets. If anyone is + interested in working on more scientific benchmarks, please let me know! + +At the same time, Dart is easy to work with—much more so than C++, and to some +extent even more than Ruby for such a large project. Granted, not as many people +are familiar with it as with JavaScript, but language implementations don't tend +to get many external contributions anyway. I'll be doing most of the work on the +new implementation, and Dart is the language that I'm personally most +comfortable with at the moment (when I'm not working on Sass, I'm on the Dart +team). Using Dart gives me a lot of extra velocity. + +Unlike Ruby or JavaScript, Dart is *statically typed*, so every value's type can +be figured out without running the code. Unlike C++, it's *garbage collected*, +so we don't have to worry as much about cleaning up after ourselves. This makes +it easy to write, easy to modify, and easy to maintain. Maybe even more +importantly, it makes it easy to translate to other programming languages, which +will help LibSass get new features faster. + +The last reason we chose Dart is something that only a few other languages can +boast: JavaScript compatibility. Dart can be compiled to JavaScript, which can +be used directly in Node.js or even potentially run in a browser. A huge chunk +of the Sass ecosystem built on node-sass, and we intend to make the JS version +of Dart Sass as close to API-compatible with node-sass as possible, so that it +can easily drop into existing tools and build systems. + +The only downside is that there's a speed hit: Dart Sass is about twice as slow +running on V8 as it is running on the Dart VM. However, this still puts it +solidly 3-4x faster than Ruby Sass. Ultimately we also hope to provide an easy +path for users of the JS-compiled version to move to the Dart VM version as +little friction as possible. + +## What Will Happen to The Other Implementations? + +Nothing's changing about LibSass's development. Michael's hard at work adding +features from [Sass +3.5](http://blog.sass-lang.com/posts/809572-sass-35-release-candidate), and we +expect that process to continue as new language features are added. The only +difference is that LibSass will no longer be required to be strictly compatible +with the latest version of the language in order for that version to launch, +since it will no longer be the only implementation with reasonable performance. + +More flexibility translates into faster LibSass releases that prioritize the +features users want most. Strict compatibility meant that important features +like [CSS custom property support](https://github.com/sass/libsass/issues/2076) +can't be released until all the tiny tricky edge cases that were in the +corresponding Ruby Sass release, like [`:root` +unification](https://github.com/sass/libsass/issues/2071), are implemented as +well. We'll still strive for as much compatibility as possible, but we won't let +that stand in the way of velocity. + +Ruby Sass, on the other hand, will eventually go away unless a new maintainer +appears. We don't want to make the transition sudden and risk fracturing the +ecosystem: Chris and I are committed to maintaining it for one year, which +includes keeping the language in sync with any new additions in Dart Sass. If +anyone is interested in volunteering as a maintainer after that period, we'd be +thrilled to mentor them and teach them the codebase over the coming year. But if +no one steps up, Ruby Sass will be officially considered deprecated and +unmaintained. + +I want to emphasize that we aren't making the decision to stop developing Ruby +Sass lightly. This is a big change, and it's not an easy one for me—I've worked +on Ruby Sass continuously for almost ten years now, and it's difficult to let +that history go. But Chris and I have discussed this thoroughly, and we're +convinced this is the right move. We only have so much time to devote to Sass, +and it no longer makes sense to put that time into an implementation that's so +slow as to be infeasible for many of our largest users. + +## What Next? + +Before we release the first stable version of Dart Sass, there are a few big +things on our to-do list: + +* Full sass-spec compatibility. There are still a bunch of corners of the + language where Dart Sass does the wrong thing, especially with respect to + `@extend`. I don't expect any individual incompatibility to be especially + difficult to address, and sass-spec is pretty comprehensive, so it's just a + matter of steadily reducing the number of failing specs until it hits zero. + +* Close-enough node-sass `render()` compatibility in the npm package. The + node-sass `render()` API is the main entrypoint to LibSass in the JavaScript + world. It's how build systems run Sass, how users define custom Sass + functions, and how [Eyeglass](https://github.com/sass-eyeglass/eyeglass) + passes modules to Sass. We want to support this API with enough fidelity that + the existing ecosystem works with JS-compiled Dart Sass. + +* Dart Sass compatibility in Ruby Sass. There are some cases where Dart Sass + intentionally differs from Ruby Sass, particularly when Ruby Sass's behavior + is considered a bug. We should add deprecation messages in Ruby Sass and, if + we can do so with minimal disruption, add support for the new behavior. + +There's plenty more we'd like to do eventually, like supporting Sass in the +browser and providing a node-sass-compatible wrapper for Sass on the Dart VM, +but those aren't blocking the initial release. + +## Onward Into the Future + +The next couple months will see a lot of work go into getting Dart Sass stable +and compatible, and getting [Sass 3.5 +features](http://blog.sass-lang.com/posts/809572-sass-35-release-candidate) into +LibSass. I think it's likely that early 2017 will see a stable release of Dart +Sass and a 3.5 release of LibSass. At that point we'll set our sight on the big +features and start working towards Sass 4.0 and its brand new module system. + +Dart Sass is a big change, but it's an exciting one as well. It'll allow us to +get new features into users' hands faster, and to make those features *run* +faster. It'll make it possible for users to trivially install and run the +reference implementation. And it'll give us a performant way to run Sass in pure +JavaScript Sass for the first time ever. The benefits are large and tangible, +and I'm confident they're worth the costs. diff --git a/source/blog/010-dart-sass-is-on-chocolatey.html.md b/source/blog/010-dart-sass-is-on-chocolatey.html.md new file mode 100644 index 000000000..6bf1852b9 --- /dev/null +++ b/source/blog/010-dart-sass-is-on-chocolatey.html.md @@ -0,0 +1,45 @@ +--- +title: Dart Sass is On Chocolatey +author: Natalie Weizenbaum +date: 2017-01-13 14:43 PST +--- + +One of the quieter benefits of [moving to Dart](/blog/announcing-dart-sass) is +how easy it is to distribute Dart applications. The Dart VM is able to bundle +all the sources for an application into one easy-to-load binary snapshot, which +means running a Dart application requires only three files: the `dart` +executable, the snapshot file, and a tiny shell script to invoke the app[^1]. +This is a huge relief coming from Ruby, which required a whole installation of +executables and libraries in order to run a single app. + +Those three files are what we distribute today [on our GitHub release +page](https://github.com/sass/dart-sass/releases). But finding, downloading, and +opening an archive and adding it to the command-line path is still a barrier to +entry that we'd like to avoid where possible. Today we're taking a step in that +direction by releasing [a Dart Sass +package](https://chocolatey.org/packages/sass) on +[Chocolatey](https://chocolatey.org/), the Windows package manager. You can +install it now using: + +``` +$ choco install sass -prerelease +``` + +This will give you a `sass` executable that runs Dart Sass on the (really fast) +Dart VM. + +A large percentage of Sass users are on Windows, and it hasn't always been easy +for them to get the latest and greatest Sass versions without a bunch of +installation headaches. I'm excited that we can start taking advantage of our +new infrastructure to fix that. + +In addition to Chocolatey, we'd love to get Dart Sass on +[Homebrew](http://brew.sh/) for our OS X users. If you're interested in helping +out with that, let us know—[this +issue](https://github.com/sass/dart-sass/issues/97) would be a great place to +start! + +[^1]: There's also [an open + issue](https://github.com/dart-lang/sdk/issues/27596) for bundling the VM + and the snapshot into a single executable file, which would allow us to pare + down our distribution to a single file. diff --git a/source/blog/011-sass-and-browser-compatibility.html.md b/source/blog/011-sass-and-browser-compatibility.html.md new file mode 100644 index 000000000..2114116d4 --- /dev/null +++ b/source/blog/011-sass-and-browser-compatibility.html.md @@ -0,0 +1,52 @@ +--- +title: Sass and Browser Compatibility +author: Natalie Weizenbaum +date: 2017-02-10 17:46 PST +--- + +One of the core design principles of Sass has always been to **understand CSS as +little as possible**. As a CSS preprocessor of course we have to understand the +syntax of CSS, but as much as we can we try to avoid caring about the +*semantics*—the meaning behind the styles. This means that Sass has no idea +which properties are valid, which HTML elements actually exist, or even to a +large extent what the syntax of most @-rules is. + +We get a lot of benefit from this. The less built-in knowledge Sass has about +CSS, the less likely it is to work poorly with new CSS features. Imagine having +to file a feature request every time you want to use a new CSS property—that +would suck! Instead, older versions of Sass will happily keep working unless the +actual *syntax* changes, which is much rarer. + +Because of this decoupling, we've never needed to worry much about browser +compatibility. Sass just passes whatever CSS its given on through. It's up to +the user to determine what works where, which gives them a lot of flexibility +and gives us designers one fewer tough decision to make. + +But despite this general policy, there are always a few cases where CSS +knowledge turns out to be necessary. A big one is `@extend`, which needs to know +a lot about the meaning of selectors to properly unify them and weed out +duplicates. Property values sometimes require semantic knowledge as well—we have +to know how to interpret colors, for example. + +One of those cases has leapt up to bite us. Long ago, we made the decision to +always emit transparent colors as the keyword `transparent`, because it was +supported on IE6 through 8 and the alternative `rgba()` syntax was not. But it +turns out that the opposite is true for more recent versions: in IE10, `:hover` +styles aren't triggered for elements with `background-color: transparent` but +they are with `background-color: rgba(0, 0, 0, 0)`. Thanks, IE! + +So we were faced with a dilemma. Keep the existing behavior which was compatible +with old outdated browsers that no one uses, or choose a new behavior that works +better with modern browsers? The choice was pretty clear: we decided to always +emit `rgba(0, 0, 0, 0)`. + +In addition, we wanted to come up with a general rule to guide us in determining +which browsers we were willing to consider outdated, and which we would continue +to support (whatever that meant for the behavior in question). We decided that +if a change would negatively affect less than 2% of the global market share of +browsers according to [StatCounter GlobalStats](http://gs.statcounter.com/), we +were willing to make it. + +This limit isn't set in stone. We reserve the right to change it in the future, +and to make individual decisions that may affect more browsers. But this is the +general guideline we're paying attention to, and we wanted you all to know. diff --git a/source/blog/012-dart-sass-is-in-beta.html.md b/source/blog/012-dart-sass-is-in-beta.html.md new file mode 100644 index 000000000..e8c146c99 --- /dev/null +++ b/source/blog/012-dart-sass-is-in-beta.html.md @@ -0,0 +1,71 @@ +--- +title: Dart Sass is in Beta +author: Natalie Weizenbaum +date: 2017-06-05 13:00 PST +--- + +Last weekend was [three days long](https://en.wikipedia.org/wiki/Memorial_Day) +and the weather in Seattle was gorgeous. Contrary to stereotype, spring here is +often characterized by bright sunny days that aren't too hot, and on days like +that I love to curl up on the armchair in my living room and write some code. +This weekend, that meant finishing up the last few outstanding `@extend` bugs, +finally **making Dart Sass fully sass-spec compatible**[^1]. + +[^1]: Technically there are still two specs marked as "TODO". These test UTF-16 + support, which is currently [blocked on Dart + support](https://github.com/dart-lang/sdk/issues/11744). + +This is the milestone we've decided would mark the transition from alpha to beta +releases of Dart Sass. Dart Sass 1.0.0-beta.1 is up now on npm, pub, and +Chocolatey, and I encourage people to start trying it out in their own +applications. We've fixed all the bugs we know about, so now we need our +diligent users to find the rest of them and [tell +us](https://github.com/sass/dart-sass/issues/new)! + +## Next Steps: Ruby Sass + +There are a number of [intentional behavior +differences](https://github.com/sass/dart-sass#behavioral-differences) between +Dart Sass and the existing implementations. All of these differences are things +we think improve the language, and many of them have also made Dart Sass much +easier to implement, but we recognize that they can make migration more +difficult. That's why our next priority is updating Ruby Sass by deprecating old +behavior or adding new behavior, as necessary. + +Our long-term compatibility goal is to ensure, as much as possible, that **if a +stylesheet compiles without warnings on Ruby Sass, it will also work with Dart +Sass**. So a substantial portion of our effort in the near future be spent on +ensuring [all the compatibility +issues](https://github.com/sass/sass/labels/Dart%20Sass%20Compatibility) are +fixed. Once that's done, we'll release those changes as part of Ruby Sass 3.5. + +## Next Steps: Dart Sass + +On the Dart front, we have [a number of +issues](https://github.com/sass/dart-sass/milestone/1) outstanding that we want +to resolve before we release a stable version of 1.0.0. The majority of these +issues are focused on one thing: compatibility with the node-sass `render()` +API. This will make it easy to integrate Dart Sass into existing JS ecosystem +tools and workflows, since anything that works with node-sass will automatically +work with Dart Sass as well. + +## Try It Out + +As with all Dart Sass releases, 1.0.0-beta.1 is available on many platforms. +Give it a try on whichever is easiest for you: + +* Standalone tarballs are [available on + GitHub](https://github.com/sass/dart-sass/releases/tag/1.0.0-beta.1), which + you can just download and run from the command line. + +* [Chocolatey](https://chocolatey.org) users on Windows can just run `choco + install sass --pre` (or `choco upgrade sass --pre` if you already have it). + +* You can get the pure-JavaScript version from npm by running `npm install -g + dart-sass`. + +* Or if you're a Dart user, you can run `pub global activate sass`. + +I'm very pleased to have 1.0.0-beta.1 tagged and out in the world, but the work +of a language maintainer is never done. I'm back to work, and if I hustle, +hopefully I'll be writing about 1.0.0-rc.1 soon! diff --git a/source/blog/013-sass-35-is-released.html.md b/source/blog/013-sass-35-is-released.html.md new file mode 100644 index 000000000..3b8d82878 --- /dev/null +++ b/source/blog/013-sass-35-is-released.html.md @@ -0,0 +1,98 @@ +--- +title: Sass 3.5 is Released +author: Natalie Weizenbaum +date: 2017-07-07 15:33 PST +--- + +I'm excited to announce that I've just released the stable version of Sass 3.5. +This release focuses on compatibility with new CSS syntax, and helps lay the +groundwork for the upcoming module system and compatibility with [Dart +Sass](/blog/announcing-dart-sass). + +Most of the major features in 3.5 were already in the release candidate, which +[you can read about here](/blog/sass-35-release-candidate). But there are a +handful of other changes that have been added since then: + +* Sass now supports the [the `::slotted()` + pseudo-element](https://drafts.csswg.org/css-scoping-1/#slotted-pseudo), + including extending its selector arguments. + +* [The `var()` function](https://www.w3.org/TR/css-variables-1/#using-variables) + may be safely passed to the CSS color functions `rgb()`, `rgba()`, `hsl()`, + and `hsla()`. + +* Transparent colors created by Sass's color functions will now be written as + `rgba(0, 0, 0, 0)` rather than `transparent` to work around a bug in Internet + Explorer. Colors written as `transparent` in the document will still be + emitted as written. + +### Dart Sass Compatibility + +[I wrote last month](http://sass.logdown.com/posts/1909151) about our plans for +keeping Ruby Sass compatible with Dart Sass in the short term. Sass 3.5 begins +to implement those plans by adding support for a number of small behavioral +extensions added by Dart Sass: + +* It's no longer an error to `@extend` a selector that appears in the + stylesheet, but for which unification fails. The purpose of extension errors + was to prevent typos, which weren't occurring in this case. + +* Pseudo selectors that take arguments can now take any argument that matches + CSS's [`` + syntax](https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value). + This will provide better forwards-compatibility with new selectors. + +* Pseudo selectors that contain placeholder selectors as well as + non-placeholders—for example, `:matches(.foo, %bar)`—will no longer be + eliminated. This matches the definition of a placeholder as a selector that + matches nothing. + +* You can now vary the indentation within an indented-syntax file, as long as it + still defines a consistent tree structure. + +There are also some deprecations for functionality that's not supported in Ruby +Sass: + +* Extending compound selectors, such as `@extend .foo.bar`, is deprecated. This + never followed the stated semantics of extend: elements that match the + extending selector are styled as though they matches the extended selector. + + When you write `h1 {@extend .a.b}`, this *should* mean that all `h1` elements + are styled as though they match `.a.b`—that is, as though they have `class="a + b"`, which means they'd match both `.a` and `.b` separately. But instead we + extend only selectors that contain *both* `.a` and `.b`, which is incorrect. + +* Color arithmetic is deprecated. Channel-by-channel arithmetic doesn't + correspond closely to intuitive understandings of color. Sass's suite of + [color + functions](/documentation/Sass/Script/Functions.html#other_color_functions) + are a much cleaner and more comprehensible way of manipulating colors + dynamically. + +* The reference combinator, `/foo/`, is deprecated since it hasn't been in the + CSS specification for some time and is being removed from Chrome soon. + +* The old-style `:name value` property syntax is deprecated. This syntax is not + widely used, and is unnecessarily different from CSS. + +### LibSass Compatibility + +[LibSass](/libsass), the C++ implementation of Sass, is well on its way to +compatibility with all these features. It's not quite there yet, but we decided +we didn't want to block the 3.5 release on 100% compatibility. LibSass will +release these features as it implements them. + +### What's Next? + +In the most immediate future, I'm going on leave for a few months, so there's +not likely to be a huge amount of work. Once that's over, I'll be focusing on +getting Dart Sass to a full 1.0.0 release, which means spending a bunch of time +making its JavaScript API compatible with +[node-sass](http://npmjs.com/package/node-sass). + +As far as Ruby Sass goes, I'll continue to fix bugs and add support for the CSS +features as browsers start to support them. Once Dart Sass 1.0.0 is out, I'll +add new features concurrently across both Ruby and Dart until the one-year +support period is up. + +But for now, run `gem update sass` and enjoy 3.5! diff --git a/source/blog/014-dart-sass-100-is-released.html.md b/source/blog/014-dart-sass-100-is-released.html.md new file mode 100644 index 000000000..53c35969b --- /dev/null +++ b/source/blog/014-dart-sass-100-is-released.html.md @@ -0,0 +1,96 @@ +--- +title: Dart Sass 1.0.0 is Released +author: Natalie Weizenbaum +date: 2018-03-26 13:15 PST +--- + +I've just uploaded Dart Sass 1.0.0, the very first stable release, to +[GitHub](https://github.com/sass/dart-sass/releases/tag/1.0.0-rc.1), +[npm](https://www.npmjs.com/package/sass), +[Chocolatey](https://chocolatey.org/packages/sass), +[Homebrew](https://github.com/sass/homebrew-sass), and +[pub](http://pub.dartlang.org/packages/sass). After working on it for almost two +years, I'm thrilled to have a stable release out there and officially ready to +use in real-world applications. [All the reasons we chose +Dart](/blog/announcing-dart-sass) as the implementation language are bearing +fruit: Dart Sass is much faster than Ruby Sass, much easier to make available +across operating systems and language environments, and much more maintainable. + +The 1.0.0 stable release indicates that Dart Sass is fully compatible with the +Sass language as defined by [the sass-spec test +suite](http://github.com/sass/sass-spec), and that its npm package is compatible +with the [Node Sass +API](https://github.com/sass/node-sass/blob/master/README.md#usage), with the +exception of source map support which is [coming +soon](https://github.com/sass/dart-sass/issues/2). + +I've also updated sass-lang.com to cover Dart Sass. The release bar now shows +the latest version of all three major implementations, as well as links to their +release notes and documentation about each one. The [install page](/install) +covers Dart Sass instead of Ruby Sass, and the [Dart Sass page](/dart-sass) +talks all about what Dart Sass is and the various ways it can be used. + +### What's Next? + +At first, the focus of Dart Sass was on compatibility with the Sass language. +Once we reached that and [graduated to a beta +release](/blog/dart-sass-is-in-beta), we shifted our focus to compatibility with +the Node Sass API. Now that we've reached that, our primary aim for the next +several months will be bringing the usability of Dart Sass up to (at least) the +standard of Ruby Sass and Node Sass. + +This means focusing on a number of features outside the language that make +working with Sass pleasant. This includes [generating source +maps](https://github.com/sass/dart-sass/issues/2) from both the command-line +interface and the JavaScript API, [adding a live watch +mode](https://github.com/sass/dart-sass/issues/264), and [integrating Dart Sass +into the Node ecosystem](https://github.com/sass/dart-sass/issues/267). We've +also got our eye on the possibility of creating [a Ruby +gem](https://github.com/sass/dart-sass/issues/249) that embeds Dart Sass with a +Ruby Sass-like API. + +Of course, I'll also continue to keep on top of bug fixes and new CSS features. +I probably won't personally have a lot of bandwidth for adding new language +features, but if anyone else is interested there are a number that [wouldn't be +too hard to +add](https://github.com/sass/sass/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22+label%3APlanned). +Dart is a very easy language to learn, and I've written up a [helpful guide on +contributing](https://github.com/sass/dart-sass/blob/master/CONTRIBUTING.md#readme). + +### What About Ruby Sass? + +I'll be posting a more detailed post about the future of Ruby Sass soon, but the +abbreviated version is that it's now officially deprecated. I'll continue +maintaining it for one more year from the date this blog post goes live, +including fixing bugs and updating it to support new CSS features, but it won't +be getting any new language features. Once the one-year deprecation period is +up, the repository will be archived and no new versions will be released. + +Of course, all that could change if someone is willing to step up as a new +maintainer! It's not an easy task, but it's a chance to work on something that's +used by tons of people every day. If you're interested, please email +[me](mailto:nex342@gmail.com) and [Chris](mailto:chris@eppsteins.net) and we'll +talk to you about next steps. + +### Give It a Whirl + +One of the big benefits of switching to Dart is increased portability, which +means it's easier than ever to install Sass. Give it a try on whichever is +easiest for you: + +- Standalone tarballs are [available on + GitHub](https://github.com/sass/dart-sass/releases/tag/1.0.0), which you can + just download and run from the command line. + +- You can get the pure-JavaScript version from npm by running `npm install -g + sass`. + +- [Chocolatey](https://chocolatey.org/) users on Windows can run `choco install + sass` (or `choco upgrade sass` if you already have it). + +- [Homebrew](https://brew.sh/) users on Mac OS X can run `brew install + sass/sass/sass` (or `brew upgrade sass` if you already have it). + +- Or if you're a Dart user, you can run `pub global activate sass`. + +Now, get styling! diff --git a/source/blog/015-ruby-sass-is-deprecated.html.md b/source/blog/015-ruby-sass-is-deprecated.html.md new file mode 100644 index 000000000..02449bcac --- /dev/null +++ b/source/blog/015-ruby-sass-is-deprecated.html.md @@ -0,0 +1,99 @@ +--- +title: Ruby Sass is Deprecated +author: Natalie Weizenbaum +date: 2018-04-02 11:35 PST +--- + +With the release of [Dart Sass 1.0.0 stable](/blog/dart-sass-100-is-released) +last week, Ruby Sass was officially deprecated. I'll continue to maintain it +over the next year, but when 26 March 2019 rolls around it will reach its +official end-of-life. I encourage all users to start migrating away sooner +rather than later. + +### The Deprecation Period + +Over the next year, I'll continue to work on Ruby Sass in a limited capacity. +I'll triage and fix any bugs that are reported, unless they're minor or obscure +enough to be unlikely to pose a practical problem over the next year. I'll also +add support for any new CSS features that require changes to the Sass parser or +other parts of the language. + +I won't be working on language features that aren't necessary for CSS support, +though. The latest and greatest features will be appearing exclusively in [Dart +Sass](/dart-sass) and [LibSass](/libsass) from here on out. + +I also won't be accepting pull requests for new Ruby Sass features. While pull +requests are a great way to contribute to projects, they still take work on my +part to merge in, and it just doesn't make sense to spend time on that work when +the project is being turned down. If you're interested in contributing to Sass, +I highly recommend [contributing to Dart +Sass](https://github.com/sass/dart-sass/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)—Dart +is an extremely easy language to learn! + +We're also be migrating the Ruby Sass repository to +https://github.com/sass/ruby-sass, so be sure to update your Git URLs. The old +repository URL will continue to work during the deprecation period, but it will +be frozen; all ongoing maintenance will happen at the new URL. Once the +deprecation period is over, the Git history for the old URL will be wiped and +replaced with feature specifications. See [this +issue](https://github.com/sass/sass/issues/2480) for the full plan. + +### Migrating Away + +We want to make it as easy as possible to migrate from Ruby Sass onto an +actively-maintained implementation. The best way to do that depends on how you +use Ruby Sass today. + +If you use Ruby Sass as a command-line tool, the easiest way to migrate is to +[install Dart Sass](/install) as a command-line tool. It supports a similar +interface to Ruby Sass, although it currently doesn't support the `--watch` or +`--update` flags—[adding them](https://github.com/sass/dart-sass/issues/264) is +high priority, though! + +If you use Ruby Sass as a plugin for a Ruby web app, particularly if you define +your own Sass functions in Ruby, the +[`sassc`](https://github.com/sass/sassc-ruby) gem provides access to +[LibSass](/libsass) from Ruby with a very similar API to Ruby Sass. In most +cases, you can just replace the `Sass` module with the `SassC` module and your +code will continue to work. + +If you're using Rails, I particularly recommend using the +[`sassc-rails`](https://github.com/sass/sassc-rails) gem, which wraps up the +`sassc` gem and integrates it smoothly into the asset pipeline. Most of the time +you won't even need to change any of your code. + +We're also planning to add support to Dart Sass for [embedding it in +Ruby](https://github.com/sass/dart-sass/issues/248) (and other programming +languages). This will allow Ruby users to get the latest and greatest features +as soon as they're implemented. + +### End of Life + +On 26 March 2019, the deprecation period for Ruby Sass will end and it will no +longer be maintained. The new `sass/ruby-sass` repository will be +[archived](https://help.github.com/articles/about-archiving-repositories/), +which means no changes will be made and no new issues or pull requests will be +accepted. The old `sass/sass` repository will have its Git history replaced with +feature specifications that have historically just been scattered around issue +comments. + +Leading up to the end of life, we'll be migrating the user-focused [reference +documentation](/documentation/file.SASS_REFERENCE.html) from the Ruby Sass +repository to the Sass website. We could use some help doing the migration and +touching up the documentation, so if you're interested please [chime in on the +tracking issue](https://github.com/sass/sass-site/issues/205)! + +#### Unless... + +We're turning down support for Ruby Sass because the Sass team just doesn't have +the bandwidth to maintain it along with the other major implementations. But +there could be another solution. If someone from the community is willing to +step up and take on the mantle of maintainer, we'd be more than happy to show +them the ropes and help them keep Ruby Sass going. + +Maintaining a language implementation isn't necessarily easy. It requires +keeping up with features as they're added to Dart Sass, as well as fixing bugs +and fielding pull requests. But it's also a great opportunity to work on a big +project with a lot of impact, and I'm happy to help get a new maintainer up to +speed. If you're interested, please email [me](mailto:nex342@gmail.com) and +[Chris](mailto:chris@eppsteins.net) and we'll talk about how to get started. diff --git a/source/blog/016-request-for-commentsimporting-css-files.html.md b/source/blog/016-request-for-commentsimporting-css-files.html.md new file mode 100644 index 000000000..f194e6f36 --- /dev/null +++ b/source/blog/016-request-for-commentsimporting-css-files.html.md @@ -0,0 +1,102 @@ +--- +title: "Request For Comments: Importing CSS Files" +author: Natalie Weizenbaum +date: 2018-07-09 11:19 PST +--- + +As Dart Sass catches up with Ruby Sass in terms of usability, we're starting +work on adding new features to the language. The first feature we're looking at +is one that's long been requested by users: adding support for importing plain +CSS files without having to rename them to `.scss`. Not only do we expect this +to be very useful, it's already partially implemented in LibSass, so this will +help bring the implementations more in line with one another. + +We're also trying out a new process with this feature. In order to help keep the +behavior of different implementations in sync, we're starting with a prose +specification of the feature before moving on to writing code. We're also taking +this as an opportunity to solicit feedback from you, the Sass community! We want +to hear your thoughts on the new feature while we have a chance to revise it +based on that feedback. + +## Background + +Historically, the reference implementations of Sass—first Ruby Sass, then Dart +Sass—only supported importing other Sass files. However, LibSass supported +importing CSS files as well, interpreting them as though they were SCSS. +Although this technically violated the [implementation guide][]'s prohibition on +unilaterally extending the language, these CSS imports were useful and were +widely adopted in the Node.js community. + +[implementation guide]: /implementation + +This became particularly clear when, at the language team's urging, LibSass +added [deprecation warnings][libsass#2611] for CSS imports and users were left +without a suitable replacement. The language team came together to discuss the +problem, and decided to move towards allowing CSS imports but forbidding the use +of non-CSS features in the imported files. The proposal describes the specifics +of that idea. + +[libsass#2611]: https://github.com/sass/libsass/issues/2611 + +LibSass's behavior at time of writing is to import files with the extension +`.css` at the same precedence level as those with the `.scss` and `.sass` +extensions, and to throw an error if an import is ambiguous between a `.css` +file and a `.scss` or `.sass` file. + +## Summary + +The proposal seeks to strike a balance between preserving compatibility with +LibSass's existing behavior and moving towards a more principled scheme for +loading CSS. This is particularly important as we intend to allow `@use` to load +CSS files without Sass features, so we want the existing CSS loading support to +be as similar as possible. + +Locating CSS files for import works similarly under the proposal as it does in +LibSass currently: a relative `.css` file takes precedence over files with any +extension on the load path, a `.css` file earlier on the load path takes +precedence over a file with any extension later on the load path, and `foo.css` +takes precedence over `index/foo.scss`. + +The only difference in loading scheme occurs when an import is ambiguous between +a `.css` file and a `.scss` or `.sass` file at the same path. LibSass currently +produces an error here, but in order to maximize compatibility with existing +Dart Sass (and Ruby Sass) behavior, the proposal has the `.scss` or `.sass` file +taking precedence. This is not a breaking change to LibSass's behavior, since it +only applies in situations that would previously have produced an error. + +The proposal diverges significantly from LibSass in parsing the imported CSS +files, though: it forbids all use of SCSS features in the parsed files. Most +SCSS features produce errors (rather than compiling to plain, likely-invalid +CSS) in order to help users who accidentally wrote SCSS in their CSS realize +what's going wrong. However, features like `@import` that overlap with plain CSS +continue to be rendered as CSS. + +In order to avoid a sudden backwards-incompatible change in LibSass, this also +includes a proposal for a set of deprecation warnings that can be added to +LibSass's existing behavior to steer users away from using Sass features in +their imported CSS without entirely breaking their build process. + +## Giving Feedback + +If you want more details on exactly how the proposed behavior will work, [head +over to the `sass/language` repo and read the full +proposal](https://github.com/sass/language/blob/master/accepted/css-imports.md). +You can skip the Background and Summary sections, since they're included above. +Be aware, though, that it's written to be a specification; it's a great for +figuring out how exactly an edge case should work, but it's not as +conversational as the sections quoted above. + +If you have any issues with the proposal as written, or if it doesn't cover a +use-case that's important to you, [please bring that up in the `sass/language` +issue +tracker](https://github.com/sass/language/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22proposal%3A+CSS+imports%22). +We'll be leaving it open for discussion for at least two weeks before we mark +the proposal as "accepted" and move on to the implementation phase. + +Please be aware, though, that while we welcome community feedback, the design of +Sass is ultimately in the hands of the language team. We'll absolutely consider +the perspectives and use-cases of users who speak up, but it's also our job to +consider all the users who are new to Sass or even to CSS and who don't yet know +to read blogs or comment on issue trackers. Remember that our careful +decision-making made Sass what it is today, and have patience with us if we +don't make the decisions you would have! diff --git a/source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md b/source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md new file mode 100644 index 000000000..0b70988da --- /dev/null +++ b/source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md @@ -0,0 +1,116 @@ +--- +title: "Feature Watch: CSS Imports and CSS Compatibility" +author: Natalie Weizenbaum +date: 2018-08-13 14:17 PST +--- + +Dart Sass 1.11 has just been released, and with it a handful of new features. +This is an exciting moment, because it marks the first major new feature that's +been added to the language since Dart Sass was launched. It's also the first +release with features that have gone through the new process, from +[proposal](https://github.com/sass/language/blob/master/accepted/css-imports.md) +to [tests](https://github.com/sass/sass-spec/pull/1277) to +[implementation](https://github.com/sass/dart-sass/pull/436). + +### CSS Imports + +The biggest feature in Dart Sass 1.11 is support for importing plain CSS files. +This is a long-awaited feature, and while we'd initially planned on waiting on +it until we launched the upcoming module system, we ended up deciding to +[implement it earlier](/blog/request-for-commentsimporting-css-files). + +You can now import a CSS file, say `styles.css`, just by writing `@import +"styles"`. That file will be parsed as plain CSS, which means that any Sass +features like variables or mixins or interpolation will be disallowed. The CSS +it defines will become part of your stylesheet, and can be `@extend`ed just like +any other styles. + +There are a couple caveats: because SCSS is a superset of plain CSS, it will +still compile `@import "styles.css"` (with an explicit extension) to a CSS +`@import` rule. If you want to import a CSS file into your Sass compilation, you +must omit the extension. + +Also, this feature isn't fully [implemented in +LibSass](https://github.com/sass/libsass/issues/2699) yet. It still has its old +behavior, where it imports CSS files but parses them as SCSS, with all the extra +Sass features allowed. This behavior will be deprecated soon, and eventually it +will produce errors for anything other than plain CSS, just like Dart Sass does +today. + +### CSS `min()` and `max()` + +Dart Sass 1.11 also adds support for CSS's `min()` and `max()` mathematical +functions. For those unfamiliar, these functions work a lot like `calc()`, +except they return the minimum or maximum of a series of values. For example, +you can write `width: max(50%, 100px)` to make your element either 50% of the +parent's width or 100px wide, whichever is greater. + +Because Sass has its own functions named `min()` and `max()`, it was difficult +to use these CSS functions... until now. Dart Sass 1.11 will intelligently +decide whether to use the plain CSS functions or the built-in Sass functions +based on whether or not you're passing in dynamic Sass values. For example: + +* The Sass function will be called if you pass a variable, like `max($width, + 100px)`. +* The Sass function will be called if you call another Sass function, like + `max(compute-width(), 100px)`. +* It will compile to a plain CSS function if you just use plain CSS numbers, + like `max(50% + 10px, 100px)`. +* It will still compile to a plain CSS function even if you use interpolation, + like `max(50% + #{$width / 2}, #{$width})`. + +This preserves backwards-compatibility with existing uses of the Sass functions, +while also users to use the CSS functions the same way they would in plain CSS. + +This feature isn't yet implemented in +[LibSass](https://github.com/sass/libsass/issues/2701) or [Ruby +Sass](https://github.com/sass/ruby-sass/issues/77). + +### Range-Format Media Queries + +CSS Media Queries Level 4 defines a [range +syntax](https://www.w3.org/TR/mediaqueries-4/#mq-range-context) for defining +certain media queries: + +```css +@media (width > 500px) { + /* ... */ +} +``` + +Dart Sass 1.11 adds support for this syntax. It works just like existing media +query support: you can either use interpolation or plain Sass expressions to +inject Sass logic into the query, and they can still be nested. + +```scss +@media (width > $width) { + @media (height < #{$height}) { + /* ... */ + } +} +``` + +This feature isn't yet implemented in +[LibSass](https://github.com/sass/libsass/issues/2698) or [Ruby +Sass](https://github.com/sass/ruby-sass/issues/75). + +### Normalized Identifier Escapes + +The last compatibility improvement is a bit of an edge case, but it's still +worth mentioning: the way Sass parses escapes in identifiers has been improved +to better match the CSS spec. + +Escapes are now normalized to a standard format, which means that (for example) +`éclair` and `\E9clair` are parsed to the same value (in this case, `éclair`). +Prior to this change, if an escape was written, it would always be preserved +as-is, so `str-length(\E9clair)` would return `8` even though that identifier +means exactly the same thing to CSS as `éclair`. + +We don't anticipate this affecting many users, but we always strive to bring +Sass as close to the semantics of CSS as possible. This is a small but important +step on that path. + +This feature isn't yet implemented in +[LibSass](https://github.com/sass/libsass/issues/2700) or [Ruby +Sass](https://github.com/sass/ruby-sass/issues/76). + diff --git a/source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md b/source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md new file mode 100644 index 000000000..746184cac --- /dev/null +++ b/source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md @@ -0,0 +1,134 @@ +--- +title: "Feature Watch: Content Arguments and Color Functions" +author: Natalie Weizenbaum +date: 2018-11-14 14:14 PST +--- + +Dart Sass 1.15, released today and available [on +npm](https://npmjs.com/package/sass) and [all other distribution +channels](/install), brings with it a number of highly-anticipated new Sass +features. This is also the first release of Dart Sass with major new language +features that *aren't* just for CSS compatibility. That's a big accomplishment, +and we intend to continue that pattern moving forward! + +### `@content` Arguments + +Mixins that take [`@content` +blocks](/documentation/file.SASS_REFERENCE.html#mixin-content) can now pass +arguments to those blocks. This is written `@content()`. If a +mixin passes arguments to its content block, users of that mixin must accept +those arguments by writing `@include using ()`. The +argument list for a content block works just like a mixin's argument list, and +the arguments passed to it by `@content` work just like passing arguments to a +mixin. + +```scss +// style.scss +@mixin media($types...) { + @each $type in $types { + @media #{$type} { + @content($type); + } + } +} + +@include media(screen, print) using ($type) { + h1 { + font-size: 40px; + @if $type == print { + font-family: Calluna; + } + } +} +``` + +```css +/* style.css */ +@media screen { + h1 { + font-size: 40px; + } +} +@media print { + h1 { + font-size: 40px; + font-family: Calluna; + } +} +``` + +For more details, see [the feature +proposal](https://github.com/sass/language/blob/master/accepted/content-args.md). +This feature is implemented in LibSass, and will be released in version 3.6.0. +Since [Ruby Sass is deprecated](/blog/ruby-sass-is-deprecated) and this isn't a +CSS compatibility feature, it won't be implemented in Ruby Sass. + +### Color Level 4 Syntax for `rgb()` and `hsl()` + +The [CSS Color Module Level 4](https://drafts.csswg.org/css-color/) has +introduced new syntax for the `rgb()` and `hsl()` functions, which has begun to +be supported in browsers. This syntax makes these functions more compact, allows +the alpha value to be specified without needing additional `rgba()` and `hsla()` +functions, and it looks like `rgb(0 255 0 / 0.5)` and `hsla(0 100% 50%)`. + +To support this function, Sass's `rgb()` and `hsl()` functions now accept a +space-separated list of components as a single argument. If this last argument +is a slash-separated pair of numbers, the first number will be treated as the +blue channel or lightness (respectively) and the second as the alpha channel. + +**Be aware though** that the normal rules for [disambiguating between division +and `/` as a +separator](/documentation/file.SASS_REFERENCE.html#division-and-slash) still +apply! So if you want to pass a variable for the alpha value, you'll need to use +the old `rgba()` syntax. We're [considering possible long-term +solutions](https://github.com/sass/sass/issues/2565) for this problem as `/` is +used more prominently as a separator in CSS. + +In addition, the new color spec defines the `rgba()` and `hsla()` functions as +pure aliases for `rgb()` and `hsl()`, and adds support for the four-argument +`rgba()` and `hsla()` syntax to `rgb()` and `hsl()` as well. To match this +behavior, Sass is also defining `rgba()` and `hsla()` as aliases and adding +support for all their definitions to `rgb()` and `hsl()`. + +All in all, this means that the function calls like all of the following are +newly supported in Sass: +* `rgb(0 255 0)`, `rgb(0% 100% 0%)`, `rgb(0 255 0 / 0.5)`, and `rgb(0, 255, 0, + 0.5)`; +* `hsl(0 100% 50%)`, `hsl(0 100% 50% / 0.5)`, and `hsl(0, 100%, 50%, 0.5)`; +* `rgba(0, 255, 0)` and `hsla(0, 100%, 50%)`; +* and `rgb($color, 0.5)`. + +This change is fully backwards-compatible, so all the arguments to `rgb()`, +`hsl()`, `rgba()`, and `hsla()` that previously worked will continue to do so. + +For more details, see [the feature +proposal](https://github.com/sass/language/blob/master/accepted/color-4-rgb-hsl.md). +This feature isn't yet implemented in +[LibSass](https://github.com/sass/libsass/issues/2722) or [Ruby +Sass](https://github.com/sass/ruby-sass/issues/84). + +### Interpolated At-Rule Names + +This feature is a little smaller than the last two, but it's been on the to-do +list for even longer: adding support for interpolation in the names of at-rules! +This works just how you'd expect: + +```scss +@mixin viewport($prefixes) { + @each $prefix in $prefixes { + @-#{$prefix}-viewport { + @content; + } + } + @viewport { + @content; + } +} +``` + +For more details, see [the feature +proposal](https://github.com/sass/language/blob/master/accepted/at-rule-interpolation.md). +This feature isn't yet implemented in +[LibSass](https://github.com/sass/libsass/issues/2721). Since [Ruby Sass is +deprecated](http://sass.logdown.com/posts/7081811) and this isn't a CSS +compatibility feature, it won't be implemented in Ruby Sass. diff --git a/source/blog/019-request-for-comments-module-system-proposal.html.md b/source/blog/019-request-for-comments-module-system-proposal.html.md new file mode 100644 index 000000000..f49789371 --- /dev/null +++ b/source/blog/019-request-for-comments-module-system-proposal.html.md @@ -0,0 +1,397 @@ +--- +title: "Request For Comments: Module System" +author: Natalie Weizenbaum +date: 2018-11-27 13:10 PST +--- + +Many of the most frequently-requested features for Sass have to do with its +imports. The import system that we've had since the very early releases of Sass +is, to put it simply, not great. It does little more than textually include one +Sass file in another, which makes it hard to keep track of where mixins, +functions, and variables were defined and hard to be sure that any new additions +won't happen to conflict with something elsewhere in the project. To make +matters worse, it overlaps with CSS's built-in `@import` rule, which forces us +to have [a bunch of heuristics](/documentation/file.SASS_REFERENCE.html#import) +to decide which is which. + +Because of these problems and others, we've wanted to do a full overhaul of the +way Sass files relate to one another for a long time. Over the last few years, +I've been working with the Sass core team and Sass framework maintainers to +create a proposal for a module system that's fit to replace `@import`. That +proposal is now in a place that the core team is pretty happy with, at least as +a starting point, so we want to open it up for community feedback. + +If you want to read the full proposal, [it's available on +GitHub](https://github.com/sass/language/blob/master/accepted/module-system.md). +Feel free to [file issues](https://github.com/sass/language/issues/new) for any +feedback you have. The main body of the proposal is written as a spec, so it's +very detailed, but the Goals, Summary, and FAQ sections (reproduced below) +should be accessible to anyone familiar with Sass. + +## Goals + +### High-Level + +These are the philosophical design goals for the module system as a whole. While +they don't uniquely specify a system, they do represent the underlying +motivations behind many of the lower-level design decisions. + +* **Locality**. The module system should make it possible to understand a Sass + file by looking only at that file. An important aspect of this is that names + in the file should be resolved based on the contents of the file rather than + the global state of the compilation. This also applies to authoring: an author + should be able to be confident that a name is safe to use as long as it + doesn't conflict with any name visible in the file. + +* **Encapsulation**. The module system should allow authors, particularly + library authors, to choose what API they expose. They should be able to define + entities for internal use without making those entities available for external + users to access or modify. The organization of a library's implementation into + files should be flexible enough to change without changing the user-visible + API. + +* **Configuration**. Sass is unusual among languages in that its design leads to + the use of files whose entire purpose is to produce side effects—specifically, + to emit CSS. There's also a broader class of libraries that may not emit CSS + directly, but do define configuration variables that are used in computations, + including computation of other top-level variables' values. The module system + should allow the user to flexibly use and configure modules with side-effects. + +### Low-Level + +These are goals that are based less on philosophy than on practicality. For the +most part, they're derived from user feedback that we've collected about +`@import` over the years. + +* **Import once**. Because `@import` is a literal textual inclusion, multiple + `@import`s of the same Sass file within the scope of a compilation will + compile and run that file multiple times. At best this hurts compilation time + for little benefit, and it can also contribute to bloated CSS output when the + styles themselves are duplicated. The new module system should only compile a + file once. + +* **Backwards compatibility**. We want to make it as easy as possible for people + to migrate to the new module system, and that means making it work in + conjunction with existing stylesheets that use `@import`. Existing stylesheets + that only use `@import` should have identical importing behavior to earlier + versions of Sass, and stylesheets should be able to change parts to `@use` + without changing the whole thing at once. + +### Non-Goals + +These are potential goals that we have explicitly decided to avoid pursuing as +part of this proposal for various reasons. Some of them may be on the table for +future work, but we don't consider them to be blocking the module system. + +* **Dynamic imports**. Allowing the path to a module to be defined dynamically, + whether by including variables or including it in a conditional block, moves + away from being declarative. In addition to making stylesheets harder to read, + this makes any sort of static analysis more difficult (and actually impossible + in the general case). It also limits the possibility of future implementation + optimizations. + +* **Importing multiple files at once**. In addition to the long-standing reason + that this hasn't been supported—that it opens authors up to sneaky and + difficult-to-debug ordering bugs—this violates the principle of locality by + obfuscating which files are imported and thus where names come from. + +* **Extend-only imports**. The idea of importing a file so that the CSS it + generates isn't emitted unless it's `@extend`ed is cool, but it's also a lot + of extra work. This is the most likely feature to end up in a future release, + but it's not central enough to include in the initial module system. + +* **Context-independent modules**. It's tempting to try to make the loaded form + of a module, including the CSS it generates and the resolved values of all its + variables, totally independent of the entrypoint that cause it to be loaded. + This would make it possible to share loaded modules across multiple + compilations and potentially even serialize them to the filesystem for + incremental compilation. + + However, it's not feasible in practice. Modules that generate CSS almost + always do so based on some configuration, which may be changed by different + entrypoints rendering caching useless. What's more, multiple modules may + depend on the same shared module, and one may modify its configuration before + the other uses it. Forbidding this case in general would effectively amount to + forbidding modules from generating CSS based on variables. + + Fortunately, implementations have a lot of leeway to cache information that + the can statically determine to be context-independent, including source trees + and potentially even constant-folded variable values and CSS trees. Full + context independence isn't likely to provide much value in addition to that. + +* **Increased strictness**. Large teams with many people often want stricter + rules around how Sass stylesheets are written, to enforce best practices and + quickly catch mistakes. It's tempting to use a new module system as a lever to + push strictness further; for example, we could make it harder to have partials + directly generate CSS, or we could decline to move functions we'd prefer + people avoid to the new built-in modules. + + As tempting as it is, though, we want to make all existing use-cases as easy + as possible in the new system, *even if we think they should be avoided*. This + module system is already a major departure from the existing behavior, and + will require a substantial amount of work from Sass users to support. We want + to make this transition as easy as possible, and part of that is avoiding + adding any unnecessary hoops users have to jump through to get their existing + stylesheets working in the new module system. + + Once `@use` is thoroughly adopted in the ecosystem, we can start thinking + about increased strictness in the form of lints or TypeScript-style + `--strict-*` flags. + +* **Code splitting**. The ability to split monolithic CSS into separate chunks + that can be served lazily is important for maintaining quick load times for + very large applications. However, it's orthogonal to the problems that this + module system is trying to solve. This system is primarily concerned with + scoping Sass APIs (mixins, functions, and placeholders) rather than declaring + dependencies between chunks of generated CSS. + + We believe that this module system can work in concert with external + code-splitting systems. For example, the module system can be used to load + libraries that are used to style individual components, each of which is + compiled to its own CSS file. These CSS files could then declare dependencies + on one another using special comments or custom at-rules and be stitched + together by a code-splitting post-processor. + +## Summary + +This proposal adds two at-rules, `@use` and `@forward`, which may only appear at +the top level of stylesheets before any rules (other than `@charset`). Together, +they're intended to completely replace `@import`, which will eventually be +deprecated and even more eventually removed from the language. + +### `@use` + +`@use` makes CSS, variables, mixins, and functions from another stylesheet +accessible in the current stylesheet. By default, variables, mixins, and +functions are available in a namespace based on the basename of the URL. + +```scss +@use "bootstrap"; + +.element { + @include bootstrap.float-left; +} +``` + +In addition to namespacing, there are a few important differences between `@use` +and `@import`: + +* `@use` only executes a stylesheet and includes its CSS once, no matter how + many times that stylesheet is used. +* `@use` only makes names available in the current stylesheet, as opposed to + globally. +* Members whose names begin with `-` or `_` are private to the current + stylesheet with `@use`. +* If a stylesheet includes `@extend`, that extension is only applied to + stylesheets it imports, not stylesheets that import it. + +Note that placeholder selectors are *not* namespaced, but they *do* respect +privacy. + +#### Controlling Namespaces + +Although a `@use` rule's default namespace is determined by the basename of its +URL, it can also be set explicitly using `as`. + +```scss +@use "bootstrap" as b; + +.element { + @include b.float-left; +} +``` + +The special construct `as *` can also be used to include everything in the +top-level namespace. Note that if multiple modules expose members with the same +name and are used with `as *`, Sass will produce an error. + +```scss +@use "bootstrap" as *; + +.element { + @include float-left; +} +``` + +#### Configuring Libraries + +With `@import`, libraries are often configured by setting global variables that +override `!default` variables defined by those libraries. Because variables are +no longer global with `@use`, it supports a more explicit way of configuring +libraries: the `with` clause. + +```scss +// bootstrap.scss +$paragraph-margin-bottom: 1rem !default; + +p { + margin-top: 0; + margin-bottom: $paragraph-margin-bottom; +} +``` + +```scss +@use "bootstrap" with ( + $paragraph-margin-bottom: 1.2rem +); +``` + +This sets bootstrap's `$paragraph-margin-bottom` variable to `1.2rem` before +evaluating it. The `with` clause only allows variables defined in (or forwarded +by) the module being imported, and only if they're defined with `!default`, so +users are protected against typos. + +### `@forward` + +The `@forward` rule includes another module's variables, mixins, and functions +as part of the API exposed by the current module, without making them visible to +code within the current module. It allows library authors to be able to split up +their library among many different source files without sacrificing locality +within those files. Unlike `@use`, forward doesn't add any namespaces to names. + +```scss +// bootstrap.scss +@forward "functions"; +@forward "variables"; +@forward "mixins"; +``` + +#### Visibility Controls + +A `@forward` rule can choose to show only specific names: + +```scss +@forward "functions" show color-yiq; +``` + +It can also hide names that are intended to be library-private: + +```scss +@forward "functions" hide assert-ascending; +``` + +#### Extra Prefixing + +If you forward a child module through an all-in-one module, you may want to add +some manual namespacing to that module. You can do what with the `as` clause, +which adds a prefix to every member name that's forwarded: + +```scss +// material/_index.scss +@forward "theme" as theme-*; +``` + +This way users can use the all-in-one module with well-scoped names for theme +variables: + +```scss +@use "material" with ($theme-primary: blue); +``` + +or they can use the child module with simpler names: + +```scss +@use "material/theme" with ($primary: blue); +``` + +### `@import` Compatibility + +The Sass ecosystem won't switch to `@use` overnight, so in the meantime it needs +to interoperate well with `@import`. This is supported in both directions: + +* When a file that contains `@import`s is `@use`d, everything in its global + namespace is treated as a single module. This module's members are then + referred to using its namespace as normal. + +* When a file that contains `@use`s is `@import`ed, everything in its public API + is added to the importing stylesheet's global scope. This allows a library to + control what specific names it exports, even for users who `@import` it rather + than `@use` it. + +In order to allow libraries to maintain their existing `@import`-oriented API, +with explicit namespacing where necessary, this proposal also adds support for +files that are only visible to `@import`, not to `@use`. They're written +`"file.import.scss"`, and imported when the user writes `@import "file"`. + +### Built-In Modules + +The new module system will also add seven built-in modules: `math`, `color`, +`string`, `list`, `map`, `selector`, and `meta`. These will hold all the +existing built-in Sass functions. Because these modules will (typically) be +imported with a namespace, it will be much easier to use Sass functions without +running into conflicts with plain CSS functions. + +This in turn will make it much safer for Sass to add new functions. We expect to +add a number of convenience functions to these modules in the future. + +#### `meta.load-css()` + +This proposal also adds a new built-in mixin, `meta.load-css($url, $with: ())`. +This mixin dynamically loads the module with the given URL and includes its CSS +(although its functions, variables, and mixins are not made available). This is +a replacement for nested imports, and it helps address some use-cases of dynamic +imports without many of the problems that would arise if new members could be +loaded dynamically. + +## Frequently Asked Questions + +* **Why this privacy model?** We considered a number of models for declaring + members to be private, including a JS-like model where only members that were + explicitly exported from a module were visible and a C#-like model with an + explicit `@private` keyword. These models involve a lot more boilerplate, + though, and they work particularly poorly for placeholder selectors where + privacy may be mixed within a single style rule. Name-based privacy also + provides a degree of compatibility with conventions libraries are already + using. + +* **Can I make a member library-private?** There's no language-level notion of a + "library", so library-privacy isn't built in either. However, members used by + one module aren't automatically visible to downstream modules. If a module + isn't [`@forward`ed](#forward) through a library's main stylesheet, it won't + be visible to downstream consumers and thus is effectively library-private. +

As a convention, we recommend that libraries write library-private + stylesheets that aren't intended to be used directly by their users in a + directory named `src`. + +* **How do I make my library configurable?** If you have a large library made up + of many source files that all share some core `!default`-based configuration, + we recommend that you define that configuration in a file that gets forwarded + from your library's entrypoint and used by your library's files. For example: + +```scss +// bootstrap.scss +@forward "variables"; +@use "reboot"; +``` + +```scss +// _variables.scss +$paragraph-margin-bottom: 1rem !default; +``` + +```scss +// _reboot.scss +@use "variables" as *; + +p { + margin-top: 0; + margin-bottom: $paragraph-margin-bottom; +} +``` + +```scss +// User's stylesheet +@use "bootstrap" with ( + $paragraph-margin-bottom: 1.2rem +); +``` + +## Sending Feedback + +This is still just a proposal. We're pretty happy with the overall shape of the +module system, but it's not at all set in stone, and anything can change with +enough feedback provided by users like you. If you have opinions, please [file +an issue on GitHub](https://github.com/sass/language/issues/new) or just [tweet +at @SassCSS](https://twitter.com/SassCSS). We'll take anything from "it looks +awesome" to "it looks awful", although the more specific you can be the more +information we have to work with! diff --git a/source/blog/020-ruby-sass-is-unsupported.html.md b/source/blog/020-ruby-sass-is-unsupported.html.md new file mode 100644 index 000000000..fb72351bb --- /dev/null +++ b/source/blog/020-ruby-sass-is-unsupported.html.md @@ -0,0 +1,57 @@ +--- +title: Ruby Sass Has Reached End-Of-Life +author: Natalie Weizenbaum +date: 2019-04-03 16:15 PST +--- + +One year has passed since we announced [the deprecation of Ruby +Sass](/blog/ruby-sass-is-deprecated), and it has now officially reached its +end-of-life. We will release one final version of the Ruby Sass gem that will +print a warning indicating that it's no longer receiving updates, and then +archive [the GitHub repository](https://github.com/sass/ruby-sass). + +![A woman saying "Goodbye, my friend"](/assets/img/blog/020-goodbye.gif) + +We will then merge the [sass/language](https://github.com/sass/language) repo +into the [sass/sass](https://github.com/sass/sass) repo. This means that +**anyone still depending on Ruby Sass from `github.com/sass/sass` will break.** +Going forward, the sass/sass repo will be the location for working on the +language specs, and will not contain any code. The sass/language repo will just +include links pointing to sass/sass. + +### Migrating Away + +If you haven't migrated away from Ruby Sass yet, now is the time. The best way +to do that depends on how you use Ruby Sass today. + +If you use Ruby Sass as a command-line tool, the easiest way to migrate is to +[install Dart Sass](/install) as a command-line tool. It supports a similar +interface to Ruby Sass, and you can run `sass --help` for a full explanation of +its capabilities. + +If you use Ruby Sass as a plugin for a Ruby web app, particularly if you define +your own Sass functions in Ruby, the +[`sassc`](https://github.com/sass/sassc-ruby) gem provides access to +[LibSass](/libsass) from Ruby with a very similar API to Ruby Sass. In most +cases, you can just replace the `Sass` module with the `SassC` module and your +code will continue to work. + +If you're using Rails, we particularly recommend using the +[`sassc-rails`](https://github.com/sass/sassc-rails) gem, which wraps up the +`sassc` gem and integrates it smoothly into the asset pipeline. Most of the time +you won't even need to change any of your code. + +### Farewell, Ruby Sass! + +On a personal note, I started writing Ruby Sass in 2006 when I was just a +college kid coding in between homework assignments. I've worked on it (with +varying degrees of focus) continuously for the last 13 years, and I expect it'll +take me a long time to match that record with any other codebase. I'm glad to +see the language [moving forward](/blog/announcing-dart-sass), but at the same +time I'll miss Ruby Sass terribly. + +I also want to take this opportunity to thank our users, especially those in the +Ruby community in which Sass was born, for appreciating the language we created +and evangelizing it so widely. Sass has an incredible userbase, and I've been so +proud to see how large and diverse it's grown over the years. Let's keep it up +as we move into a new era of Sass! diff --git a/source/blog/021-brand-new-sass-docs.html.md b/source/blog/021-brand-new-sass-docs.html.md new file mode 100644 index 000000000..b709c9682 --- /dev/null +++ b/source/blog/021-brand-new-sass-docs.html.md @@ -0,0 +1,33 @@ +--- +title: Brand New Sass Docs +author: Natalie Weizenbaum +date: 2019-04-23 10:04 PST +--- + +I'm excited to announce the launch of [a full rewrite and redesign of the Sass +documentation](/documentation), going live today after eight months of work by +[Jina Anne](https://github.com/jina) and myself! Jina, the lead of Team Sass +Design, is responsible for the layout and visual design of the new +documentation. She made everything gorgeous and readable. +[I](https://github.com/nex3) wrote all the text, so if you see a typo I'm the +one to blame. + +A preview of the function documentation page. + +In addition to reorganizing and rewriting all the documentation, we've added a special example widget that makes it easy to see how Sass stylesheets translate into CSS. It has tabs for both SCSS and the indented syntax, so you can use whichever you prefer, or switch between them to see the difference. + +The example widget. + +The Sass function documentation is included in the rewrite. Functions are now organized into easy-to-understand sections, and Jina designed a super readable layout for them. + +The round() function. + +Best of all, the new documentation has full-text search courtesy of our friends +at [Algolia](https://www.algolia.com/). You can search for features, function +names, or anything else you want to learn more about and find it in an instant. + +![An Algolia search.](/assets/img/blog/021-search.png) + +Please take a look and enjoy! And if you find any issues, don't hesitate to +[file them](https://github.com/sass/sass-site/issues/new) so we can keep making +the website better and better. diff --git a/source/blog/022-request-for-commentsforward-slash-as-separator.html.md b/source/blog/022-request-for-commentsforward-slash-as-separator.html.md new file mode 100644 index 000000000..c7ea2bd7d --- /dev/null +++ b/source/blog/022-request-for-commentsforward-slash-as-separator.html.md @@ -0,0 +1,81 @@ +--- +title: "Request For Comments: Forward Slash as Separator" +author: Natalie Weizenbaum +date: 2019-05-06 16:15 PST +--- + +Early on in Sass's history, the decision was made to use `/` as a division +operator, since that was (and is) by far the most common representation across +programming languages. The `/` character was used in very few plain CSS +properties, and for those it was an optional shorthand. So Sass defined [a set +of heuristics][] that defined when `/` would be rendered as a literal slash +versus treated as an operator. + +[a set of heuristics]: /documentation/operators/numeric#slash-separated-values + +For a long time, these heuristics worked pretty well. In recent years, however, +new additions to CSS such as [CSS Grid][] and [CSS Color Level 4][] have been +using `/` as a separator increasingly often. Using the same character for both +division and slash-separation is becoming more and more annoying to users, and +will likely eventually become untenable. + +[CSS Grid]: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row +[CSS Color Level 4]: https://drafts.csswg.org/css-color/#rgb-functions + +As such, we're planning to redefine `/` to be *only* a separator. Rather than +creating an unquoted string (as it currently does when at least one operand +isn't a number), it will create a list with a new slash separator. For example, +`1 / 2 / 3` will be a three-element slash-separated list. Division will instead +be written as a function, `divide()` (or `math.div()` in [the new module +system][]). + +[the new module system]: /blog/request-for-comments-module-system-proposal + +## Rollout + +This is a major breaking change to existing Sass semantics, so we'll roll it out +in a three-stage process: + +1. The first stage won't introduce any breaking changes. It will: + * Add a `divide()` function which will work exactly like the `/` operator + does today, except that it will produce deprecation warnings for any + non-number arguments. + * Add slash-separated lists to Sass's object models, *without* a literal + syntax for creating them. That will come later, since it would otherwise be + a breaking change. + * Add a `slash-list()` function that will create slash-separated lists. + * Produce deprecation warnings for all `/` operations that are interpreted as + division. + +2. The second stage *will* be a breaking change. It will: + * Make `/` exclusively a list separator. + * Make `divide()` throw errors for non-number arguments. + * Deprecate the `slash-list()` function, since it will now be redundant. + +3. The third stage will just remove the `slash-list()` function. This is not a + priority, and will be delayed until the next major version release. + +## Giving Feedback + +If you want more details on exactly how the proposed behavior will work, [head +over to the Sass language repo and read the full +proposal](https://github.com/sass/sass/blob/master/accepted/slash-separator.md). +You can skip the Background and Summary sections, since they're included above. +Be aware, though, that it's written to be a specification; it's a great for +figuring out how exactly an edge case should work, but it's not as +conversational as the sections quoted above. + +If you have any issues with the proposal as written, or if it doesn't cover a +use-case that's important to you, [please bring that up in the Sass language +issue +tracker](https://github.com/sass/sass/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22proposal%3A+slash+separator%22). +We'll be leaving it open for discussion for at least two weeks before we mark +the proposal as "accepted" and move on to the implementation phase. + +Please be aware, though, that while we welcome community feedback, the design of +Sass is ultimately in the hands of the language team. We'll absolutely consider +the perspectives and use-cases of users who speak up, but it's also our job to +consider all the users who are new to Sass or even to CSS and who don't yet know +to read blogs or comment on issue trackers. Remember that our careful +decision-making made Sass what it is today, and have patience with us if we +don't make the decisions you would have! diff --git a/source/blog/023-module-system-preview.html.md b/source/blog/023-module-system-preview.html.md new file mode 100644 index 000000000..296f9b477 --- /dev/null +++ b/source/blog/023-module-system-preview.html.md @@ -0,0 +1,51 @@ +--- +title: Module System Preview +author: Natalie Weizenbaum +date: 2019-09-04 15:14 PST +--- + +Exciting news, Sass fans! After a year of development and some iteration on the +spec, we're ready to launch a beta preview of the new Sass module system! We may +still make a few last-minute tweaks based on user feedback, so don't go using +itin production just yet, but please do take this opportunity to play around +with it and let us know what you think. + +## Installing the Preview + +The preview release is available on all the normal distribution channels as +version `1.23.0-module.beta.1`. You can download it from the [GitHub release +page](https://github.com/sass/dart-sass/releases/tag/1.23.0-module.beta.1), or +install it using one of the following commands (depending on your preferred +installation channel): + +```shellsession +$ npm install --save-dev sass@1.23.0-module.beta.1 + +$ npm install -g sass@1.23.0-module.beta.1 + +$ brew install sass/sass/sass@1.23.0-module.beta.1 + +$ choco install sass --version 1.23.0.modulebeta-1 + +$ pub global activate sass 1.23.0-module.beta.1 +``` + +Note that 1.23.0 may not *actually* be the final version number for the stable +module system release, it's just the next minor version number in Dart Sass's +release series. + +## How to Use the Module System + +The original [summary of the module +system](/blog/request-for-comments-module-system-proposal) is still a great way +to learn how it works. You can also check out the [official +proposal](https://github.com/sass/sass/blob/master/accepted/module-system.md) +for a much more detailed dive into its behavior. + +## Sending Feedback + +If you have opinions on the module system, please [file an issue on +GitHub](https://github.com/sass/language/issues/new) or just [tweet at +@SassCSS](https://twitter.com/SassCSS). We'll take anything from "it looks +awesome" to "it looks awful", although the more specific you can be the more +information we have to work with! diff --git a/source/blog/024-the-module-system-is-launched.html.md b/source/blog/024-the-module-system-is-launched.html.md new file mode 100644 index 000000000..11461bf06 --- /dev/null +++ b/source/blog/024-the-module-system-is-launched.html.md @@ -0,0 +1,351 @@ +--- +title: The Module System is Launched +author: Natalie Weizenbaum +date: 2019-10-01 18:58 PST +--- + +The Sass team has known for years that the `@import` rule, one of the earliest +additions to Sass, wasn't as good as we wanted it. It caused a litany of +problems for our users: + +* It was next to impossible to figure out where a given variable, mixin, or + function (collectively called "members") was originally defined, since + anything defined in one stylesheet was available to all stylesheets that were + imported after it. + +* Even if you chose to explicitly import every stylesheet that defined members + you used, you'd end up with duplicate CSS and strange side-effects, because + stylesheets were reloaded from scratch every time they were imported. + +* It wasn't safe to use terse and simple names because there was always a + possibility that some other stylesheet elsewhere in your application would use + the same name and mess up your logic. To be safe users had to manually add + long, awkward namespaces to everything they defined. + +* Library authors had no way to ensure that their private helpers wouldn't be + accessed by downstream users, causing confusion and backwards-compatibility + headaches. + +* The [`@extend` rule][] could affect any selector anywhere in the stylesheet, + not just those that its author explicitly chose to extend. + + [`@extend` rule]: /documentation/at-rules/extend + +We also knew that any replacement we wanted to introduce would have to be +designed and developed with the utmost care to ensure it would provide a +rock-solid foundation for the future of Sass development. Over the past few +years, we've discussed, designed, and developed a brand-new module system that +solves these problems and more, and today we're excited to announce that it's +available in Dart Sass 1.23.0. + +Please note that the module system is *fully backwards-compatible*. No existing +features have been removed or deprecated, and your current Sass stylesheets will +keep working just as they always have. We designed the module system to be +[fully interoperable with `@import`](#import-compatibility) to make it easy for +stylesheet authors to migrate to it incrementally. We do plan to [eventually get +rid of `@import`](#future-plans), but not until long after everyone's had a +chance to migrate. + +## `@use`, the Heart of the Module System + +The [`@use` rule][] is the primary replacement for `@import`: it makes CSS, +variables, mixins, and functions from another stylesheet accessible in the +current stylesheet. By default, variables, mixins, and functions are available +in a namespace based on the basename of the URL. + +[`@use` rule]: /documentation/at-rules/use + +```scss +@use "bootstrap"; + +.element { + background-color: bootstrap.$body-bg; + @include bootstrap.float-left; +} +``` + +In addition to namespacing, there are a few important differences between `@use` +and `@import`: + +* `@use` only executes a stylesheet and includes its CSS once, no matter how + many times that stylesheet is used. +* `@use` only makes names available in the current stylesheet, as opposed to globally. +* Members whose names begin with `-` or `_` are private to the current + stylesheet with `@use`. +* If a stylesheet includes `@extend`, that extension is only applied to + stylesheets it imports, not stylesheets that import it. + +Note that placeholder selectors are *not* namespaced, but they *do* respect +privacy. + +### Controlling Namespaces + +Although a `@use` rule's default namespace is determined by the basename of its +URL, it can also be set explicitly using `as`. + +```scss +@use "bootstrap" as b; + +.element { + @include b.float-left; +} +``` + +The special construct `as *` can also be used to include everything in the +top-level namespace. Note that if multiple modules expose members with the same +name and are used with `as *`, Sass will produce an error. + +```scss +@use "bootstrap" as *; + +.element { + @include float-left; +} +``` + +#### Configuring Libraries + +With `@import`, libraries are often configured by setting global variables that +override `!default` variables defined by those libraries. Because variables are +no longer global with `@use`, it supports a more explicit way of configuring +libraries: the `with` clause. + +```scss +// bootstrap.scss +$paragraph-margin-bottom: 1rem !default; + +p { + margin-top: 0; + margin-bottom: $paragraph-margin-bottom; +} +``` + +```scss +@use "bootstrap" with ( + $paragraph-margin-bottom: 1.2rem +); +``` + +This sets bootstrap's `$paragraph-margin-bottom` variable to `1.2rem` before +evaluating it. The `with` clause only allows variables defined in (or forwarded +by) the module being imported, and only if they're defined with `!default`, so +users are protected against typos. + +## `@forward`, for Library Authors + +The [`@forward` rule][] includes another module's variables, mixins, and +functions as part of the API exposed by the current module, without making them +visible to code within the current module. It allows library authors to be able +to split up their library among many different source files without sacrificing +locality within those files. Unlike `@use`, forward doesn't add any namespaces +to names. + +[`@forward` rule]: /documentation/at-rules/forward + +```scss +// bootstrap.scss +@forward "functions"; +@forward "variables"; +@forward "mixins"; +``` + +### Visibility Controls + +A `@forward` rule can choose to show only specific names: + +```scss +@forward "functions" show color-yiq; +``` + +It can also hide names that are intended to be library-private: + +```scss +@forward "functions" hide assert-ascending; +``` + +### Extra Prefixing + +If you forward a child module through an all-in-one module, you may want to add +some manual namespacing to that module. You can do what with the `as` clause, +which adds a prefix to every member name that's forwarded: + +```scss +// material/_index.scss +@forward "theme" as theme-*; +``` + +This way users can use the all-in-one module with well-scoped names for theme +variables: + +```scss +@use "material" with ($theme-primary: blue); +``` + +or they can use the child module with simpler names: + +```scss +@use "material/theme" with ($primary: blue); +``` + +## Built-In Modules + +The new module system also adds [built-in modules](/documentation/modules) +(`sass:math`, `sass:color`, `sass:string`, `sass:list`, `sass:map`, +`sass:selector`, and `sass:meta`) to hold all the existing built-in Sass +functions. Because these modules will (typically) be imported with a namespace, +it's now much easier to use Sass functions without running into conflicts with +plain CSS functions. + +This in turn makes it much safer for Sass to add new functions. We expect to add a number of convenience functions to these modules in the future. + +### Renamed Functions + +Some functions have different names in the built-in modules than they did as +global functions. Built-in functions that already had manual namespaces, like +[`map-get()`](/documentation/modules/map#get), have those namespaces removed in +the built-in modules so you can just write `map.get()`. Similarly, +[`adjust-color()`](/documentation/modules/color#adjust), +[`scale-color()`](/documentation/modules/color#scale), and +[`change-color()`](/documentation/modules/color#change) are now +`color.adjust()`, `color.scale()`, and `color.change()`. + +We've also taken this opportunity to change a couple confusing old function +names. [`unitless()`](/documentation/modules/math#unitless) is now +`math.is-unitless()`, and +[`comparable()`](/documentation/modules/math#compatible) is now +`math.compatible()`. + +### Removed Functions + +Sass's shorthand color functions `lighten()`, `darken()`, `saturate()`, +`desaturate()`, `opacify()`, `fade-in()`, `transparentize()`, and `fade-out()` +all had very unintuitive behavior. Rather than scaling their associated +attributes fluidly, they just incremented them by a static amount, so that +`lighten($color, 20%)` would return `white` for a color with `85%` lightness +rather than returning a color with `88%` lightness (`20%` closer to full white). + +To help set us on the path towards fixing this, these functions (along with +`adjust-hue()`) aren't included in the new built-in modules. You can still get +the same effect by calling +[`color.adjust()`](/documentation/modules/color#adjust)—for example, +`lighten($color, $amount)` is equivalent to `color.adjust($color, $lightness: +$amount)`—but we recommend trying to use +[`color.scale()`](/documentation/modules/color#scale) instead if possible +because of how much more intuitive it is. + +At some point in the future, we plan to add `color.lighten()` and similar +functions as shorthands for `color.scale()`. + +### `meta.load-css()` + +The new module system comes with a new built-in mixin, [`meta.load-css($url, +$with: ())`](/documentation/modules/meta#load-css). This mixin dynamically loads +the module with the given URL and includes its CSS (although its functions, +variables, and mixins are not made available). This is a replacement for nested +imports, and it helps address some use-cases of dynamic imports without many of +the problems that would arise if new members could be loaded dynamically. + +## `@import` Compatibility + +The Sass ecosystem won't switch to `@use` overnight, so in the meantime it needs +to [interoperate well with +`@import`](/documentation/at-rules/import#import-and-modules). +This is supported in both directions: + +* When a file that contains `@import`s is `@use`d, everything in its global + namespace is treated as a single module. This module's members are then + referred to using its namespace as normal. + +* When a file that contains `@use`s is `@import`ed, everything in its public API + is added to the importing stylesheet's global scope. This allows a library to + control what specific names it exports, even for users who `@import` it rather + than `@use` it. + +In order to allow libraries to maintain their existing `@import`-oriented API, +with explicit namespacing where necessary, this proposal also adds support for +files that are only visible to `@import`, not to `@use`. They're written +`"file.import.scss"`, and imported when the user writes `@import "file"`. + +## Automatic Migration + +Concurrent with the launch of the new module system, we're launching a new +[automated Sass migrator](/documentation/cli/migrator). This tool makes it easy +to migrate most stylesheets to use the new module system automatically. Follow +the instructions on [the Sass website](/documentation/cli/migrator#installation) +to install it, then run it on your application: + +```shellsession +$ sass-migrator module --migrate-deps +``` + +The [`--migrate-deps` flag](/documentation/cli/migrator#migrate-deps) tells the +migrator to migrate not only the file you pass, but anything it imports as well. +The migrator will automatically pick up files imported through [Webpack's +`node_modules` +syntax](https://github.com/webpack-contrib/sass-loader#resolving-import-at-rules), +but you can also pass explicit load paths with the [`--load-path` +flag](/documentation/cli/migrator#load-path). + +If you want the migrator to tell you what changes it would make without actually +making them, pass both the [`--dry-run` +flag](/documentation/cli/migrator#dry-run) and the [`--verbose` +flag](/documentation/cli/migrator#verbose) to tell it to just print out the +changes it would make without saving them to disk. + +### Migrating a Library + +If you want to migrate a Sass library that's meant for downstream users to load +and use, run: + +```shellsession +$ sass-migrator module --migrate-deps --forward=all +``` + +The [`--forward` flag](/documentation/cli/migrator#forward) tells the migrator +to add [`@forward` rules](/documentation/at-rules/forward) so that users can +still load all the mixins, variables, and functions your library defines with a +single `@use`. + +If you added a manual namespace to your library to avoid name conflicts, the +migrator will remove it for you if you pass the [`--remove-prefix` +flag](/documentation/cli/migrator#remove-prefix). You can even choose to only +forward members that originally had that prefix by passing `--forward=prefixed`. + +### Filing Issues + +The migration tool is brand new, so it may still have some rough edges. If you +run into any problems, please don't hesitate to [file an issue on +GitHub](https://github.com/sass/migrator/issues/new)! + +## Try It Now! + +The module system is available as part of Dart Sass 1.23.0. You can install it +right now using: + +```shellsession +$ npm install -g sass +``` + +Alternately, check out [the installation page](/install) for all the different +ways it can be installed! + +## Future Plans + +The Sass team wants to allow for a large amount of time when `@use` and +`@import` can coexist, to help the ecosystem smoothly migrate to the new system. +However, doing away with `@import` entirely is the ultimate goal for simplicity, +performance, and CSS compatibility. As such, we plan to gradually turn down +support for `@import` on the following timeline: + +- One year after both Dart Sass and LibSass have launched support for the + module system _or_ two years after Dart Sass launches support for the module + system, whichever comes sooner (**1 October 2021** at latest), we will + deprecate `@import` as well as global core library function calls that could + be made through modules. + +- One year after this deprecation goes into effect (**1 October 2022** at + latest), we will drop support for `@import` and most global functions + entirely. This will involve a major version release for all implementations. + +This means that there will be at least two full years when `@import` and `@use` +are both usable at once, and likely closer to three years in practice. diff --git a/source/documentation/cli/ruby-sass.html.md.erb b/source/documentation/cli/ruby-sass.html.md.erb index 0de20b3f2..154f5486a 100644 --- a/source/documentation/cli/ruby-sass.html.md.erb +++ b/source/documentation/cli/ruby-sass.html.md.erb @@ -8,7 +8,7 @@ table_of_contents: true [Ruby Sass has reached end of life][] and is now totally unmaintained. Please switch to [Dart Sass][] or [LibSass][] at your earliest convenience. -[Ruby Sass has reached end of life]: /blog/posts/7828841-ruby-sass-is-unsupported +[Ruby Sass has reached end of life]: /blog/ruby-sass-is-unsupported [Dart Sass]: /dart-sass [LibSass]: /libsass <% end %> diff --git a/source/feed.xml.builder b/source/feed.xml.builder new file mode 100644 index 000000000..3ec08eee0 --- /dev/null +++ b/source/feed.xml.builder @@ -0,0 +1,22 @@ +xml.instruct! +xml.feed xmlns: "http://www.w3.org/2005/Atom" do + blog_url = "#{config[:host]}/blog" + xml.title "Sass Blog" + xml.id blog_url + xml.link href: blog_url + xml.link href: "#{config[:host]}/feed.xml", rel: "self" + xml.updated(blog.articles.first.date.to_time.iso8601) unless blog.articles.empty? + + blog.articles[0..5].each do |article| + xml.entry do + url = config[:host] + without_html(article.url) + xml.title article.title + xml.link href: url, rel: "alternate" + xml.id url + xml.published article.date.to_time.iso8601 + xml.updated File.mtime(article.source_file).iso8601 + xml.author { xml.name article.data.author } + xml.content article.body, "type" => "html" + end + end +end diff --git a/source/layouts/blog.haml b/source/layouts/blog.haml new file mode 100644 index 000000000..e9ba932b9 --- /dev/null +++ b/source/layouts/blog.haml @@ -0,0 +1,3 @@ += wrap_layout :layout do + = partial 'layouts/components/attribution', locals: {page: current_page} + = Typogruby.improve(yield) diff --git a/source/layouts/components/_attribution.haml b/source/layouts/components/_attribution.haml new file mode 100644 index 000000000..26baf735f --- /dev/null +++ b/source/layouts/components/_attribution.haml @@ -0,0 +1 @@ +%p.sl-c-attribution Posted #{page.date.strftime('%e %B %Y')} by #{page.data.author} diff --git a/source/layouts/layout.haml b/source/layouts/layout.haml index d27b4ee50..bb68ce3bf 100644 --- a/source/layouts/layout.haml +++ b/source/layouts/layout.haml @@ -6,6 +6,7 @@ %title= page_title %meta(name='description' content='Syntatically Awesome Style Sheets') %meta(name='viewport' content='width=device-width, initial-scale=1') + %link(rel="alternate" type="application/atom+xml" href="/feed.xml") = stylesheet_link_tag 'https://fonts.googleapis.com/css?family=Source+Code+Pro|Source+Sans+Pro:300,400,600|Source+Serif+Pro' = stylesheet_link_tag 'https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css' @@ -51,7 +52,7 @@ %p %strong Sass just launched a brand new module system. = succeed '!' do - = link_to '/blog/posts/7858341-the-module-system-is-launched' do + = link_to '/blog/the-module-system-is-launched' do Learn all about it on the Sass blog .sl-c-pop-stripe @@ -67,7 +68,7 @@ :markdown - [Install](/install) - [Learn Sass](/guide) - - [Blog](http://blog.sass-lang.com/) + - [Blog](/blog) - [Documentation](/documentation) - [Get Involved](/community) -