From 47db80d6f8e99abd7e10609b3d87a7c1ccf011bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 7 Aug 2017 18:04:25 +0200 Subject: [PATCH] [docs] Add css style guide section on open/closed principle (#12276) --- style_guides/css_style_guide.md | 115 ++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/style_guides/css_style_guide.md b/style_guides/css_style_guide.md index 61822d3217e3..9c4cd6799a0c 100644 --- a/style_guides/css_style_guide.md +++ b/style_guides/css_style_guide.md @@ -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 +
+
+
+ Card Description +
+
+
+``` + +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.