On Github elyseholladay / tech-talk-roux-sass
Arrow left/right between sections
Arrow up/down inside sections
CSS Basics
CSS Vocabulary Cascade & Inheritance Specificity Using Inheritance Compositionnimbupani.com/css-vocabulary.html
First, a little vocab lesson. It’s easier to talk about CSS when we know all the names of what we are discussing.
What element(s) the styles should apply to; an element, class, ID, etc.
A selector is what you declare which elements the styles should apply to.
Elements h1, p, div
Classes .page-header
IDs #login
Attributes input[type=“text”]
Pseudo-classes :last-child
Pseudo-elements :after
Property The style that you are applying to a selector, e.g. color.
Value The value that the property can have, e.g. blue.
Therefore you have a property: value; pair,
Declaration The combination of a property: value; pair.
Rulesets A selector followed by some number of declarations:
.classname { color: blue; font-size: 18px; }
nicolasgallagher.com/css-cascade-specificity-inheritance
Let's talk a little bit about the cascade and inheritance. This is the part of CSS that really trips everybody up when it gets complex.
The cascade is a mechanism for determining which styles should be applied to a given element, based on the rules that have cascaded down from various sources.
The cascade takes importance, origin, specificity, and source order of style rules into account. It assigns a weight to each rule. When multiple rules apply to a given element, the rule with the greatest weight takes precedence. The result is an unambiguous way to determine the value of a given element/property combination.
http://nicolasgallagher.com/css-cascade-specificity-inheritance/
importance + origin + specificity + source order = cascade
See Nicholas Gallagher notes
header { color: red; } .header h1 {}
what color will the h1 be? (red)
Some properties, e.g. color, are automatically inherited by the children of the element to which they are applied.
.header { color: red; } .header { color: blue; } .header h1 {}
what color will the h1 be? (blue)
Some properties, e.g. color, are automatically inherited by the children of the element to which they are applied.
.header { color: red; } .header { color: blue; } .header h1 { color: green; }
what color will the h1 be? (green)
.header { color: red; } .header h1 { color: green; } .header { color: blue; }
what color will the h1 be? (green) ... why? (specificity)
Specificity is a method of conflict resolution within the cascade.
Specificity calculates whether or not a value will apply (and override inheritance) based on the weight of the selector.
inline styles are 1000
IDs are 100
classes are 10
elements are 1
How would you expect to use inheritance to your advantage in a complex website? (expecting an answer about "all headers in the sidebar are blue")
“I want every h2 in the sidebar to look the same, and I don’t want to have to write CSS every time we create a new sidebar widget.”
h2 { color: #fd7900; font-size: 1.8em; line-height: 1.1; margin-bottom: .3em; }
It all starts because someone says “I don’t want to have to write CSS every time I add an h2″. So we write:
.sidebar h2 { color: #8cc5e6; font-size: 2.2em; padding-bottom: .2em; border-bottom: 1px solid black; }
This works great at first, but then it happens: A story owner wants to change the look of all of the .sidebar h2.
We don’t need to change everything, just the color, size and border. So we take advantage of the CSS cascade and tweak the values that need to be updated.
.block border: 1px solid #8cc5e6; padding: 0 15px; } .block h2 { /* Color was changed by .sidebar h2, set it back */ color: #fd7900; /* remove border added by .sidebar h2 */ border: none; /* remove the margin set by h2 */ margin: 0; padding: .3em; background: #8cc5e6; }
We are trying to be smart by breaking small pieces of functionality into reusable sidebar blocks, so we decide to create some default block styles. This way all of the blocks we create today, and in the future, can inherit the same styles. Each block has a h2, so let’s look at how that will be styled.
/* The Markup:
Now we’ve been asked to create an alternate block style that uses the original sidebar header, but has full grey background.
our title is now inheriting styles from 4 different selectors, our code is bloated, our site’s performance is taking a hit, and our style system is incredibly fragile. Any change to h2 , .sidebar h2 , .block h2 will have an effect on .alt-block h2 whether we intended for it to or not
element inheritance
location inheritance
class inheritance
In the above example we experienced 3 different types of CSS inheritance: element inheritance, location inheritance, and class inheritance. Let’s take a look at how each one of them works, why they cause problems, and solutions to fixing them.
ties presentation to HTML elements and markup
We use HTML elements to add semantic meaning to our sites. When we apply styles to these elements we end up mixing semantics and presentation. I don’t mind applying a very basic set of default styles to our elements, but we ran into problems in our example when we tied our finished, presentational styles to the h2 element. This not only muddied up the water for all of our other h2 elements, but it also made those base styles impossible to reuse once overridden. Instead of relying on element inheritance to propagate our base style, we should move those styles into a reusable class or extend. You can even call it .h1 or %h1 if you want to! But the key is to avoid tying presentation to your base elements
means your styles are dependent on their location in the DOM and parents
Using location inheritance means that your header styles are dependent on being in the sidebar (not standalone or reusable), and that you’re required have intimate knowledge of your parent container before writing styles.
Someone is going to ask you to create a new header style for the sidebar and the last thing you want to have to do is try out all 6 of the header elements ( h1 – h6) to see which one has the least number of styles to override.
You will eventually be asked to move a component from the main content region over to the sidebar. How much do you want to bet that the .sidebar h2 styles won’t have ANY effect on the .widget h2 you are moving over.
You might think that using a decendant selector (like .sidebar > h2) will solve all of your problems, but now your styles are dependent on markup order, and there is no way to reuse those h2 styles elsewhere in your site.
creates relationships & dependencies where none should exist
Class inheritance is the practice of applying an entire system of styles on a collection of markup via a single class. In our example we have a .block class that is a complete component, then we add on another set of styles with .alt-block . this means that .alt-block “modifies or relies on the internal workings of another module”. This isn’t always a bad thing, but it is something that can quickly become complex and fragile.
Imagine that you wrote the .block code, and then someone else on the team decided to create .my-calendar-widget using .block as a set of base styles, i.e. a “relied upon module”.
what happens when we get a new story to change block to have a different background?
Unless you have a well established system for documenting these relationships, this becomes what I like to call “hijacked inheritance”. We have no indication in our CSS that .block has another component tightly coupled to it, so we’ll be dealing with random bugs on our calendar page every time we update .block.
.block border: 1px solid #8cc5e6; padding: 0 15px; } .block h2 { /* Color was changed by .sidebar h2, set it back */ color: #fd7900; /* remove border added by .sidebar h2 */ border: none; /* remove the margin set by h2 */ margin: 0; padding: .3em; background: #8cc5e6; }
Even with single inheritance our .block element is still completely dependent on the cascade. Move a .block out of the sidebar and it will break. Change the header to H3 and it will break. The problem is that each element inside of .block inherits styles from the parent class, the block’s location and the HTML tag itself. No styles are prescribed to it due its semantic purpose, which is to be a “title”.
is the idea that an html component might “contain” other styles, rather than “inheriting” those styles.
Note how each title has its own unique class. This allows us to target the title regardless of the element used.
%primary-header { font-size: 1.8em; line-height: 1.1; color: #fd7900; margin: .3em; } %secondary-header { font-size: 2.2em; line-height: 1.1; color: #8cc5e6; margin: 0 0 .3em; padding-bottom: .2em; border-bottom: 1px solid black; } %block-header { font-size: 2.2em; line-height: 1.1; color: #fd7900; margin: 0; padding: .3em; background: #8cc5e6; margin: 0 -15px; } %block { border: 1px solid #8cc5e6; padding: 0 15px; } %alt-block { padding: 15px; background: #eee; }
.calendar-widget { @extend %block; } .calendar-widget-title { @extend %block-header; } /*...*/ .latest-blogs { @extend %alt-block; } .latest-blogs-title { @extend %secondary-header; } /*...*/ .latest-news { @extend %alt-block; } .latest-news-title { @extend %secondary-header; }
Notice how each semantic selector is composed of styles rather than inheriting them from its tag, location or parent class. This allows us to “package up our code and reuse it in many different unrelated places and situations”.
The placeholder extends create a relationship between the style and the module name, but not between different modules.
Roux
CSS in Roux vs RMN New Pages CommentingA single source of truth for the way ingredients look, their HTML and Sass/CSS code, and how to implement them;
Refactored Sass code to improve developer ergonomics, making it easier to find what you need than to write something similar from scratch;
An accessible view into the common ingredients available to build out an RMN page, how they work, the code, and how they can be extended or modified;
An ability for developers to quickly code new features without frustrating and untraceable CSS bugs;
Improved developer and designer ergonomics, so you can work on the stuff you are best at without worrying about the rest.
Roux is 80% of our CSS — globals and shared styles. making one-off unique CSS is _okay_! roux does not mean we dont have to ever write css again
1. Create templates/markup
2. Create example.scss manifest file in www/gui/libsass
3. Create partial templates in libsass/pages/example/
4. Import Roux and partials into example.scss
- roux // (symlink folder) example.scss // (imports roux, example/partial1, example/partial2) - pages - example partial1.scss partial2.scss
show store
show store subpages
show typography, favorite, mobile dropdown
Sass Standards
General Naming Conventions Spacing & Formatting Media Queriesanyone who says CSS is easy isn’t doing it right. Sass is a Turing-complete language and it deserves to be treated with the same amount of respect and care we treat other languages. perhaps even more, because it is responsible for what our users see, and very easy to break.
Keep functional Sass separate from presentational styles
Keeping functional Sass separate from presentational Sass is important in order to maintain readability, search-ability and scaleability of your code. Patterns like placing mixins in the same file as presentational Sass leads to overly complex files to scan and opportunities for accidental pollution of your processed CSS. http://gist.io/4436524
example: transitions/spinner
Write for composition, not inheritance.
This mainly means not to create relationships where none exist, like creating alt-block from block. Namespace your modules and make them standalone.
Extends/Placeholders, Mixins, & Maps
Use extends to reuse code with no output, create a relationship
http://sassmeister.com/gist/18c47aadd302b8bd9566
button placeholders
use mixins to alter variables, give options
http://sassmeister.com/gist/elyseholladay/878b591ee969db0026b4 and http://sassmeister.com/gist/elyseholladay/1adb96cae0a363086916
square-image and spinner
use maps for exponential code with a relationship
https://stash.rmn.com/projects/UI/repos/roux-ingredients/browse/sass/_molecules/_coupon_anchor.scss
coupon anchors
Namespace (nest) modules one level to eliminate conflicts… but use minimal nesting to eliminate specificity hell.
.survey-module { .survey-module-header {} }
This is OK
.survey-module { .survey-module-header { .survey-module-header-close { .icon-close {} } } }
This is NOT OK
Always use classes over elements or IDs.
even when it means making more classnames!!
elements are bad b/c: location inheritance and tightly-coupled DOM;IDs are bad: unique, only for JS. use js- prefix classes for js functionality
// Incorrect .survey-module { h2 {} .icon {} } // Correct .survey-module { .survey-module-header {} // h2 .icon-close {} // specific icon }
Check the existing codebase before adding a new var, mixin, or extend.
can you reuse something that is there? do you need to overwrite an existing function? if so, do you know where it will affect?
places to check: roux-ingredients, typography, colors, utils/helper folders (show these)
Variabilize numbers that have a relationship locally
$square-image-size: 25px; .square-image { height: $square-image-size; width: $square-image-size; }
these have a relationship
$square-image-size: 25px; .square-image { height: $square-image-size; width: $square-image-size; padding: 10px; // creates 10px of white border/empty space around the image }
padding doesn’t have a relationship. could we say $square-image-size*.4 ? yes. but why? not related. also.... we added a comment as to WHY
Add inline documentation. Always.
if your CSS is not obvious at first glance, PUT A COMMENT.
li.ds-dfp-banner-container { padding: 0; margin: -1px; .ds-dfp-banner { padding: 20px 0; margin: 0 -16px; text-align: center; } }
why the negative one margin? why the li? what is dfp?
// li required to add specificity to override some of the styling li.ds-dfp-banner-container { padding: 0; margin: -1px; .ds-dfp-banner { padding: 20px 0; margin: 0 -16px; text-align: center; } }
ok... this is an improvement.. but what styling? what is dfp?
// Double Click for Publishers (DFP) banner ads // ---------------------------------------------------------------------- // // li required to add specificity over .coupon-horizontal li.ds-dfp-banner-container { // when banner ad child is hidden (DFP doesn't serve ad), li needs to seem hidden padding: 0; margin: -1px; // hide double border from .coupon-horizontal top borders .ds-dfp-banner { padding: 20px 0; margin: 0 -16px; // align with sides when screen is small text-align: center; } }
muuuuch better
Choose human readable names over acronyms
.btn-lg-s {} // ???
button… large? login? logo? save? submit?
.button-login-submit {}
much easier. computers don’t really care if things are long/short/acronyms/etc. we do.
if you have to use an acronym, like our DFP doubleclick for publishers example (because that would be annoyingly long), PUT A COMMENT!
Shared or global name, then specific name
.blue-button … .button-blue .red-button … .button-red .submit-button … .button-submit
easier to scan visually, easier to remember
Use dashes, not underscores or camelcase.
We don't specifically use BEM, although I see some people doing it, which is fine, we use a BEM-like syntax. But don't camelcase. Please.
// Incorrect .buttonPrimary // Trying to deprecate (BEM) .button--primary // Correct .button-primary .button-submit-offer
Never use display/functionality in names
.orange-box {} .form-float-left {}
why is this bad?
.orange-box { background: green; } .form-float-left { float: right; }
lulz
Be descriptive.
Yes, naming is hard. You can always ask me for help. But try to explain what is in the element you are naming.
.csat-survey .csat-survey-content .csat-survey-header .csat-survey-question-wrapper .csat-survey-questions .csat-survey-question .csat-question-prompt .button-csat-response
what's better... this...
.csat-survey .surveyContent .header-survey .surveywrapper div .question-survey-item p .button
or this?
Use four-space tabs with an editor config.
Put spaces after the colon in property declarations.
// Correct display: block; // Incorrect display:block;
Put spaces before brackets in declarations.
// Correct .class {} // Incorrect .class{}
Place closing braces of declaration blocks on a new line.
// Correct .class { styles: go-here; } // Incorrect .class { styles: go-here; }
Put one property per line.
// Correct .class { display: block; color: red; } // Incorrect .class { display: block; color: red; }
When grouping selectors, keep individual selectors to a single line.
// Correct .class, .box { styles: go-here; } // Incorrect .class, .box { styles: go-here; }
Avoid specifying units for zero values and using zeros before decimals.
// Correct .class { margin: 0; font-size: .5em; } // Incorrect .class { margin: 0px; font-size: 0.5em; }
why do we do this?
Use non-outputting // for comments
One line between rulesets; two lines between sections
.coupon-anchor { ... text-align: center; // size and color of SVG icons inside the coupon anchor amount div .icon { width: 30px; height: 45px; fill: $white; } } // COUPON ANCHOR COLOR MAP ---------------------------------------------- // // ---------------------------------------------------------------------- //
Write media queries inside rulesets.
Media queries go first before all other CSS in a block.
Write responsive code small to large (mobile first)
.page-callout-content { @include media(grid-med) { float: left; width: 75%; padding-left: 1em; } padding-top: 0.75em; padding-right: 2em; }
inside, FIRST before other CSS; small to large (anything else
@include media(grid-med) { .page-callout-content { float: left; width: 75%; padding-left: 1em; } } .page-callout-content { padding-top: 0.75em; padding-right: 2em; }
NOT separately. inside the selector is easier to parse, and you avoid writing the selector twice