Skip to content

Commit 807a755

Browse files
committed
Merge pull request airbnb#8 from lencioni/deprecate-extend
Advise against @extend, enable SCSS-lint ExtendDirective
2 parents bf1e947 + 9392e24 commit 807a755

File tree

2 files changed

+13
-62
lines changed

2 files changed

+13
-62
lines changed

.scss-lint.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ linters:
1010
DeclarationOrder:
1111
enabled: false
1212

13+
ExtendDirective:
14+
enabled: true
15+
1316
LeadingZero:
1417
enabled: false
1518

README.md

Lines changed: 10 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
- [Syntax](#syntax)
1919
- [Ordering](#ordering-of-property-declarations)
2020
- [Mixins](#mixins)
21-
- [Placeholders](#placeholders)
21+
- [Extend directive](#extend-directive)
2222
- [Nested selectors](#nested-selectors)
2323

2424
## Terminology
@@ -174,55 +174,41 @@ We recommend creating JavaScript-specific classes to bind to, prefixed with `.js
174174
### Syntax
175175

176176
* Use the `.scss` syntax, never the original `.sass` syntax
177-
* Order your `@extend`, regular CSS and `@include` declarations logically (see below)
177+
* Order your regular CSS and `@include` declarations logically (see below)
178178

179179
### Ordering of property declarations
180180

181-
1. `@extend` declarations
181+
1. Property declarations
182182

183-
Just as in other OOP languages, it's helpful to know right away that this “class” inherits from another.
183+
List all standard property declarations, anything that isn't an `@include` or a nested selector.
184184

185185
```scss
186186
.btn-green {
187-
@extend %btn;
188-
// ...
189-
}
190-
```
191-
192-
2. Property declarations
193-
194-
Now list all standard property declarations, anything that isn't an `@extend`, `@include`, or a nested selector.
195-
196-
```scss
197-
.btn-green {
198-
@extend %btn;
199187
background: green;
200188
font-weight: bold;
201189
// ...
202190
}
203191
```
204192

205-
3. `@include` declarations
193+
2. `@include` declarations
206194

207-
Grouping `@include`s at the end makes it easier to read the entire selector, and it also visually separates them from `@extend`s.
195+
Grouping `@include`s at the end makes it easier to read the entire selector.
208196

209197
```scss
210198
.btn-green {
211-
@extend %btn;
212199
background: green;
213200
font-weight: bold;
214201
@include transition(background 0.5s ease);
215202
// ...
216203
}
217204
```
218205

219-
4. Nested selectors
206+
3. Nested selectors
220207

221208
Nested selectors, _if necessary_, go last, and nothing goes after them. Add whitespace between your rule declarations and nested selectors, as well as between adjacent nested selectors. Apply the same guidelines as above to your nested selectors.
222209

223210
```scss
224211
.btn {
225-
@extend %btn;
226212
background: green;
227213
font-weight: bold;
228214
@include transition(background 0.5s ease);
@@ -235,49 +221,11 @@ We recommend creating JavaScript-specific classes to bind to, prefixed with `.js
235221

236222
### Mixins
237223

238-
Mixins, defined via `@mixin` and called with `@include`, should be used sparingly and only when function arguments are necessary. A mixin without function arguments (i.e. `@mixin hide { display: none; }`) is better accomplished using a placeholder selector (see below) in order to prevent code duplication.
239-
240-
### Placeholders
241-
242-
Placeholders in Sass, defined via `%selector` and used with `@extend`, are a way of defining rule declarations that aren't automatically output in your compiled stylesheet. Instead, other selectors “inherit” from the placeholder, and the relevant selectors are copied to the point in the stylesheet where the placeholder is defined. This is best illustrated with the example below.
243-
244-
Placeholders are powerful but easy to abuse, especially when combined with nested selectors. **As a rule of thumb, avoid creating placeholders with nested rule declarations, or calling `@extend` inside nested selectors.** Placeholders are great for simple inheritance, but can easily result in the accidental creation of additional selectors without paying close attention to how and where they are used.
245-
246-
**Sass**
247-
248-
```sass
249-
// Unless we call `@extend %icon` these properties won't be compiled!
250-
%icon {
251-
font-family: "Airglyphs";
252-
}
224+
Mixins should be used to DRY up your code, add clarity, or abstract complexity--in much the same way as well-named functions. Mixins that accept no arguments can be useful for this, but note that if you are not compressing your payload (e.g. gzip), this may contribute to unnecessary code duplication in the resulting styles.
253225

254-
.icon-error {
255-
@extend %icon;
256-
color: red;
257-
}
226+
### Extend directive
258227

259-
.icon-success {
260-
@extend %icon;
261-
color: green;
262-
}
263-
```
264-
265-
**CSS**
266-
267-
```css
268-
.icon-error,
269-
.icon-success {
270-
font-family: "Airglyphs";
271-
}
272-
273-
.icon-error {
274-
color: red;
275-
}
276-
277-
.icon-success {
278-
color: green;
279-
}
280-
```
228+
`@extend` should be avoided because it has unintuitive and potentially dangerous behavior, especially when used with nested selectors. Even extending top-level placeholder selectors can cause problems if the order of selectors ends up changing later (e.g. if they are in other files and the order the files are loaded shifts). Gzipping should handle most of the savings you would have gained by using `@extend`, and you can DRY up your stylesheets nicely with mixins.
281229

282230
### Nested selectors
283231

0 commit comments

Comments
 (0)