Joshua's Docs - CSS and General Styling - Cheatsheet, Common Issues, Etc.
Light

Resources

UI Inspiration

Different frameworks and tools

Cheatsheet


CSS Transitions

Syntax:

div {
	transition: <property> <duration> <timing-function> <delay>;
}

Example:

div {
	transition: all 2s ease 1s;
}

CSS Transitions - Multiple Properties Shorthand

To declare transitions for multiple properties, with shorthand, you have two main options:

1 - Comma separate shorthand declarations:

.myClass {
	transition: width .5s linear, color .5s ease-in-out;
}

2 - Overrides

.myClass {
	/* Unlike the above method, this requires all props to share common base settings  */
	transition: all .5s linear;
	/* This overrides the `all` from above */
	transition-property: width, color;
}

I found this out, thanks to this S/O answer

CSS Transitions - Common Things to Remember

  • You can target transform as a property to transition
    • You can use this to build a scaling transition, for example

Extracting CSS

Chrome supports extracting all the CSS of an element via (Inspect Element) -> Right Click Node -> Copy -> Copy styles. I believe this feature was dropped and then added back - full writeup here.

There are also browser extensions too, like Snappy Snippet, or visbug.


Globals, variables, and theming

Can I use: Browser Support. Note that IE 11 has no support. You can use something like webpack to transform the dynamic variables refs into static. See this. Or you can simply define the CSS value twice, first with a non-variable value that will be the fallback, and then with the variable. On older browsers it should just use the non-variable fallback.

CSS variables (more accurately custom properties) are notated with a double-dash prefix. You can declare them at multiple levels, and are inherited from parents (scoped).

CSS:

.vendorWidget {
	--primaryColor: red;
	--secondaryColor: blue;
}
.vendorButton {
	background-color: var(--primaryColor);
}

HTML:

<div class="vendorWidget">
	<button class="vendorButton">Click Me!</button>
</div>

To emulate theming, a common approach is to declare global variables at the highest level. In CSS, there is a trick you can use instead of guessing the element with the highest specificity: just target :root. (MDN).

:root {
	--loosePaddingPx: 14px;
	--tightPaddingPx: 4px;
	--primaryColor-light: #BEFFFF;
	/* You can mix vars and non-vars */
	background-color: red;
}

CSS Variable Fallbacks:

You can define a fallback in case a variable is undefined:

.myButton {
	background-color: var(--myVar,red);
}

If you want to try a few different vars, and keep falling back if undefined, you can nest them:

.myButton {
	background-color: var(--myVar,var(--secondaryVar,red));
}

Note that fallbacks are not the same as polyfilling or providing defaults for if a browser does not support custom properties. You can use a polyfill library to do that, or repeat each property twice, first with a default fallback, and then with the variable, like so:

.myButton {
	background-color: red;
	background-color: var(--myVar,var(--secondaryVar,red));
}

Using CSS Variables in RGBA Color Properties

The easiest way (currently) to define CSS variables in a way that supports using them with rbga(), so you can easily tweak alpha, is to declare them like so:

.selector {
	--cta: #1a83d6;
	/** This is the RGB of the above HEX value */
	--ctaRGB: 26, 131, 214;
}

By declaring a separate version of the variable that has the RGB values as comma separated integers, you can easily pull it into places with RGBA:

.selector button {
	/** Use cta color, with half opacity */
	background-color: rgba(var(--ctaRGB), 0.5);
}

📄 For a more detailed look into this approach, check out this blog post

Creating Derived Colors From CSS Variables

CSS lacks built-in functions to manipulate color objects (like darken() in SASS), but with some creative variable declaration, you can get around this. By splitting up your color value into its separate parts (either H-S-L or R-G-B), you can later combine them and manipulate them with ease.

:root {
	--primary: #e1e0ff;
}

Or, if you wanted to be able to manipulate this color in any way you want:

:root {
	/** It is a good idea to still have the full HEX as a value */
	--primary: #e1e0ff;
	/** RGB */
	--primary-r: 225;
	--primary-g: 224;
	--primary-b: 255;
	/** HSL */
	--primary-h: 242;
	--primary-s: 100%;
	--primary-l: 94%;
}

