Skip to content

Commit

Permalink
[6.x] [docs] Add css style guide section on open/closed principle
Browse files Browse the repository at this point in the history
Backports PR elastic#12276
  • Loading branch information
weltenwort committed Aug 7, 2017
1 parent 679d8ad commit da90d03
Showing 1 changed file with 115 additions and 0 deletions.
115 changes: 115 additions & 0 deletions style_guides/css_style_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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.

0 comments on commit da90d03

Please sign in to comment.