Pro-tip: Press space bar to progress and it won't skip any slides
For Practical Peoples
Prologue
Part 1
1%
33.333%
150%
.parent {
border-color: gray;
border-style: dashed;
}
.box {
width: 50%;
background: deepskyblue;
}
.box
em
1em
= Calculated font-size
of current element
1em
1.25em
3em
.box {
width: 2em;
background: deepskyblue;
}
.box-2 {
font-size: 2em;
width: 2em;
background: palegreen;
}
.box
.box-2
.box {
/* font-size: 16px; (default) */
width: 2em; /* 2em = 16px * 2 = 32px */
background: deepskyblue;
}
.box-2 {
font-size: 2em; /* 2em = 16px * 2 = 32px */
/* The 32px font-size will then change what
2em on the width means */
width: 2em; /* 2em = 32px * 2 = 64px */
background: palegreen;
}
rem
1rem
= Calculated font-size
of html
element
1rem
1.25rem
3rem
.box {
width: 2rem;
background: deepskyblue;
}
.box-2 {
font-size: 2rem;
width: 2rem;
background: palegreen;
}
.box
.box-2
ex
and ch
Based on the font that renders
1ex
1.25ex
15ex
1ex
= Calculated width of a lower-case x
1ch
1.25ch
15ch
1ch
= Calculated width of the number 0
.box {
font-family: monospace;
width: 25ch;
background: deepskyblue;
}
.box-2 {
font-family: sans-serif;
width: 25ch;
background: palegreen;
}
100vw
25vw
100vh
25vh
mm
millimetercm
centimeterin
inchpt
pointpc
picaWhen size should be proportionate to the unit's basis
Sized with em
Sized with px
A fallback, if you can't/shouldn't use a relative unit*.
* Most devs and teams I've known use pixels by default, while that has drawbacks, it's not "bad".
Special styles for specific circumstances
@media /* Conditions */ {
/* CSS Rules */
}
@media screen { /* Computer Display CSS Rules */ }
@media print { /* Print CSS Rules */ }
Fun fact: speech
, braille
, embossed
(braille printers), tty
(like command line), tv
also exist.
@media (min-width: 768px) {
/* CSS Rules */
}
/* OR the newest Comparison syntax */
@media (width >= 768px) { /* CSS Rules */ }
@media (min-width: 48em) and (min-height: 30em) {
/* CSS Rules */
}
@media (400px <= width <= 600px) {
/* Styles for viewports between 400px and 600px. */
}
@media
Best Practices@media
queries
Write min-width
and min-height
,
not max-width
or max-height
.box {
/* Mobile CSS */
}
@media (min-width: 48em) {
.box {
/* Decent size screen styles */
}
}
@media (min-width: 62em) {
.box {
/* Huge screen styles */
}
}
/* Widget Styles */
.widget { }
@media (min-width: 768px) {
.widget { }
}
/* Doo Dad Styles */
.doo-dad { }
@media (min-width: 768px) {
.doo-dad { }
}
@media (min-width: 768px) and screen {
/* Is screen necessary, do we want to exclude print? */
.widget { }
}
@media (min-width: 1024px) and (min-height: 768px) {
/* Is height necessary, should 750px tall screens be excluded? */
.widget { }
}
That means asking questions like:
Test from 350px - 1600px wide.
This screenshot is faked
Basics and terminology
Element surrounding the grid.
Direct child element of a grid container
Any line in the grid
.grid-container {
display: grid;
grid-template-columns: 25% 50% 25%;
}
Grid code examples stolen/modified from GridByExample.com, from Rachel Andrew
grid-column-start: 2;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 2;
grid-column-start: -3;
grid-column-end: -1;
grid-row-start: -2;
grid-row-end: -1;
grid-column-start: 1;
grid-column-end: -1;
.my-header {
grid-column: 1 / -1;
}
.my-content {
grid-column: 1 / span 2;
}
.my-sidebar {
grid-row: 2;
grid-column: 3;
}
grid-template-areas
Name regions in your grid.
.grid-container {
display: grid;
grid-template-columns: 25% 50% 25%;
grid-template-areas:
"header header header"
"content content sidebar"
"footer footer footer";
}
grid-area
Set location of grid items to a grid region.
.my-header { grid-area: header; }
.my-content { grid-area: content;}
.my-sidebar { grid-area: sidebar;}
.my-footer { grid-area: footer; }
.grid-container {
display: grid;
grid-template-columns: 50% 50%;
grid-template-areas:
'header header'
'content content'
'sidebar footer';
}
fr
Distributes free space in a grid track
grid-template-row: 1fr 50% 1fr;
1fr 1fr /* 50% 50% (Maybe) */
1fr 2fr 1fr /* 25% 50% 25% (Maybe) */
25% 1fr 1fr /* 25% 37.5% 37.5% (Maybe) */
minmax()
display: grid;
gap: 10px;
grid-template-columns:
minmax(200px, 1fr) 200px 200px;
repeat(number, size)
display: grid;
gap: 10px;
grid-template-columns: repeat(4, 100px);
grid-template-rows: repeat(3, auto);
auto-fit
and auto-fill
grid-template-columns: repeat(auto-fit, 150px)
grid-template-columns: repeat(auto-fill, 150px)
display: grid;
grid-template-columns:
repeat(auto-fit, minmax(180px, 1fr));
gap: 1rem;
You may assume this would have a good result:
.wrapper {
display: grid;
grid-template-columns: 25% 25% 25% 25%;
gap: 10px;
}
.wrapper {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 10px;
}
Fix the equal width grid with gutters yourself:
codepen.io/pen/RvBzrV
Try more CSSGridGarden.com
Or explore GridByExample.com
Basics and terminology
Element enclosing everything
Direct child of flex container
The axis the flex items are laid out on (row/column).
The opposite axis of the main (column/row)
The beginning of the main axis is where items start from, end is the opposite side.
The beginning of the cross axis will be top if flex is horizontal, left if it's vertical
.flex-container {
display: flex; /* All you need */
/* flex-direction: row; (Default) */
/* flex-wrap: nowrap; (Default) */
}
flex-wrap
.flex-container {
display: flex;
/* flex-direction: row; (Default) */
flex-wrap: wrap;
}
flex-direction
.flex-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
Examples of flex-direction
align-items
valuesalign-items: center;
align-items: baseline;
All of the previous properties applied to flex containers, these are for flex items.
order
Changes the visual order of the elements on the page.
.flex-item-3 {
order: 1;
}
order
is calculated like weight
in Drupal, heavier goes to the end, lighter goes to the top.
.flex-item-1 { /* Not set */ }
.flex-item-2 { order: -999; }
.flex-item-3 { order: 100; }
.flex-item-4 { order: 10; }
.flex-item-5 { /* Not set */ }
flex-grow
Distributes extra space to items that have a value
.flex-item-3 { flex-grow: 2; }
.flex-item-4 { flex-grow: 1; }
flex-shrink
When there isn't enough space items will shrink to fit
.flex-item-3 { flex-shrink: 2; }
.flex-item-4 { flex-shrink: 1; }
flex-basis
Sets initial size of flex item on the main axis, before flex-grow
or flex-shrink
are applied.
.flex-item-3 { flex-basis: 4em; }
.flex-item-4 { flex-basis: 2em; }
margin
and flex items💖auto
will use left over space to push as far as it can
.flex-item-3 {
margin: auto;
}
Try styling a menu for an up and coming (fake) industrialist super-power:
codepen.io/pen/rPrERx
Hint: Having A Complete Guide to Flexbox from CSS-Tricks.com open in another browser may come in handy!
Key Quality | Grid | Flexbox |
---|---|---|
Layout Specialty | 2d layout | 1d layout |
Prefers respecting | Layout (content conforms) |
Content (layout flexes) |
gap
align-[items/content]
align-self
justify-[items/content]
gap
With 1 value, it applies to rows and columns, 2 values set row, then column.
Formerly known as: column-gap/row-gap/grid-gap/grid-row-gap/grid-column-gap
.flex-container {
display: flex;
/* gap: 5px 10px; /* Sets row to 5px and column gap to 10px */
gap: 5px; /* Sets row and column gap to 5px */
}
justify-content
How extra space is distributed along the main axis
grid
is always horizontal..flex-container {
display: flex;
justify-content: center;
}
justify-content
valuesjustify-content: flex-start;
justify-content: flex-end;
justify-content
valuesjustify-content: space-between;
justify-content: space-around;
justify-content: space-evenly;
align-items
How extra space is distributed along the cross axis
.flex-container {
display: flex;
align-items: center;
}
align-items
valuesalign-items: stretch; /* (Default) */
align-items: flex-start;
align-items: flex-end;
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin rutrum nibh diam, et rhoncus nulla interdum vitae. Suspendisse ac quam justo. In ut enim faucibus, aliquet velit a, rhoncus mauris. Ut pharetra magna ac euismod gravida. Aenean fringilla ex sit amet est condimentum, fermentum dapibus diam finibus. Donec id tortor turpis. Morbi semper turpis quis posuere sagittis. Suspendisse ac pulvinar magna, a hendrerit arcu. Aenean dictum nunc sit amet libero fringilla, vel vulputate risus auctor. Vestibulum interdum vulputate nibh et sodales. Donec lorem nisi, mattis quis tempus sed, finibus at velit. Curabitur pharetra libero eget felis ornare finibus. Vivamus eget sollicitudin risus, eu lobortis est. Duis sed lectus a purus luctus fermentum. Duis consequat gravida ex, id pellentesque turpis finibus eu.
.column-container {
column-count: 3;
}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin rutrum nibh diam, et rhoncus nulla interdum vitae. Suspendisse ac quam justo. In ut enim faucibus, aliquet velit a, rhoncus mauris. Ut pharetra magna ac euismod gravida. Aenean fringilla ex sit amet est condimentum, fermentum dapibus diam finibus. Donec id tortor turpis. Morbi semper turpis quis posuere sagittis. Suspendisse ac pulvinar magna, a hendrerit arcu. Aenean dictum nunc sit amet libero fringilla, vel vulputate risus auctor. Vestibulum interdum vulputate nibh et sodales. Donec lorem nisi, mattis quis tempus sed, finibus at velit. Curabitur pharetra libero eget felis ornare finibus. Vivamus eget sollicitudin risus, eu lobortis est. Duis sed lectus a purus luctus fermentum. Duis consequat gravida ex, id pellentesque turpis finibus eu.
column-width
.column-container {
column-width: 9em;
}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin rutrum nibh diam, et rhoncus nulla interdum vitae. Suspendisse ac quam justo. In ut enim faucibus, aliquet velit a, rhoncus mauris. Ut pharetra magna ac euismod gravida. Aenean fringilla ex sit amet est condimentum, fermentum dapibus diam finibus. Donec id tortor turpis. Morbi semper turpis quis posuere sagittis. Suspendisse ac pulvinar magna, a hendrerit arcu. Aenean dictum nunc sit amet libero fringilla, vel vulputate risus auctor. Vestibulum interdum vulputate nibh et sodales. Donec lorem nisi, mattis quis tempus sed, finibus at velit. Curabitur pharetra libero eget felis ornare finibus. Vivamus eget sollicitudin risus, eu lobortis est. Duis sed lectus a purus luctus fermentum. Duis consequat gravida ex, id pellentesque turpis finibus eu.
gap
.column-container {
column-count: 3;
gap: 2em;
}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin rutrum nibh diam, et rhoncus nulla interdum vitae. Suspendisse ac quam justo. In ut enim faucibus, aliquet velit a, rhoncus mauris. Ut pharetra magna ac euismod gravida. Aenean fringilla ex sit amet est condimentum, fermentum dapibus diam finibus. Donec id tortor turpis. Morbi semper turpis quis posuere sagittis. Suspendisse ac pulvinar magna, a hendrerit arcu. Aenean dictum nunc sit amet libero fringilla, vel vulputate risus auctor. Vestibulum interdum vulputate nibh et sodales. Donec lorem nisi, mattis quis tempus sed, finibus at velit. Curabitur pharetra libero eget felis ornare finibus. Vivamus eget sollicitudin risus, eu lobortis est. Duis sed lectus a purus luctus fermentum. Duis consequat gravida ex, id pellentesque turpis finibus eu.
break-inside
.column-children {
break-inside: avoid;
}
The most basic and oldest layout method on the web.
<div>
has one default style, display: block
width
, height
margin
, padding
border
<strong>
, <em>
, <span>
)-or- the effects of cat grumpiness
position
Very useful, and often misused.
top, bottom, left, right
Change the location of "positioned" elements
z-index
Determines vertical layering of "positioned" elements
position: static;
Position's default value, these elements are not "positioned" so associated styles are ignored.
.element {
position: static;
top: 100px; /* Ignored, because position: static */
left: 50px; /* Static isn't considered "positioned" */
float: left;
}
position: relative;
Update the element from where it would rendered.
.element {
position: relative;
top: 25px;
left: 50px;
float: left;
}
position: absolute;
Update the element based on positioning of a "positioned" parent element
.element {
position: absolute;
top: 0;
left: 0;
float: left;
}
position: fixed;
Positions element to the window and element doesn't move when page scrolls.
.element {
position: fixed;
top: 100px;
left: 50px;
}
position: sticky;
Element will stick to defined position when page scrolls
(Not ready for prime time yet)
.element {
position: sticky;
top: 100px;
left: 50px;
}
position
position: absolute
.element {
position: absolute;
top: 0;
left: 0;
}
z-index
Some guidelines
Think in this order as a general rule:
position: absolute;
position: fixed;
margin
position: relative;
if top/right/bottom/left
are settransform/rotate/translate/skew/scale
Best meaning for the client, budget, or your sanity.
aspect-ratio
.blue-box {
width: 25%;
aspect-ratio: 2 / 1;
}
margin
and flex items❓margin
does not collapse inside of a flex container
.flex-item-3 {
margin-left: 2em;
margin-right: 2em;
}
.flex-item-4 { margin-left: 2em; }
margin
and grid itemsmargin
pushes on the grid area instead of adjacent elements.
/* Assuming left to right, top to bottom language, like English is: */
width/height ~ inline-size/block-size
margin-left/margin-right ~ margin-inline-start/margin-inline-end
margin-inline ~ margin-left + margin-right
border-top/border-bottom ~ border-block-start/border-block-end
border-block ~ border-top + border-bottom
top/bottom ~ inset-block-start/inset-block-end
left/right ~ inset-inline-start/inset-inline-end
/* Follows same rules as margin/padding values */
inset ~ top right bottom left
transform
transform: translate(x, y);
.element {
transform: translate(50px, 25px);
}
transform: translate(x);
.element {
transform: translate(50px);
}
transform: scale(x);
.element {
transform: scale(2);
}
transform: scale(x, y);
.element {
transform: scale(2, 0.5);
}
transform: rotate(deg);
.element {
transform: rotate(45deg);
}
transform: skew(deg, deg);
.element {
transform: skew(45deg, 15deg);
}
transform-origin: x, y;
.blue-element,
.red-element {
transform: rotate(45deg);
/* transform-origin: center center; Default */
}
.red-element {
transform-origin: left top;
}
Order matters!
.blue-element {
transform: translate(200px) rotate(45deg);
}
.red-element {
transform: rotate(45deg) translate(200px);
}
transition
.element {
transition: transform 1s;
}
.element:hover {
transform: translate(50px, 25px);
}
.element {
transition: transform 1s, background 3s;
}
.element:hover {
transform: translate(50px, 25px);
background: rgba(200, 0, 0, 0.6);
}
.blue-element { transition: transform 1s linear; }
.red-element { transition: transform 1s ease-in; }
.yellow-element { transition: transform 1s ease-out; }
.blue-element { transition-delay: 0; }
.red-element { transition-delay: 1s; }
.yellow-element { transition-delay: 2s; }
animation
@keyframes slide-in {
0% {
transform: translate(-15em);
opacity: 0;
}
100% {
transform: translate(0);
opacity: 1;
}
}
@keyframes slide-in { ... }
.element {
animation-name: slide-in;
animation-duration: 2s;
animation-iteration-count: infinite;
}
@keyframes slide-all-over {
0% {
transform: translate(-15em);
opacity: 0;
}
33% {
transform: translate(-10em, -5em);
}
66% {
transform: translate(-5em, 5em);
}
100% {
transform: translate(0);
opacity: 1;
}
}
If the desired animation can be done with transform, it should be.
.element {
animation-name: slide-in;
animation-duration: 2s;
animation-iteration-count: infinite;
}
/* If they prefer reduced motion, you can remove animation completely,
Or go with something that has minimal movement */
@media (prefers-reduced-motion: reduce) {
.element {
animation: none;
}
}
cubic-bezier()
Make your own animation timing!
Now with web site helper!:before
and :after
(aka pseudo-content)
<span>
Bare minimum is a selector, before or after, and the content attribute (which can be an empty string).
.element:before {
content: '';
}
This creates an empty invisible element.
.clearfix:after {
content: '';
display: table;
clear: both;
}
So long as it isn't necessary for the content to be understood.
.email-address:before {
content: 'Contact me at ';
}
someone@something.com
[data-label]:before {
content: attr(data-label);
display: inline-block;
margin-right: 0.5em;
padding: 0.25em 0.5em;
background: rgb(225, 200, 0);
color: rgb(100, 50, 0);
}
@media print {
main a[href]:after {
content: " (" attr(href) ") ";
}
}
I stole this idea from CSS Tricks
There are a lot of tools, Web AIM contrast checker is an easy one
Accessibility browser extensions like WAVE and Axe Devtools will test for this, but they have false positives sometimes
:focus
selector when adding :hover
selector*
.button:hover,
.button:focus {
background: #121399;
}
*In general, form elements are an exception, e.g. text input, select, checkbox, radio, etc. Having a separate hover vs focus is often preferred with them.
display: none;
visibility: hidden;
.element-invisible
.sr-only
text-indent: -9999em;
aka the Phark technique 🤓(and better mousing!)
*This is less applicable to links in the flow of text and content that isn't near more clickable elements
Photo by Wade Austin Ellis on Unsplash
body.html.page-node-X
#header
#header-wrapper h2,
body.html.page-node-X
#header
#header-wrapper
#block-views-view-name-block-1
> .view-view-name
> .view-content
> .views-row
> .row-inner
> .views-field-title,
body.html.page-node-X
#header
#header-wrapper
#block-views-view-name-block-1
> .view-view-name
.attachment
.view-heading,
#block-views-view-name-block-1
> .view-view-name
.attachment
body.html.page-node-X
#header
#header-wrapper
.view-heading,
body.html.page-node-X
#header
#header-wrapper
#block-views-view-name-block-1
> .view-view-name
.attachment
.view-view-name
.views-row
.views-field-title,
#block-views-view-name-block-1
> .view-view-name
.attachment
.view-view-name
.views-row
body.html.page-node-X
#header
#header-wrapper
.views-field-title {
display: block;
text-align: center;
line-height: 1.3em;
padding-top: 140px
}
tagname
Type/Tag (0, 0, 1)
.class-name
Class (0, 1, 0)
#id-name
ID (1, 0, 0)
*
Universal (0, 0, 0)
[attribute]
Attribute (0, 1, 0)
<div attribute-name="value"><div>
[attribute-name] [attribute-name='value'] [attribute-name*='lu'] [attribute-name^='val']
All of these are a specificity of (0, 1, 0)
>
Direct descendant (0, 0, 0)
~
General sibling (0, 0, 0)
+
Adjacent Sibling (0, 0, 0)
:hover, :focus
(0, 1, 0)
:first-child, :last-child
(0, 1, 0)
:empty
(0, 1, 0)
:checked
(0, 1, 0)
:nth-child
Pseudo-Classes:nth-child()
(0, 1, 0)
:nth-of-type()
(0, 1, 0)
:nth-last-child()
(0, 1, 0)
.article h4 a
.main-menu > li a
.bio-photo ~ .bio-name
.js .carousel .slide
#main .article a
(1, 1, 1)
#page #main a
(2, 0, 1)
h4.sidebar-title a
(0, 1, 2)
#main .article a
(1, 1, 1)
.article a
(0, 1, 1)
#page #main a
(2, 0, 1)
[id="main"] a
(0, 1, 1)
h4.sidebar-title a
(0, 1, 2)
.sidebar-title a
(0, 1, 1)
<article class="node node-news node-published node-not-promoted node-not-sticky clearfix" id="node-news-2" about="/page-url" typeof="foaf:Document">
<div class="field field-name-body field-type-text-with-summary field-label-hidden">
<div class="field-items">
<div class="field-item even" property="content:encoded">
<p>Hello World!</p>
</div>
</div>
</div>
</article>
.node-news .field-name-bodyThan this:
.node .field
Explicit classes are meant to target very specific elements, e.g. .widget__photo--captioned
Utility classes are meant to apply very specific styles, e.g. .text-align-center
Consider prefixing utility classes, e.g. .u-text-align-center
e.g. Lullabot.com Example
gr-
for giantrabbit.com) you know where it came from.sidebar .col-lg-3 {
text-align: right;
/* .col-lg-3 is intended for layout, not text treatment :( */
}
!important
unless you're overriding inline styles or another important that you can't remove..main-header .header-logo
header.main-header
.widget__title--featured
[id=”id-name”]
.my-widget[class][class]
nth-child
Tricksaka CSS variables
:root {
/* Setting a custom property */
--my-cool-var: #c00001;
}
.my-element {
/* Use the custom property with no fallback */
background-color: var(--my-cool-var);
/* Use it with a fallback, in case it isn't set */
background-color: var(--my-cool-var, #c00);
}
Technically it does, but in the real world it's low value and high cost.
See:
Performance Impact of CSS Selectors - Steve stevesouders
@import
will-change
to clue in browser to animationsfont-display
to prevent a web font from blocking render