Now, coming up with some derived colors is much easier:

  • Equivalent to SASS's darken($primary, 20%)
    • --primary-dark-20: hsl(var(--primary-h), var(--primary-s), calc(var(--primary-l) - 20%));
  • Equivalent to SASS's lighten($primary, 5%)
    • --primary-light-20: hsl(var(--primary-h), var(--primary-s), calc(var(--primary-l) + 5%));
  • Changing opacity on the fly (example: half opacity)
    • --primary-opaque-50: rgba(var(--primary-r), var(--primary-g), var(--primary-b), 0.5);
    • See above section too:

Here are some great resources on using CSS properties in this way (and more advanced) ways:

Theme Switching

There are a bunch of ways to accomplish this. I've written up a comprehensive exploration of options at https://joshuatz.com/posts/2019/coding-a-css-theme-switcher-a-multitude-of-web-dev-options/

Accessing CSS Variables with JavaScript:

/**
 * === Setting Values ===
 */

// This will target :root variables
document.querySelector(':root').style.setProperty('--myColor', newColor);
// Or, same thing...
document.documentElement.style.setProperty('--myColor', newColor);

/**
 * === Reading Values
 */
document.documentElement.style.getPropertyValue('--myColor');
// Or, for computed values
getComputedStyle(document.querySelector(':root')).getPropertyValue('--myColor')

Sass/Scss


Targeting the first element of something

First child, regardless of type

Use the :first-child pseudo class / selector.

.parent div:first-child {
	border-top: 1px solid black;
}
.parent div {
	border-bottom: 1px solid black;
}

The above code is nice because it gives both top and bottom borders to only the first element, and then bottom borders to the rest. If I added top and bottom to all children, then elements after the first would end up with double borders (the tops and bottoms would combine).

Note: this requires that the targeted element is a direct child of the parent selector

First child of certain element type

If we have a bunch of mixed element types, first-child would both not make sense, and might not work too. Consider this kind of setup:

<div class="root">
	<div class="abcd">
		<div>I'm the first child of abcd</div>
		<!-- Element below is my actual target -->
		<span class="target">Hello</span>
	</div>
	<span class="target">World.</span>
	<span class="target">How are you?</span>
</div>
<style>
.target {
	background-color: blue;
}
</style>

Let's say I wanted to make the first <span> have a red background, but all the rest have blue. I can't use first-child, because it is not the first child of div.abcd. I could use the nth-child() rule, like .abcd .target:nth-child(2) { background-color: red; }, but that would require that the order always stay the same. What if I add another div in front of it?

A better option is the newer :first-of-type pseudo selector:

.abcd span:first-of-type {
	background-color: red;
}

Note that by type, the rule is referring to the type of element, not a selector. If you try to do something like abcd .target:first-of-type, it won't work, because .target is a class selector, not a type of element.

Targeting All Children AFTER the First Child

If you have a bunch of children and you want to apply styling to only those that come after the first one, you have a great use-case for the nth-child() pseudo selector. For example, imagine that you have a unordered list, and you want to add a border between each list item. Border-top would work, but you would have to omit the first child - which you can do so with nth-child:

<ul>
	<li>First</li>
	<li>Second</li>
	<li>Third</li>
	<li>Last!</li>
</ul>

<style>
/** This will target the 2nd child, 
 * and every +1 item after (`1n+2`)
 */
ul li:nth-child(1n+2) {
	border-top: 3px dashed red;
}
</style>

🔗 CodePen Demo


Unusual / Fun selectors to remember

📄 MDN: CSS Selectors

Code What Notes
div[data-ref*="23"] Attribute Selector See "Attribute Selector Cheatsheet" below
:not(___) Negation pseudo-class selector Use to select those elements not matching selector

You can use multiple comma separated selectors, just like normal

Cannot nest other pseudo-selectors
:target Target pseudo-class selector Targets the element that has an id value that matches the current URL fragment (hash value).

Useful for animating elements that have just been "jumped" (or scrolled) to, adding sticky offsets, etc.

Given a URL of example.com#faq, :target{} would match <section id="faq"></section>.
:scope Scope pseudo-class selector The main benefit to this comes when using JavaScript; when this selector is used inside of scoped queries (e.g. myElement.querySelector()), the :scope part acts like the element your query is scoped to.

This enables certain queries that were previously impossible; such as selecting direct children of an element while inside the scope:
    myElement.querySelector(':scope > *')
:nth-child nth-child pseudo-class selector Target elements based on their order / position among siblings, and/or offset.

Attribute Selector Cheatsheet

