[docs] Add css style guide section on open/closed principle (#12276)

This commit is contained in:
Felix Stürmer 2017-08-07 18:04:25 +02:00 committed by GitHub
parent 8cfbb82cfb
commit 47db80d6f8

View file

@ -15,6 +15,7 @@
- [Don't use multiple modifier classes together](#dont-use-multiple-modifier-classes-together)
- [How to apply DRY](#how-to-apply-dry)
- [Compelling reasons for using mixins](#compelling-reasons-for-using-mixins)
- [The Open/Closed Principle](#the-openclosed-principle)
## Selecting elements
@ -103,6 +104,8 @@ Our CSS naming convention is based on BEM:
* [BEM 101 (CSS Tricks)](https://css-tricks.com/bem-101/)
* [Getting your head around BEM syntax (CSS Wizardry)](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/)
* [CSS for BEM (bem.info)](https://en.bem.info/methodology/css/)
* [CSS Guidelines](https://cssguidelin.es/)
## Concepts
@ -461,3 +464,115 @@ border-radius changes for all buttons, you only need to change it there. Or if
the designers anticipate that all new types of buttons should have the same
border-radius, then you can just extend this mixin when you create a new button
base class.
### The Open/Closed Principle
References:
* [The Open/Closed Principle on bem.info](https://en.bem.info/methodology/css/#openclosed-principle)
* [The Open/Closed Principle in CSS Guidelines](https://cssguidelin.es/#the-openclosed-principle)
* [The Open/Closed Principle on Wikipedia](https://en.wikipedia.org/wiki/Open/closed_principle)
Formally the open/closed principle reads
> Software entities (classes, modules, functions, etc.) should be **open for
> extension**, but **closed for modification**.
Applied to CSS, this means that CSS rulesets should be treated as immutable.
Once a declaration block for a specific selector has been defined, its style
should not be overridden in a different ruleset using the same selector:
```css
// BAD
.button {
color: blue;
font-size: 1.5em;
padding: 16px;
}
.header .button {
font-size: 1em;
padding: 4px;
}
```
Not only does this example violate the semantics of a BEM block, it also
**modifies** the meaning of `.button` depending on the context. Instead, this
could be expressed using a block modifier or a completely separate class which
is kept DRY using mixins:
```css
// GOOD
.button {
color: blue;
font-size: 1.5em;
}
.button--small {
font-size: 1em;
padding: 4px;
}
```
#### Exception: Block Groups
It is a common occurrence that groups of blocks within a container should be
styled differently that single blocks in order to indicate their association.
But using pure BEM mixes of blocks and group modifiers would sometimes require
a large number of modifiers to be applied to multiple elements to achieve that,
e.g.:
```css
.kuiCard { /* ... */ }
.kuiCard__description { /* ... */ }
.kuiCardGroup { /* ... */ }
.kuiCardGroup__card { /* ... */ }
.kuiCardGroup__cardDescription { /* ... */ }
```
```html
<div class="kuiCardGroup">
<div class="kuiCard kuiCardGroup__card">
<div class="kuiCard__description kuiCardGroup__cardDescription">
Card Description
</div>
</div>
</div>
```
To avoid the combinatorial explosion of classes with such groupings and thier
modifiers, it is permissible to nest a block's selector under another block's
selector if:
* The relationship is of a very narrow "`element` to `elementGroup`" kind that
is apparent from the block names.
* The rulesets are colocated in the same component directory.
```css
.kuiCard { /* ... */ }
.kuiCard__description { /* ... */ }
.kuiCardGroup { /* ... */ }
.kuiCardGroup .kuiCard { /* ... */ }
.kuiCardGroup .kuiCard__description { /* ... */ }
```
#### Exception: Normalization/Reset
We cannot control the selectors introduced by third-party stylesheets and these
selectors may not adhere to our styleguide, e.g. `a` or `input[type="text"]`.
In these cases, we are forced to duplicate these selectors within our own
stylesheets and override those styles to control their look and feel.
When this happens, it is important to add comments that make it clear why these
selectors exist and which third-party dependencies they override. We should
also define these selectors in files which refer back to the dependency, e.g. a
file named `ui_select_overrides.less` will contain styles overriding those
introduced by the `ui-select` dependency.