From 5f11cdbe4d082982d06b7aa1593e2af2aef7bbb2 Mon Sep 17 00:00:00 2001 From: Sonja Date: Thu, 26 Apr 2018 13:26:19 -0700 Subject: [PATCH 1/4] =?UTF-8?q?DESKTOP-129:=20=E2=9C=A8=20=20add=20respons?= =?UTF-8?q?ive=20best=20practices=20to=20code=20style=20and=20tidy-up=20ol?= =?UTF-8?q?der=20writing.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/class-naming-conventions/readme.md | 35 ++++---- css/css-best-practices/readme.md | 80 ++++++++++++----- css/introduction/readme.md | 25 ++---- .../readme.md | 53 ++++++----- css/sass-best-practices/readme.md | 89 ++++++++----------- 5 files changed, 144 insertions(+), 138 deletions(-) diff --git a/css/class-naming-conventions/readme.md b/css/class-naming-conventions/readme.md index 055eb70..9537e07 100644 --- a/css/class-naming-conventions/readme.md +++ b/css/class-naming-conventions/readme.md @@ -43,17 +43,17 @@ Our CSS class naming convention (which we call CSM or Component, Sub-Component, ``` -This example may seem confusing at first but if we break down each of the selectors that we have, it begins to make more sense. +This example may seem confusing at first, but if we break down each of the selectors that we have, it begins to make more sense. `.c-blog` This is a high-level component. In this example, it describes a wrapper that may contain blog content. -`.c-blog__title` This is a sub-component. In this example, it is a title for a blog. +`.c-blog__title` This is a sub-component. In this example, it's a title for a blog. -`.c-blog-post` This is another high-level component. In this example, it describes the blog post itself. Notice that it is its own component instead of a sub-component of `c-blog` because a blog post does not need to be child of the blog container. This way the component is able to live anywhere. +`.c-blog-post` This is another high-level component. In this example, it describes the blog post itself. Notice that it can be its own component instead of a sub-component of `c-blog` because a blog post does not need to be child of the blog container. This way, the component is able to live anywhere. `c-blog-post.c--featured` This is a modifier. Notice that the `c--featured` class is paired with the component or sub-component it belongs to. In this example, it describes a different way of displaying the `c-blog-post` component. -`.c-blog-post__time` Like before, this is another sub-component this time belonging to the `c-blog-post` component. It is still a sub-component even though it is not a **direct** child of the component. In other words, sub-components are not required to be direct children of its parent component. +`.c-blog-post__time` Like before, this is another sub-component this time belonging to the `c-blog-post` component. It's still a sub-component, even though it is not a **direct** child of the component. In other words, sub-components are not required to be direct children of their parent component. ### Components @@ -70,7 +70,7 @@ Components are independent and self-contained units of UI. Styles belonging to a ### Sub-components -Sub-components are elements that are child to its parent component. The classname should be formatted as such: `c-[parent-component-name]__[sub-component-name]`. Sub-components do not, and should not, have sub-components of their own. If you find you need to write a sub-sub-component, instead just treat it as a sub-component – sub-components are only ever child to the parent component. +Sub-components are elements that are descendants of their parent component. Their classnames should be formatted as such: `c-[parent-component-name]__[sub-component-name]`. Sub-components do not, and should not, have sub-components of their own. If you find you need to write a sub-sub-component, instead just treat it as a sub-component. Like components, these should always live at the root level of a file. Avoid nesting these within the parent component or another sub-component. @@ -103,7 +103,7 @@ Like components, these should always live at the root level of a file. Avoid nes ### Modifiers -Modifiers, as their name suggests, modify components or sub-components. They are always chained to the component or sub-component they belong to. +Modifiers, as their name suggests, modify components or sub-components. They're always chained to the component or sub-component they belong to. * Prefixed with the namespace of the affected element and two dashes (`c--`, `t--`) * Contained to the scope of a single component @@ -292,7 +292,7 @@ Prefix | Purpose | Location | `.m-` (*) | Desktop embedded mobile markup classes: these are classes that we will use if we author Markup that is intended for clients to embed onto their desktop pages, but is for mobile content. | *n/a* | `.js-` | Javascript classes are used exclusively by scripts and should never have CSS styles applied to them. Repeat: **Do NOT** style Javascript classes. | *n/a* -> \* The `m-` class prefix has an old, deprecated use: Mobify Modules. However, Mobify Modules have been replaced with third part plugins, and are treated as third party libraries with their own conventions. +> \* The `m-` class prefix has an old, deprecated use: Mobify Modules. However, Mobify Modules have been replaced with third party plugins, and are treated as third party libraries with their own conventions. ## Components That Style Components @@ -308,9 +308,9 @@ Sometimes there are situations when a component makes use of other components, a ``` -In situations like this it is tempting to just style the icon's class inside of the button. However, this practice is poor and creates tight coupling between the Button and Icon components that shouldn't exist. As a rule of thumb, a component should only know about what it's responsible for; it should be unaware of anything external to itself. Continuing with this example, the Icon is an external component, therefore the Button component should be completely unaware there there is even such thing as icon classes, like `c-icon`. +In situations like this it is tempting to just style the icon's class inside of the button. However, this practice is poor and creates tight coupling between the Button and Icon components that shouldn't exist. As a rule of thumb, a component should only know about what it's responsible for; it shouldn't be aware of anything external to itself. Since Icon is an external component, the Button component should be completely unaware that of `c-icon`. -The solution to this challenge is to instead give the external component a new class that our new component can know about, like `c-button__icon`. By doing it in this way the external Icon component is, for all intents and purposes, being treated as a sub-component of the Button component. This method also has the benefit of being free of any (tight) coupling between the components. Both components can change, be added or removed, without really effecting the other in an unpredictable way. +The solution to this challenge is to instead give the external component a new class that our new component can know about, like `c-button__icon`. This way, the component is treated like a sub-component of Button, and eliminates any tight coupling between the components. Both components can change, be added or removed, without affecting the other in an unpredictable way. So, to summarize... @@ -349,25 +349,22 @@ So, to summarize... ## Parsing vs. Decorating -It's important to understand that we have a few different ways of authoring our CSS, and the way we do this is depends a lot on how we convert the desktop markup for mobile. Ideally, we parse the desktop markup and take full control of the final HTML. However, this isn't always possible, and sometimes we just output the desktop markup as is: untouched, or perhaps partially wrapped in order to control the appearance entirely through CSS. +Ideally, we have total control over the HTML markup of a project. However, sometimes there are engineering requirements that force us to retain client markup, or partially wrap it in a container of our own. -If you find yourself wondering "should I be adding a new class, or should I use the classes from desktop?" consider the following: If we're using their class names, we obviously can't follow our CSM syntax. But that said, sometimes we just have no choice; perhaps there are engineering requirements that force us to retain the markup structure. Under such circumstances, we must stick to the desktop classes. - -Below is laid out some situational advice that should clarify when to use desktop classes and when to author our own. We also talk about ways to adjust the code style when using their class names. +If you find yourself wondering "should I be adding a new class, or should I use the classes from desktop?" consider the following: If we're using their class names, we can't follow our CSM syntax. Here's some advice: ### When to use our class naming convention * When writing your own markup in a template -* When decorating (adding, moving, or wrapping) markup in a View, Parser, Decorator or UI-Script +* When decorating (adding, moving, or wrapping) markup in a View, Parser, Decorator or UI-Script (Adaptive.js) * When adding custom classes to existing markup * When you find yourself using @extend -### When to use their existing selectors +### When to use client selectors * When it's fastest, easiest or most efficient to use their markup than it is to add our own. * When their markup is too inconsistent, or makes parsing too difficult. -* When mobile functionality is tightly coupled to desktop's markup structure. -* When intercepting AJAXed content or content added after a page is too costly, unperformant, or inefficent. +* When functionality is tightly coupled to markup structure. ### How to use their existing selectors in our components @@ -394,7 +391,7 @@ Always component classes should always be structured with our naming conventions Desktop classes can be added inside their parent component, but adding our own classes should be your FIRST approach so as to avoid nesting. -Constantly evaluate your nesting in situation like this. +Constantly evaluate your nesting in situations like this. ```scss // Okay @@ -427,7 +424,7 @@ Constantly evaluate your nesting in situation like this. } ``` -Use their modifiers the same way you would use our modifiers. Chain it to the component or sub-component it directly affects. +Use their modifiers the same way you would use our modifiers. Chain them to the component or sub-component it directly affects. ```scss // Okay diff --git a/css/css-best-practices/readme.md b/css/css-best-practices/readme.md index b105f79..b9f298a 100644 --- a/css/css-best-practices/readme.md +++ b/css/css-best-practices/readme.md @@ -10,6 +10,7 @@ * [A Note On Attribute Selectors](#a-note-on-attribute-selectors) * [Class Naming Convention](#class-naming-convention) * [Self Documenting Selectors](#self-documenting-selectors) +* [Mobile First](#mobile-first) * [Single Direction Rule](#single-direction-rule) * [Name Spacing](#name-spacing) * [Size Units](#size-units) @@ -21,9 +22,7 @@ ## Code Like it's 2020 -Because we use Autoprefixer, we are able to write our code as if all our properties are fully supported. When compiled, Autoprefixer will of course convert any properties that have special requirements as far as compatibility is concerned and add prefixes to them as needed. - -That includes things like Flexbox, CSS3 properties, and many more! This also means that we *should not* be using mixins for prefixing. Remember that Autoprefixer uses data from caniuse.com to determine what will be output — so properties that don't have enough browser support should probably still be avoided (or at least used with extreme caution). +Because we use post-processors, we are able to write our code as if all our properties are fully supported–includeing things like Flexbox, CSS3 properties, and many more! This also means that we *should not* be using mixins for prefixing. ## Selector Specificity @@ -32,32 +31,30 @@ We strive to write performant, portable, selectors whenever possible. In short, To help do that, it might be helpful to know how to measure specificity which [Smashing Magazine has an article just for that](http://www.smashingmagazine.com/2007/07/27/css-specificity-things-you-should-know/)! -### Dos: +### Some Notes: * Use class names for specificity because it improves performance. -* Use the component oriented naming conventions outlined below. -* If you have no other choice and you must select an ID, use the attribute selector instead - -### Do Nots: - * Avoid using IDs. They decrease portability. +* Use the component oriented naming conventions outlined below. * Avoid using tag selectors. They both impact performance and portability. * Never over qualify selectors because it impacts performance. +* If you have no other choice and you must select an ID, use the attribute selector instead + ```scss -// NO +// Instead of: ul.button-group li.button { } -// Yes +// Try: .button-group__button { } -// NO +// Instead of: #something { } -// Yes (Only as a last resort!) +// Try (Only as a last resort!): [id="something"] { } ``` @@ -67,7 +64,7 @@ ul.button-group li.button { A common use case is to target input types. For example `input[type="text"]`. -It's important to realize that the element selector is not necessary here. If you think about it, we are actually increasing the specificity needlessly. Attribute selectors have the same specificity as a class. The above example has the same specificity as `input.someClass` +It's important to realize that the element selector (`input`, in this case) is not necessary here. Using `input` increases the specificity needlessly. Attribute selectors have the same specificity as a class. The above example has the same specificity as `input.someClass` All we really need is `[type="text"]`, because that is sufficient for targeting text inputs. @@ -76,7 +73,7 @@ In summary: *attribute selectors should be used alone*, just like classes. ## Class Naming Convention -We use a modified version of BEM that we call CSM (Component, Sub-component, Modifier). At it's core, it's virtually identical to BEM, but our exact syntax is slightly different. Basically: +We use a modified version of BEM that we call CSM (Component, Sub-component, Modifier). At its core, it's virtually identical to BEM, but our syntax is slightly different. Basically: ``` .c-component @@ -93,14 +90,54 @@ When authoring CSS, you should be always aware of the selectors that you are cre Strive to create selectors that actually fully describe where it is authored. Put another way, any given selector should tell you which file and where in the file it is written. -This can be down by following this simple rule: the first class in a selector is the file it can be found +This can be down by following this simple rule: the first class in a selector is the file it can be found. For example `.t-pdp .c-product` would be written in `_pdp.scss` and NOT `_product.scss`. -The exception to this rule are when a base or root class is dependant on a global state. +The exception to this rule is when a base or root class is dependent on a global state: + +`.x-landscape .t-about .c-contact-form` would be found in `_about.scss` and NOT a `_landscape.scss` file (modifier classes alone don't have their own files). Using `x-` prefixes is an old convention and won't be found very often. + + +## Mobile First + +When styling responsively, keep in mind that the first breakpoint is no breakpoint. This way, you build upon a ruleset that already exists, rather than creating one from scratch for each breakpoint. + +Instead of: +``` +// Button +// === + +.c-button { + @media screen and (min-width: 0) and (max-width: 460px) { + padding: 10px; + font-size: 12px; + } + + @media screen and (min-width: 461px) and (max-width: 768px) { + padding: 10px; + font-size: 14px; + } +} +``` + +Try: + +``` +// Button +// === + +.c-button { + padding: 10px; + font-size: 12px; -For example `.x-landscape .t-about .c-contact-form` would be found in `_about.scss` and NOT a `_landscape.scss` file (modifier classes alone don't have their own files). + @media screen and (min-width: 461px) { + font-size: 14px; + } +} +``` +Exceptions to this rule obviously exist. If you are styling a completely different DOM or the overall layout of the component needs to change completely, it is best to used mediaqueries that are scoped to a particular range. A good example here would be a menu that changes from drawer-style to mega-menu depending on viewport width. ## Single Direction Rule @@ -115,9 +152,7 @@ This principle is talked about in depth by [Harry Roberts on csswizardy.com](htt ## Name Spacing -The first thing you'll notice when going through Customer Success's CSS is that all of our class names are prefixed (aka: name-spaced) to one of two letters: `c-` or `t-`, meaning `_component_` or `_template_` respectively. See the [below table](../class-naming-conventions#class-prefix-conventions) for more details on Mobify's namespacing practices. - -Because we work on top of our client's markup and javascript, we need to make sure our class names will never conflict with their class names. By prefixing/namespacing our classes with `c-` or `t-`, we can be assured that 99.9% of those situations are avoided. +The first thing you'll notice when going through our CSS is that all of our class names are prefixed (aka: name-spaced) to one of two letters: `c-` or `t-`, meaning `_component_` or `_template_` respectively. See the [below table](../class-naming-conventions#class-prefix-conventions) for more details on Mobify's namespacing practices. ## Size Units @@ -230,6 +265,7 @@ And as before, we use [Sass-Lint](https://github.com/sasstools/sass-lint) to hel 1. Pseudo-elements 1. Modifier elements 1. Child elements +1. Media Queries ```scss .c-selector { @@ -309,7 +345,7 @@ And as before, we use [Sass-Lint](https://github.com/sasstools/sass-lint) to hel Sometimes we break out of this convention to add to the readability of our stylesheets. This occurs especially often with long comma separated property values like gradients, shadows, transitions, or includes. These can be arrange across multiple lines and indentation levels to help with diffs and readability. ```scss -.x-selector { +.c-selector { @include icon( home, $color: blue, diff --git a/css/introduction/readme.md b/css/introduction/readme.md index b6ae88e..853023e 100644 --- a/css/introduction/readme.md +++ b/css/introduction/readme.md @@ -14,40 +14,27 @@ We follow a mixture of various methodologies include, but not limited to: SMACSS ## Tools & Frameworks * [Sass](http://sass-lang.com/) is our preprocessor of choice +* [Susy](http://susy.readthedocs.io/) is used for our SASS-based grid system * [PostCSS](https://github.com/postcss/postcss) for its [Autoprefixer](https://github.com/postcss/autoprefixer) plugin -* [Vellum](https://github.com/mobify/vellum) is our starting point for base styles on Customer Success projects at Mobify -* [Spline](https://github.com/mobify/spline) is our library of Sass mixins and functions -* [Stencil](https://github.com/mobify/stencil) (Deprecated – but a new 2.0 version is coming soon!) is our library or reusable UI patterns * [Sass-Lint](https://github.com/sasstools/sass-lint) is our preferred linter for `SCSS`. Our custom linting rules are found [here](https://github.com/mobify/mobify-code-style/blob/master/css/.sass-lint.yml)). Find out how to integrate Sass-Lint with your text editor [here](../sass-lint/readme.md). * [CSScomb](http://csscomb.com/) is a tool that can be plugged into most popular text editors that automatically formats your code! Our formatting ruleset can be found [here](https://github.com/mobify/mobify-code-style/blob/master/css/.csscomb.json). Find out how to integrate CSSComb with your text editor [here](../csscomb/readme.md). ## Philosophy & Structure -We strive to write modular, component driven CSS with a clear seperation of concerns, structured so they are reuseable and findable. In the end, our code should be easy to maintain by anyone - even for new people entering a project. +We strive to write modular, component driven CSS with a clear separation of concerns, structured so they are re-useable and findable. In the end, our code should be easy to maintain by anyone. These guidelines are a summary of our base principles: Our code bases should all... * Be written like a single person typed it -* Be components first +* Be mobile-first +* Be modular–components are better than page specific styles * Be page specific only as a last resort * Be written with nesting no deeper than 4 levels -* Be written with selectors that self documents its location - -Our seperation of concerns is reflected by our style directory structure as follows: - -``` -/styles - /vellum - /components - /partials - /pages -``` - -Note that Vellum represents our "Base" styles. +* Be written with selectors that self document their location > You may notice the heavy influence of methodologies like [SMACSS](http://smacss.com/) and [OOCSS](http://www.smashingmagazine.com/2011/12/12/an-introduction-to-object-oriented-css-oocss/). > -> Familiarity with these concepts is cruicial! If you are not, then we urge that you at least learn the basics: [Jonathan Snook's "CSS is a Mess"](http://vimeo.com/99877232) and [Andy Hume's "CSS For Grown Ups"](http://lanyrd.com/2012/sxsw-interactive/spmqc/) is a good place to start. +> Familiarity with these concepts is crucial! We urge that you at least learn the basics: [Jonathan Snook's "CSS is a Mess"](http://vimeo.com/99877232) and [Andy Hume's "CSS For Grown Ups"](http://lanyrd.com/2012/sxsw-interactive/spmqc/) are good places to start. Continue on to [CSS Best Practices →](../css-best-practices#css-best-practices) diff --git a/css/localization-and-theming-best-practices/readme.md b/css/localization-and-theming-best-practices/readme.md index f09075e..9e1433b 100644 --- a/css/localization-and-theming-best-practices/readme.md +++ b/css/localization-and-theming-best-practices/readme.md @@ -2,41 +2,16 @@ ## Table of Contents -* [For Non-Componentized Projects](#for-non-componentized-projects) * [For Componentized Projects](#for-componentized-projects) +* [For Older, Non-Componentized Projects](#for-non-componentized-projects) * [Best Practices for Theming](#best-practices-for-theming) Otherwise known as l10n and i18n, we sometimes must author CSS that targets certain nationalities. Below we describe two methodologies for tackling this particular challenge: - -## For Non-Componentized Projects - -Projects that don't follow Mobify's modern CSS best practices aren't likely to have component classes. As such, targeting changes is most likely going to be entirely through template class names and desktop class names. - -As such, our preferred method for apply l10n and i18n styles is as follows. - -1. Create a localization or internationalization folder -2. Create a SCSS file for each l10n or i18n that is to be targetted (i.e. english, french, deutch, etc.) -3. Write your SCSS in the following format... - -```scss -.x-deutsch { - - .t-template-name { - // ... - } - - .client-class-name { - // ... - } -} -``` - - ## For Componentized Projects -Projects that do follow Mobify's modern CSS best practices have component classes. As such, our preferred method of applying l10n and i18n changes is as follows. +Projects that follow Mobify's modern CSS best practices have component classes. Our preferred method of applying l10n and i18n changes are as follows: 1. Identify whether a l10n or i18n change applies to a component or template class 2. Open that component or class in your editor @@ -84,6 +59,30 @@ Projects that do follow Mobify's modern CSS best practices have component classe ``` +## For Non-Componentized Projects + +Projects that don't follow Mobify's modern CSS best practices aren't likely to have component classes. As such, targeting changes is most likely going to be entirely through template class names and desktop class names. + +As such, our preferred method for apply l10n and i18n styles is as follows. + +1. Create a localization or internationalization folder +2. Create a SCSS file for each l10n or i18n that is to be targetted (i.e. english, french, deutch, etc.) +3. Write your SCSS in the following format... + +```scss +.x-deutsch { + + .t-template-name { + // ... + } + + .client-class-name { + // ... + } +} +``` + + ## Best Practices for Theming When creating theme styles, it is best practice to... diff --git a/css/sass-best-practices/readme.md b/css/sass-best-practices/readme.md index aed0e04..340ed61 100644 --- a/css/sass-best-practices/readme.md +++ b/css/sass-best-practices/readme.md @@ -1,6 +1,6 @@ # Sass (SCSS) Best Practices -As mentioned earlier, we use [Sass](http://sass-lang.com/) using the `SCSS` syntax and [Autoprefixer](https://github.com/ai/autoprefixer) to build our CSS. We have some guidelines when using these guys. +As mentioned earlier, we use [Sass](http://sass-lang.com/) with SCSS syntax. ## Table of Contents @@ -23,31 +23,29 @@ As mentioned earlier, we use [Sass](http://sass-lang.com/) using the `SCSS` synt ## Nest Only When Necessary -Limit nesting as much as possible. Assess every single level of nesting that you use. This prevents increasing specificity and impacting performance. Before nesting, ask yourself "will this work without nesting?" Just because you *can* nest does not mean you should, or that it makes the code maintainable (Hint: it doesn't). +Limit nesting as much as possible. This prevents increasing specificity and impacting performance. Before nesting, ask yourself, "will this work without nesting?" Just because you *can* nest doesn't mean you should, or that it makes the code maintainable (Hint: it doesn't). At most, go no more than 4 levels deep. ### Beware Nested Comma Separated Selectors -[This example](http://sassmeister.com/gist/891f2002ef23bf8e4788) demonstrates a real-world scenario that happens when developers recklessly author code to match the markup too closely. - -It is a bad habit to nest every or most times an element is appears nested in the markup. CSS is not HTML, so we can't treat it in the same way. We have to be mindful of the selectors that we are compiling. +[This example](http://sassmeister.com/gist/891f2002ef23bf8e4788) demonstrates a real-world scenario that happens when developers recklessly author code to match the markup too closely. CSS is not HTML, so we can't treat it in the same way. We have to be mindful of the selectors that we're compiling. What strategy do we use to avoid unnecessary nesting? Let's use the above [sassmesiter.com](http://sassmeister.com/gist/891f2002ef23bf8e4788) example and tweak it to show a few ways we could approach it instead. We could... * [Nest less](http://sassmeister.com/gist/12ca39f4fa72cafc5a75) * [Don't nest at all](http://sassmeister.com/gist/67f8fd11522e1d4692a9) and use template classes -* or, [don't nest at all](http://sassmeister.com/gist/036b0a161a47f321b776) and use component classes +* Or, [don't nest at all](http://sassmeister.com/gist/036b0a161a47f321b776) and use component classes -The approach you use depends on many factors. How much control you have over the markup? How reusable are the styles that you are writing? Are the desktop or inline styles that you must account for? +The approach you use depends on many factors. How much control you have over the markup? How reusable are the styles that you are writing? Are there desktop or inline styles that you must account for? -Chances are you will have to use a combination of all these strategies that works based on the state of your project and its markup. +Chances are you'll have to use a combination of all these strategies that works based on the state of your project and its markup. ## Global vs. Local Variables/Mixins -Any `$variable` that is used in more than one file should be placed in the `/vellum/variables.scss` file. Others should be placed at the top of the file in which they're used. +Any `$variable` that is used in more than one file should be placed in the `/variables.scss` file. Others should be placed at the top of the file in which they're used. Any `@mixin` that is used in more than one file should be placed in the `/utilities` folder. @@ -59,7 +57,7 @@ As a rule of thumb, try to avoid `@extend`. ### Pitfalls -The main problem with `@extend` is that it is easy to bloat your code by using it. When first starting to use it, the code can be very innocent in appearance, such as: +The main problem with `@extend` is that it has a tendency to bloat your code. When first starting to use it, the code can be very innocent in appearance: ```scss // SCSS code @@ -74,7 +72,7 @@ The main problem with `@extend` is that it is easy to bloat your code by using i .c-callout {} ``` -That does appear pretty innocent. However, what happens if we do this: +Nothing too strange here. However, what happens if we do this: ```scss // SCSS code @@ -94,12 +92,12 @@ That does appear pretty innocent. However, what happens if we do this: .t-home .cta .c-button, .t-home .cta .c-callout {} ``` -Whoa! See what happened? Notice the extra selector that got compiled that we probably didn't expect to happen: `.t-home .cta .c-callout`. This happens because Sass extends every single instance of that selector, regardless of the selector chain. That means any, and I mean really any instance that `.c-button` is written in a selector, they all get extended by `.c-callout`, which can be a massive amount of unwanted code. +Whoa! See what happened? You probably didn't intend to create the `.t-home .cta .c-callout` selector. This happens because Sass extends every single instance of that selector, regardless of the selector chain. That means any time `.c-button` is written in a selector, it will get extended by `.c-callout`, which can lead to a massive amount of unwanted code. ### Workaround -So there is a workaround for the problem we described above: __never directly extend a standard class__. Instead, __only extend placeholder classes__. Let's see what that looks like using the same example from above: +There is a workaround for the problem we described above: __never directly extend a standard class__. Instead, __only extend placeholder classes__. Let's see what that looks like using the same example from above: ```scss // SCSS code @@ -127,7 +125,7 @@ This technique is described in detail in Chris Lamb's article [Mastering Sass Ex The placeholder class always goes after the regular selectors. In other words, make the placeholder class the last selector in a chain of comma separated selectors. -In most cases, the placeholder class is named after the element or component class it is related to: +In most cases, the placeholder class is named after the element or component class it's related to: ``` h1, @@ -166,12 +164,12 @@ If the placeholder selector is for a modifier class, use the following name conv ### Genuine Usecases -__Scenario 1__: There are situations where you want to have default styles on elements like lists or headings, but you may also need classes for those same styles to use when you can't use the exact markup. Good real life example is when you need a heading to be an `

` but it must look like an `

` or vice versa. +__Scenario 1__: There are situations where you want to have default styles on elements like lists or headings, but you may also need classes for those same styles to use when you can't use the exact markup. A good real life example is when you need a heading to be an `

` but it should look like an `

` or vice versa. This is how we deal with this scenario using `@extend`: ```scss -// In `/vellum` +// In `/base` // --- h1, @@ -212,11 +210,11 @@ h2, // and so on... ``` -Please note that in Mobify's way of writing CSS, we do not declare classes in vellum (a.k.a. globals) and we do not style elements or tags in components, which is why these two are declared separately in their respective directories. +At Mobify, we don't declare classes in the default `base` styles or style elements or tags in components, which is why these two are declared separately in their respective directories. -__Scenario 2__: This scenario is very specific to Mobify and here is why... as you probably know by now, using Mobify's Adaptive.js you are basically transforming a site's DOM and applying new CSS to the new DOM. Typically, we would expect to have full control over the markup, and therefore over all the classes added to the DOM. Unfortunately, there are times when parts of the DOM cannot be changed exactly like you might want, such as when the website is using third-party plugins like BazaarVoice. +__Scenario 2__: This scenario occurs commonly when working with 3rd party plugins like BazaarVoice. -What are the consequences of not being able to control parts of the DOM? It means we might not be able to add classes to the DOM reliably, which means that we can't apply our styles as easily as we would like. Instead, we are forced to write some gnarly selectors to ensure these situations can work. Let's use BazaarVoice again as our example: +What are the consequences of not being able to control parts of the DOM? It means we might not be able to add classes to the DOM reliably, which means that we can't apply our styles as easily as we would like. Instead, we are forced to write some gnarly selectors. Here's an example using BazaarVoice: ```scss [id="BVRRContainer"] { @@ -235,49 +233,38 @@ What are the consequences of not being able to control parts of the DOM? It mean } ``` -So what is happening here? Well because we can't add classes to the DOM on the BazaarVoice widget, instead we have to directly select the IDs and classes that they are using already. Now because we want BazaarVoice to look like our website, we want to reuse some of the CSS we've written. The solution to this is to use `@extend` on BazaarVoice selectors. +What's happening here? Since we can't add classes to the DOM on the BazaarVoice widget, we have to directly select the IDs and classes that they're using already. However, we still want BazaarVoice to look like our website, AND to reuse some of the CSS we've written. The solution is to use `@extend` on BazaarVoice selectors. ## Filename Naming Convention -The file naming convention should be identical to the Class Naming convention as described below, but with the following difference: +The file naming convention should be identical to the Class Naming convention described below, but with the following difference: -Sass files (technical scss files) should be a Sass partial +Sass files (technical SCSS files) should be a Sass partial: * This means it's prepended with a underscore `_` -Sass files are named after it's root class name +Sass files are named after their root class name: -* Vellum: the filename can be named after the grouping of elements - * Example `ul`, `ol` and `li` can be grouped together in `_list.scss` +* Utilities: the filename can be named after the grouping of elements + * Example `u-color-error` and `u-bg-color-error` both live in `_color.scss` * Components: the base component will be the filename - * `c-color-picker` makes `_color-picker.scss` - * Sub-components and modifiers are ignored! + * `c-color-picker` lives in `_color-picker.scss`, along with its sub-components and modifiers. * Templates: the base template will be the filename - * `t-my-account` makes `_my-account.scss` - * Sub-templates and modifiers are ignored! + * `t-my-account` lives in `_my-account.scss` with its sub-templates and modifiers. * Note that this should ultimately match our template filename naming convention -## Note on Partials - -Be aware that there are two kinds of partials: - -*Template Partials* are dust template partials that are used specifically to hold small chunks of reusable code. - -These partials live in the `/adaptation/templates/partials` directory. - -*Sass Partials* are Sass or SCSS files that are appended with the underscore (`_`) character and is used for two reasons: First reason is to prevent the file from compiling into a CSS of the same name. The second is to simplify `@import` declarations by way of allowing you to reference the file without the file extension. - -These partials live throughout the `/assets/styles` directory. In fact, most SCSS files are partials with the exception of the core `stylesheet.scss`. +### Note on Underscores -When discussing partials, it should be clear which type is being talked about based on context. For example when discussing HTML, the structure of a document or a View then the Template Partial is what's relevant. +SCSS files are appended with the underscore (`_`) character for two reasons: -On the flip side, if discussing CSS, Sass or stylesheets then a Sass Partial is what's relevant. +1. To prevent the file from compiling into a `.css` file of the same name. +1. To simplify `@import` declarations by allowing you to reference the file without the file extension. ## Commenting Best Practice -It is always better to over document your stylesheets than under document! That means writing lots of comments! +It's always better to over-document your stylesheets than under-document! That means writing lots of comments! When writing comments, it is best to following a format that makes making changes easy, without having to clutter your code. @@ -302,9 +289,9 @@ The second aspect of comments are the comments themselves! There are three types 2. Direct Comments -Direct comments are those that apply to a single line of code as denoted by the number in the note. So the first note (1) will apply anywhere you see `// 1`. +Direct comments are those that apply to a single line of code, as denoted by the number in the note. So the first note (1) will apply anywhere you see `// 1`. -Be aware that these notes typically only refer to the code directly beneath it, as far as just before the next section (i.e. the next sub-component). That next section could have it's own Direct Notes, but they will only apply to that section despite using the same numbers. +Be aware that these notes typically only refer to the code directly beneath them. The section below the next title may have its own notes as well, and the numbering will start again. ```scss // My Component @@ -330,7 +317,7 @@ Be aware that these notes typically only refer to the code directly beneath it, // // Notes: // -// 1. We see the number 1 again! But this note only counts for the code below and ignore the 1 above +// 1. We see the number 1 again! But this note only counts for the code below and ignores the 1 above .c-my-component__inner { display: block; // 1 @@ -340,7 +327,7 @@ Be aware that these notes typically only refer to the code directly beneath it, 3. Global Direct Comments -Global Direct Comments are used in the same way as normal Direct Comments with one crucial difference: these are declared once at the top of the file and can be used through any section! +Global Direct Comments are used in the same way as normal Direct Comments with one crucial difference: these are declared once at the top of the file and can be used in any section! So Note A will always refer to the same note. @@ -367,22 +354,22 @@ This is a rare use case, but can be useful sometimes when you have the same set } ``` -### Common things to Comment +### What to Comment * The parent relative position to an absolutely positioned element -* Explicit dimensions like widths or heights that don't appear based on any meaninful unit (like `$v-space` or `$h-space` and even font sizes) +* Explicit dimensions like widths or heights that don't appear based on any meaningful `$unit` ## Variable Naming Convention Variable names should follow this pattern: `${modifer(s)}-{name}`. -The name of a variable should describe the application of the variable value. For example, instead of saying `$color` (which is too generic to be useful), you would write `$link-color` which gives the name meaning and purpose. +The name of a variable should describe the application of the variable value. For example, instead of saying `$color` (which is too generic to be useful), you would write `$link-color`, which gives the name meaning and purpose. Similarly, the variable name can refer to specific properties such as `$border-radius` or `$border`. Modifiers should be added before the name. So our above examples with modifiers prepended to them will look like `$dark-link-color`, `$large-border-radius` and `$dotted-border`. -Do note that variables without modifiers are implicitly the base version of that variable. As such, variables like `$base-link-color`, `$base-border-radius` and `$base-border-radius` are unnecessary. +Note that variables without modifiers are implicitly the base version of that variable. As such, variables like `$base-link-color`, `$base-border-radius` and `$base-border-radius` are unnecessary. ### Exceptions From 07b28e5a7b821f199e73deec8aafaa049bfa75c2 Mon Sep 17 00:00:00 2001 From: Sonja Date: Fri, 27 Apr 2018 17:16:19 -0700 Subject: [PATCH 2/4] =?UTF-8?q?DESKTOP-129:=20=E2=9C=A8=20=20add=20in=20re?= =?UTF-8?q?sponsive=20best=20practices=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/Readme.md | 1 + css/class-naming-conventions/readme.md | 2 +- css/css-best-practices/readme.md | 38 +----- css/responsive-best-practices/readme.md | 153 ++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 38 deletions(-) create mode 100644 css/responsive-best-practices/readme.md diff --git a/css/Readme.md b/css/Readme.md index abd4081..62ed4dd 100644 --- a/css/Readme.md +++ b/css/Readme.md @@ -39,6 +39,7 @@ * [When to use our selector naming scheme](class-naming-conventions#when-to-use-our-selector-naming-scheme) * [When to use their existing selectors](class-naming-conventions#when-to-use-their-existing-selectors) * [How to use their existing selectors in our components](class-naming-conventions#how-to-use-their-existing-selectors-in-our-components) +* [Responsive Best Practices](responsive-best-practices/readme.md) * [Localization and Theming Best Practices](localization-and-theming-best-practices/readme.md) * [Block Comment Documentation Guide](comments/Readme.md) * [Hybrid Projects Best Practices](hybrid-projects/Readme.md) diff --git a/css/class-naming-conventions/readme.md b/css/class-naming-conventions/readme.md index 9537e07..6fcf58a 100644 --- a/css/class-naming-conventions/readme.md +++ b/css/class-naming-conventions/readme.md @@ -453,4 +453,4 @@ Use their modifiers the same way you would use our modifiers. Chain them to the } ``` -Continue on to [Block Comment Documentation Guide →](../localization-and-theming-best-practices/readme.md) +Continue on to [Responsive Best Practices →](../responsive-best-practices/readme.md) diff --git a/css/css-best-practices/readme.md b/css/css-best-practices/readme.md index b9f298a..354a844 100644 --- a/css/css-best-practices/readme.md +++ b/css/css-best-practices/readme.md @@ -101,43 +101,7 @@ The exception to this rule is when a base or root class is dependent on a global ## Mobile First -When styling responsively, keep in mind that the first breakpoint is no breakpoint. This way, you build upon a ruleset that already exists, rather than creating one from scratch for each breakpoint. - -Instead of: -``` -// Button -// === - -.c-button { - @media screen and (min-width: 0) and (max-width: 460px) { - padding: 10px; - font-size: 12px; - } - - @media screen and (min-width: 461px) and (max-width: 768px) { - padding: 10px; - font-size: 14px; - } -} -``` - -Try: - -``` -// Button -// === - -.c-button { - padding: 10px; - font-size: 12px; - - @media screen and (min-width: 461px) { - font-size: 14px; - } -} -``` - -Exceptions to this rule obviously exist. If you are styling a completely different DOM or the overall layout of the component needs to change completely, it is best to used mediaqueries that are scoped to a particular range. A good example here would be a menu that changes from drawer-style to mega-menu depending on viewport width. +When styling responsively, we use min-width queries and build on top of them when we need to. Learn more about our other responsive best practices [here](responsive-best-practices/readme.md). ## Single Direction Rule diff --git a/css/responsive-best-practices/readme.md b/css/responsive-best-practices/readme.md new file mode 100644 index 0000000..4f350d7 --- /dev/null +++ b/css/responsive-best-practices/readme.md @@ -0,0 +1,153 @@ +# Responsive Best Practices + +## Mobile First + +Our philosophy is that _the first breakpoint is no breakpoint_. + +There are plenty of good reasons to approach [design](https://www.lukew.com/ff/entry.asp?933) and [content strategy](https://alistapart.com/article/your-content-now-mobile) from this perspective, and the same goes for styling. An experience shouldn't depend on a specific viewport width work well. + +When writing your CSS, a mobile-first mindset will help keep your code DRY. *Using `min-width` only queries is the key.* + +Instead of: + +``` +// Button +// === + +.c-button { + @media screen and (max-width: 460px) { + padding: 10px; + font-size: 12px; + } + + @media screen and (min-width: 461px) and (max-width: 768px) { + padding: 10px; + font-size: 14px; + } +} +``` + +Try: + +``` +// Button +// === + +.c-button { + padding: 10px; + font-size: 12px; + + @media screen and (min-width: 461px) { + font-size: 14px; + } +} +``` + +Now instead of re-writing styles at each breakpoint, we're only adding on what we need to! + +Exceptions obviously exist. If you are styling markup that gets replaced at a specific breakpoint (a drawer style navigation that switches to a mega-menu for wider screens is a good example), it is best to use media queries that are scoped to a particular range. + + +## Use 4 or Less Major Breakpoints + +Good designs are based on content and context, not specific device sizes, and our styles should be as well. Work with the designers on your team to figure out what these breakpoints are, and use 4 or less. Remember, if you have 4 _major_ breakpoints, you'll have 5 different layout changes because the first breakpoint is _no_ breakpoint. + +_Major_ breakpoints are project-wide variables, and follow the naming convention `$small-breakpoint`, `$medium-breakpoint`, `$large-breakpoint`, and `$x-large-breakpoint`. Keep the number of _major_ breakpoints small and consistent–it makes code easier to understand and maintain, and reduces the element of surprise. + +_Minor_ breakpoints are one-offs that are used for smaller design changes, such as font-sizing, in between _major_ breakpoints. They are not ideal, but often necessary. Keep them to a minimum if possible. + + +## Keep Your Queries With Their Components + +SCSS allows you to write media queries inside a declaration. This has several advantages, especially with more complicated components or in larger SCSS files: + +1. All component and sub-component styles, including modifiers, are in one place +1. You can easily see what you are building on top of +1. Less scrolling and reduced cognitive overhead +1. Debugger is simpler + +Instead of: + +``` +// Some Component +// === + +.c-some-component { + padding: 10px; + display: inline; + border: 1px solid red; + font-size: 16px; + + &.c--some-modifier { + font-weight: bold; + } +} + +.c-component__thing { + display: none; +} + +.c-component__other-thing { + ... +} + +... + +@media screen and (min-width: $small) { + .c-some-component { + padding: 15px; + font-size: 18px; + + &.c--some-modifier { + font-color: red; + } + } + + .c-component__thing { + display: block; + background-color: blue; + } +} +``` + +Try: + +``` +// Some Component +// === + +.c-some-component { + padding: 10px; + display: inline; + border: 1px solid red; + font-size: 16px; + + &.c--some-modifier { + font-weight: bold; + } + + @media screen and (min-width: $small-breakpoint) { + padding: 15px; + font-size: 18px; + + &.c--some-modifier { + font-color: red; + } + } +} + +.c-component__thing { + display: none; + + @media screen and (min-width: $small-breakpoint) { + display: block; + background-color: blue; + } +} + +.c-component__other-thing { + ... +} +``` + +Continue on to [Localization and Theming Best Practices →](../localization-and-theming-best-practices/readme.md) From 6500b67c1551976119dbaab1f2db3d492927144a Mon Sep 17 00:00:00 2001 From: Sonja Date: Mon, 30 Apr 2018 10:58:14 -0700 Subject: [PATCH 3/4] =?UTF-8?q?DESKTOP-129:=20=F0=9F=93=93=20=20update=20c?= =?UTF-8?q?hangelog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b5c9eb..062a51b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## v2.8.5 (April 30, 2018) +- Add in Responsive Best Practices section, updated references to Adaptive [#165](https://github.com/mobify/mobify-code-style/pull/165) + ## v2.8.4 (October 31, 2017) - Add support to copyright tooling for TypeScript files (.ts, .tsx) [#164](https://github.com/mobify/mobify-code-style/pull/164) From 85a0b34c131279b88e1184d9eab99ad73b77aa9f Mon Sep 17 00:00:00 2001 From: Sonja Date: Tue, 1 May 2018 11:48:13 -0700 Subject: [PATCH 4/4] =?UTF-8?q?DESKTOP-129:=20=F0=9F=92=84=20=20address=20?= =?UTF-8?q?PR=20feedback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/class-naming-conventions/readme.md | 2 +- css/css-best-practices/readme.md | 4 ++-- css/introduction/readme.md | 2 +- css/responsive-best-practices/readme.md | 18 ++++++++++++------ css/sass-best-practices/readme.md | 2 +- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/css/class-naming-conventions/readme.md b/css/class-naming-conventions/readme.md index 6fcf58a..a07c30f 100644 --- a/css/class-naming-conventions/readme.md +++ b/css/class-naming-conventions/readme.md @@ -308,7 +308,7 @@ Sometimes there are situations when a component makes use of other components, a ``` -In situations like this it is tempting to just style the icon's class inside of the button. However, this practice is poor and creates tight coupling between the Button and Icon components that shouldn't exist. As a rule of thumb, a component should only know about what it's responsible for; it shouldn't be aware of anything external to itself. Since Icon is an external component, the Button component should be completely unaware that of `c-icon`. +In situations like this it is tempting to just style the icon's class inside of the button. However, this practice is poor and creates tight coupling between the Button and Icon components that shouldn't exist. As a rule of thumb, a component should only know about what it's responsible for; it shouldn't be aware of anything external to itself. Since Icon is an external component, the Button component should be completely unaware of `c-icon`. The solution to this challenge is to instead give the external component a new class that our new component can know about, like `c-button__icon`. This way, the component is treated like a sub-component of Button, and eliminates any tight coupling between the components. Both components can change, be added or removed, without affecting the other in an unpredictable way. diff --git a/css/css-best-practices/readme.md b/css/css-best-practices/readme.md index 354a844..e5e0a24 100644 --- a/css/css-best-practices/readme.md +++ b/css/css-best-practices/readme.md @@ -90,7 +90,7 @@ When authoring CSS, you should be always aware of the selectors that you are cre Strive to create selectors that actually fully describe where it is authored. Put another way, any given selector should tell you which file and where in the file it is written. -This can be down by following this simple rule: the first class in a selector is the file it can be found. +This can be done by following this simple rule: the first class in a selector is the file it can be found. For example `.t-pdp .c-product` would be written in `_pdp.scss` and NOT `_product.scss`. @@ -101,7 +101,7 @@ The exception to this rule is when a base or root class is dependent on a global ## Mobile First -When styling responsively, we use min-width queries and build on top of them when we need to. Learn more about our other responsive best practices [here](responsive-best-practices/readme.md). +When styling responsively, we use min-width queries and build on top of them when we need to. Learn more about our other responsive best practices [here](responsive-best-practices/readme.md). ## Single Direction Rule diff --git a/css/introduction/readme.md b/css/introduction/readme.md index 853023e..2a52c9b 100644 --- a/css/introduction/readme.md +++ b/css/introduction/readme.md @@ -28,7 +28,7 @@ These guidelines are a summary of our base principles: Our code bases should all * Be written like a single person typed it * Be mobile-first -* Be modular–components are better than page specific styles +* Be modular: components are better than page specific styles * Be page specific only as a last resort * Be written with nesting no deeper than 4 levels * Be written with selectors that self document their location diff --git a/css/responsive-best-practices/readme.md b/css/responsive-best-practices/readme.md index 4f350d7..3f049ea 100644 --- a/css/responsive-best-practices/readme.md +++ b/css/responsive-best-practices/readme.md @@ -1,16 +1,22 @@ # Responsive Best Practices +## Table of Contents + +* [Mobile First](#mobile-first) +* [Use 4 or Less Major Breakpoints](#use-4-or-less-major-breakpoints) +* [Keep Your Queries With Their Components](#keep-your-queries-with-their-components) + ## Mobile First Our philosophy is that _the first breakpoint is no breakpoint_. -There are plenty of good reasons to approach [design](https://www.lukew.com/ff/entry.asp?933) and [content strategy](https://alistapart.com/article/your-content-now-mobile) from this perspective, and the same goes for styling. An experience shouldn't depend on a specific viewport width work well. +There are plenty of good reasons to approach [design](https://www.lukew.com/ff/entry.asp?933) and [content strategy](https://alistapart.com/article/your-content-now-mobile) from this perspective, and the same goes for styling. An experience shouldn't depend on a specific viewport width to work well. When writing your CSS, a mobile-first mindset will help keep your code DRY. *Using `min-width` only queries is the key.* Instead of: -``` +```scss // Button // === @@ -29,7 +35,7 @@ Instead of: Try: -``` +```scss // Button // === @@ -64,11 +70,11 @@ SCSS allows you to write media queries inside a declaration. This has several ad 1. All component and sub-component styles, including modifiers, are in one place 1. You can easily see what you are building on top of 1. Less scrolling and reduced cognitive overhead -1. Debugger is simpler +1. Debugging is simpler Instead of: -``` +```scss // Some Component // === @@ -112,7 +118,7 @@ Instead of: Try: -``` +```scss // Some Component // === diff --git a/css/sass-best-practices/readme.md b/css/sass-best-practices/readme.md index 340ed61..8158b6c 100644 --- a/css/sass-best-practices/readme.md +++ b/css/sass-best-practices/readme.md @@ -45,7 +45,7 @@ Chances are you'll have to use a combination of all these strategies that works ## Global vs. Local Variables/Mixins -Any `$variable` that is used in more than one file should be placed in the `/variables.scss` file. Others should be placed at the top of the file in which they're used. +Any `$variable` that is used in more than one file should be placed in the `_variables.scss` file. Others should be placed at the top of the file in which they're used. Any `@mixin` that is used in more than one file should be placed in the `/utilities` folder.