Full list and details on MDN.

Short Practical Example What
{elem}[attr] or [attr] script[async] Matches any input that has attribute of id, regardless of value
[attr="value"] script[src="https://www.google-analytics.com/analytics.js"] Attribute must exactly match value
[attr*="value"] script[src*="analytics"] Attribute must contain value
[attr~="value"] [data-color-scheme~="red"] Attribute must be a string of whitespace separated words, and the value must exactly match one of them.
[attr^="value" script[src^="https://www.google-analytics.com"] Attribute must start with exact value
[attr$="value"] script[src$="analytics.js"] Attribute must end with exact value
`[attr ="value"]` `script[src

Note: You can add i before the closing brackets to force a case insensitive match. Like: script[src*="gOOgle"i]

Note: You can target by any attribute, including value. This has led to a notable CSS-only hack (HN) that can listen for specific characters and report back to an external server (bad for password fields!). Note, this only works if JS is updating the value attribute as the user types. In an "uncontrolled" field, this doesn't work.

Question: [attr~="val"] vs [attr*="val"]

Since the description for [attr~="val"] can be a little confusing, here is a very simple demonstration of its difference and the value it brings - a table of matches:

DOM [animals*="cat"] [animals~="cat"]
<div animals="dog cattle bird"> Yes No
<div animals="dog cat bird"> Yes Yes

Calculations

As usual, CSS-Tricks has an excellent guide on the topic: "A Complete Guide to Calc in CSS"

Evaluating Calculations

There are a limited number of ways to evaluate a calc() statement and read the result:

  • Apply the rule, then use JavaScript's getComputedStyle(MY_ELEMENT) to read the result
  • Apply the rule, then use the browser DevTool's computed tab

Aspect Ratios

Eventually, this will be very easy to do with the new aspect-ratio property:

.vidPreview {
	aspect-ratio: 16 / 9;
}

However, only around 65% of browsers currently support this new property. The old-school way to maintain an aspect ratio is with the padding-top approach. By specifying padding-top with a percentage equal to height / width:

<div class="container">
	<div class="content">
		<!-- Actual content -->
	</div>
</div>

<style>
.container {
	position: relative;
	width: 100%;
	padding-top: calc(9 / 16 * 100%); /** 16:9 aspect ratio */
	/** You could also hard-code padding-top instead of using calc() */
}

.content {
	position: absolute;
	top: 0;
	width: 100%;
	height: 100%;
}

🔗 CodePen Demo


Grid Layout

Some tools:

Flexbox Layout

Flexbox Tools

These are tools that help with building, debugging, and understanding flex based layouts.

Flexbox Use Cases

These are collections of use-cases showing how Flexbox can be used to solve common design problems

Aligning Items in Flex Layouts

Aligning single items in a flex layout can be a little confusing, especially since there is no justify-self property. However, this StackOverflow response is one of the best summaries of different axis alignment scenarios and how to implement them.

Flexbox Frameworks

  • Flexbox Grid
    • Micro-framework, based on Flexbox, which provides handy 12-column system

Flex-Forgetful

Here are some things I'm jotting down, since I commonly forget them and need a quick reminder:

  • How to force a flex child to take up 100% height (of its parent)
    • For specific children: instead of height: 100% on children, replace with align-self: stretch
    • For all children, on the parent use align-items: stretch
    • More answers here
  • How to add margins between items
    • In general, there is nothing preventing the use of margin on flex children
    • If you need minimum spacing between items while allowing for easy column layout, you can try some of the approaches from this StackOverflow
      • The OP actually has a good trick: negative margin on flex container to offset minimum margin of container items
    • If you need vertical separation between flex children that have overflowed into a new row
      • You can add margin-top or margin-bottom to all flex container items (e.g. .row > * {})
      • You can use the negative margin trick from above to avoid adding too much extra height to your flex container
  • How to make an isolated overflow child align to the left or right if it is the only item in a row?
  • Why are my images (<img>) getting squished inside flex?
    • Change image's align-self to center or start
    • See this SO

Boilerplate CSS

I've moved the content that was here to my snippets folder 👉 snippets/css

Markdown Source Last Updated:
Mon Aug 02 2021 16:57:53 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Mon Aug 19 2019 17:06:24 GMT+0000 (Coordinated Universal Time)
© 2021 Joshua Tzucker, Built with Gatsby
Feedback