|
| 1 | +--- |
| 2 | +title: "Breaking Change: Strict Function Units" |
| 3 | +introduction: > |
| 4 | + Various built-in functions will become stricter in which units they allow |
| 5 | + and will handle those units more consistently. This makes Sass more compatible |
| 6 | + with the CSS spec and helps catch errors more quickly. |
| 7 | +--- |
| 8 | + |
| 9 | +## Hue |
| 10 | + |
| 11 | +<% impl_status dart: '1.32.0', libsass: false, ruby: false %> |
| 12 | + |
| 13 | +When specifying a color's hue, CSS allows any [angle unit][] (`deg`, `grad`, |
| 14 | +`rad`, or `turn`). It also allows a unitless number, which is interpreted as |
| 15 | +`deg`. Historically, Sass has allowed *any* unit, and interpreted it as `deg`. |
| 16 | +This is particularly problematic because it meant that the valid CSS expression |
| 17 | +`hsl(0.5turn, 100%, 50%)` would be allowed by Sass but interpreted entirely |
| 18 | +wrong. |
| 19 | + |
| 20 | +[angle unit]: https://drafts.csswg.org/css-values-4/#angles |
| 21 | + |
| 22 | +To fix this issue and bring Sass in line with the CSS spec, we're making changes |
| 23 | +in multiple phases: |
| 24 | + |
| 25 | +### Phase 1 |
| 26 | + |
| 27 | +<% impl_status dart: '1.32.0', libsass: false, ruby: false %> |
| 28 | + |
| 29 | +At first, Sass just emitted a deprecation warning if you passed a number with a |
| 30 | +unit other than `deg` as a hue to any function. Passing a unitless number is |
| 31 | +still allowed. |
| 32 | + |
| 33 | +### Phase 2 |
| 34 | + |
| 35 | +<% impl_status dart: '1.52.1', libsass: false, ruby: false %> |
| 36 | + |
| 37 | +Next, we changed the way angle units are handled for hue parameters to match the |
| 38 | +CSS spec. This means that numbers with `grad`, `rad`, or `turn` units will be |
| 39 | +converted to `deg`: `0.5turn` will be converted to `180deg`, `100grad` will be |
| 40 | +converted to `90deg`, and so on. |
| 41 | + |
| 42 | +Because this change is necessary to preserve CSS compatibility, according to the |
| 43 | +[Dart Sass compatibility policy] it was made with only a minor version bump. |
| 44 | +However, it changes as little behavior as possible to ensure that Sass |
| 45 | +interprets all valid CSS according to the CSS spec. |
| 46 | + |
| 47 | +[Dart Sass compatibility policy]: https://github.com/sass/dart-sass#compatibility-policy |
| 48 | + |
| 49 | +### Phase 3 |
| 50 | + |
| 51 | +<% impl_status dart: false, libsass: false, ruby: false %> |
| 52 | + |
| 53 | +Finally, in Dart Sass 2.0.0 color functions will throw errors if they're passed |
| 54 | +a hue parameter with a non-angle unit. Unitless hues will still be allowed. |
| 55 | + |
| 56 | +## Saturation and Lightness |
| 57 | + |
| 58 | +When specifying an HSL color's saturation and lightness, CSS only allows `%` |
| 59 | +units. Even unitless numbers aren't allowed (unlike for the hue). Historically, |
| 60 | +Sass has allowed *any* unit, and interpreted it as `%`. You could even write |
| 61 | +`hsl(0, 100px, 50s)` and Sass would return the color `red`. |
| 62 | + |
| 63 | +To fix this issue and bring Sass in line with the CSS spec, we're making changes |
| 64 | +in two phases: |
| 65 | + |
| 66 | +### Phase 1 |
| 67 | + |
| 68 | +<% impl_status dart: '1.32.0', libsass: false, ruby: false %> |
| 69 | + |
| 70 | +Currently, Sass just emits a deprecation warning if you pass a number with no |
| 71 | +unit or a unit other than `%` as a lightness or saturation to any function. |
| 72 | + |
| 73 | +### Phase 2 |
| 74 | + |
| 75 | +<% impl_status dart: false, libsass: false, ruby: false %> |
| 76 | + |
| 77 | +In Dart Sass 2.0.0 color functions will throw errors if they're passed a |
| 78 | +saturation or lightness parameter with no unit or a non-`%` unit. |
| 79 | + |
| 80 | +## Alpha |
| 81 | + |
| 82 | +When specifying a color's alpha value, CSS (as of [Colors Level 4]) allows |
| 83 | +either unitless values between 0 and 1 or `%` values between `0%` and `100%`. In |
| 84 | +most cases Sass follows this behavior, but the functions `color.adjust()` and |
| 85 | +`color.change()` have historically allowed *any* unit, and interpreted it as |
| 86 | +unitless. You could even write `color.change(red, $alpha: 1%)` and Sass would |
| 87 | +return the opaque color `black`. |
| 88 | + |
| 89 | +[Colors Level 4]: https://www.w3.org/TR/css-color-4/#typedef-alpha-value |
| 90 | + |
| 91 | +To fix this issue and bring Sass in line with the CSS spec, we're making changes |
| 92 | +in three phases: |
| 93 | + |
| 94 | +### Phase 1 |
| 95 | + |
| 96 | +<% impl_status dart: '1.56.0', libsass: false, ruby: false %> |
| 97 | + |
| 98 | +Currently, Sass just emits a deprecation warning if you pass a number with any |
| 99 | +unit, including `%`, as an alpha value to `color.change()` or `color.adjust()`. |
| 100 | + |
| 101 | +### Phase 2 |
| 102 | + |
| 103 | +<% impl_status dart: false, libsass: false, ruby: false %> |
| 104 | + |
| 105 | +Next, we'll change the way `%` units are handled for the alpha argument to |
| 106 | +`color.change()` and `color.adjust()`. Alphas with unit `%` will be divided by |
| 107 | +`100%`, converting them to unitless numbers between 0 and 1. |
| 108 | + |
| 109 | +Because this change is a bug fix that improves consistency with other Sass |
| 110 | +functions, it will be made with only a minor version bump. It will be changed at |
| 111 | +minimum three months after Phase 1 is released, to give users time to adjust |
| 112 | +their code and avoid the bug. |
| 113 | + |
| 114 | +[Dart Sass compatibility policy]: https://github.com/sass/dart-sass#compatibility-policy |
| 115 | + |
| 116 | +### Phase 3 |
| 117 | + |
| 118 | +<% impl_status dart: false, libsass: false, ruby: false %> |
| 119 | + |
| 120 | +Finally, in Dart Sass 2.0.0 `color.change()` and `color.adjust()` will throw |
| 121 | +errors if they're passed an alpha parameter with a non-`%` unit. Unitless alphas |
| 122 | +will still be allowed. |
| 123 | + |
| 124 | +## `math.random()` |
| 125 | + |
| 126 | +[The `math.random()` function] has historically ignored units in `$limit` and |
| 127 | +returned a unitless value. For example `math.random(100px)` would drop "px" and |
| 128 | +return a value like `42`. |
| 129 | + |
| 130 | +A future version of Sass will stop ignoring units for the `$limit` argument and |
| 131 | +return a random integer with the same units. |
| 132 | + |
| 133 | +[The `math.random()` function]: ../modules/math#random |
| 134 | + |
| 135 | +<% example(autogen_css: false) do %> |
| 136 | + // Future Sass, doesn't work yet! |
| 137 | + @debug math.random(100px); // 42px |
| 138 | + === |
| 139 | + // Future Sass, doesn't work yet! |
| 140 | + @debug math.random(100px) // 42px |
| 141 | +<% end %> |
| 142 | + |
| 143 | +### Phase 1 |
| 144 | + |
| 145 | +<% impl_status dart: '1.54.5', libsass: false, ruby: false %> |
| 146 | + |
| 147 | +Currently, Sass emits a deprecation warning if you pass a `$limit` with units to |
| 148 | +`math.random()`. |
| 149 | + |
| 150 | +### Phase 2 |
| 151 | + |
| 152 | +<% impl_status dart: false, libsass: false, ruby: false %> |
| 153 | + |
| 154 | +In Dart Sass 2.0.0, passing a `$limit` number with units will be an error. |
| 155 | + |
| 156 | +### Phase 3 |
| 157 | + |
| 158 | +<% impl_status dart: false, libsass: false, ruby: false %> |
| 159 | + |
| 160 | +In a minor release after Dart Sass 2.0.0, passing a `$limit` number with units |
| 161 | +to the `math.random()` function will be allowed again. It will return a random |
| 162 | +integer the same units as `$limit`, instead of a unitless number. |
| 163 | + |
| 164 | +## Weight |
| 165 | + |
| 166 | +The [`color.mix()` function] and [`color.invert()` function] have both |
| 167 | +historically ignored units in their `$weight` arguments, despite that argument |
| 168 | +conceptually representing a percentage. A future version of Sass will require |
| 169 | +the unit `%`. |
| 170 | + |
| 171 | +[`color.mix()` function]: ../modules/color#mix |
| 172 | +[`color.invert()` function]: ../modules/color#invert |
| 173 | + |
| 174 | +### Phase 1 |
| 175 | + |
| 176 | +<% impl_status dart: '1.56.0', libsass: false, ruby: false %> |
| 177 | + |
| 178 | +Currently, Sass emits a deprecation warning if you pass a `$weight` with no |
| 179 | +units or with units other than `%` to `color.mix()` or `color.invert()`. |
| 180 | + |
| 181 | +### Phase 2 |
| 182 | + |
| 183 | +<% impl_status dart: false, libsass: false, ruby: false %> |
| 184 | + |
| 185 | +In Dart Sass 2.0.0, `color.mix()` and `color.invert()` will throw errors if |
| 186 | +they're passed a `$weight` with no unit or a non-`%` unit. |
| 187 | + |
| 188 | +## Index |
| 189 | + |
| 190 | +The [`list.nth()` function] and [`list.set-nth()` function] have both |
| 191 | +historically ignored units in their `$n` arguments. A future version of Sass |
| 192 | +will forbid any units. |
| 193 | + |
| 194 | +[`list.nth()` function]: ../modules/list#nth |
| 195 | +[`list.set-nth()` function]: ../modules/list#set-nth |
| 196 | + |
| 197 | +### Phase 1 |
| 198 | + |
| 199 | +<% impl_status dart: '1.56.0', libsass: false, ruby: false %> |
| 200 | + |
| 201 | +Currently, Sass emits a deprecation warning if you pass a `$weight` with no |
| 202 | +units or with units other than `%` to `color.mix()` or `color.invert()`. |
| 203 | + |
| 204 | +### Phase 2 |
| 205 | + |
| 206 | +<% impl_status dart: false, libsass: false, ruby: false %> |
| 207 | + |
| 208 | +In Dart Sass 2.0.0, `list.nth()` and `list.set-nth()` will throw errors if |
| 209 | +they're passed an index `$n` with a unit. |
0 commit comments