CSS

Setting up a CSS file.

Reset

User agent styles

Chrome stylesheet

Example

Add this reset to your file (adapted from A Modern CSS Reset):

NOTE CSS In-depth recommended adding this to each stylesheet:

button,
input {
  font: inherit;
}

This might be taken care of by the * {... font: inherit; } ruleset below.

/* Box sizing rules */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Remove default margin */
* {
  margin: 0;
  padding: 0;
  /* inherit font so you can define styles 
  for h1, h* elements instead of rely on user 
  agent defaults */
  font: inherit;
}

/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
ul[role="list"],
ol[role="list"] {
  list-style: none;
}

/* Set core root defaults */
html:focus-within {
  scroll-behavior: smooth;
}

html,
body {
  height: 100%;
}

/* Set core body defaults */
body {
  text-rendering: optimizeSpeed;
  line-height: 1.2;
}

/* A elements that don't have a class get default styles */
a:not([class]) {
  text-decoration-skip-ink: auto;
}

/* Make images easier to work with */
img,
picture,
svg {
  max-width: 100%;
  display: block;
}

/* Remove all animations, transitions and smooth scroll for people that prefer not to see them */
@media (prefers-reduced-motion: reduce) {
  html:focus-within {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* button, */
input,
select,
textarea {
  width: 150px;
  padding: 0;
  margin: 0;
  box-sizing: border-box;

  font-family: inherit;
  font-size: 100%;

  /* removes system-level styling */
  appearance: none;
}

Set up variables

This example shows you how to set up variables for the entire site:

:root {
  --clr-accent-500: hsl(12, 60%, 45%);
  --clr-accent-400: hsl(12, 88%, 59%);
  --clr-accent-300: hsl(12, 88%, 75%);
  --clr-accent-100: hsl(13, 100%, 96%);

  --clr-primary-400: hsl(228, 39%, 23%);

  --clr-neutral-900: hsl(232, 12%, 13%);
  --clr-neutral-100: hsl(0 0% 100%);

  --ff-primary: "Be Vietnam Pro", sans-serif;

  --ff-body: var(--ff-primary);
  --ff-heading: var(--ff-primary);

  --fw-regular: 400;
  --fw-semi-bold: 500;
  --fw-bold: 700;

  --fs-300: 0.8125rem;
  --fs-400: 0.875rem;
  --fs-500: 0.9375rem;
  --fs-600: 1rem;
  --fs-700: 1.875rem;
  --fs-800: 2.5rem;
  --fs-900: 3.5rem;

  --fs-body: var(--fs-400);
  --fs-primary-heading: var(--fs-800);
  --fs-secondary-heading: var(--fs-700);
  --fs-nav: var(--fs-500);
  --fs-button: var(--fs-300);

  --size-100: 0.25rem;
  --size-200: 0.5rem;
  --size-300: 0.75rem;
  --size-400: 1rem;
  --size-500: 1.5rem;
  --size-600: 2rem;
  --size-700: 3rem;
  --size-800: 4rem;
  --size-900: 5rem;
}

@media (min-width: 50em) {
  :root {
    --fs-body: var(--fs-500);
    --fs-primary-heading: var(--fs-900);
    --fs-secondary-heading: var(--fs-800);

    --fs-nav: var(--fs-300);
  }
}

Forms

<body>
  <h1>Registration Form</h1>
  <p>Please fill out this form with the required information</p>

  <form action="https://register-demo.freecodecamp.org" method="post">
    <fieldset>
      <label for="first-name"
        >Enter Your First Name:
        <input id="first-name" type="text" name="first-name" required
      /></label>
      <label for="last-name"
        >Enter Your Last Name:
        <input id="last-name" type="text" name="last-name" required
      /></label>
      <label for="email"
        >Enter Your Email: <input id="email" type="email" name="email" required
      /></label>
      <label for="new-password"
        >Create a New Password:
        <input
          id="new-password"
          type="password"
          pattern="[a-z0-5]{8,}"
          name="new-password"
          required
      /></label>
    </fieldset>
    <fieldset>
      <label for="personal-account"
        ><input
          class="inline"
          id="personal-account"
          type="radio"
          name="account-type"
        />
        Personal Account</label
      >
      <label for="business-account"
        ><input
          class="inline"
          id="business-account"
          type="radio"
          name="account-type"
        />
        Business Account</label
      >
      <label for="terms-and-conditions">
        <input
          class="inline"
          id="terms-and-conditions"
          type="checkbox"
          name="terms-and-conditions"
          required
        />
        I accept the
        <a href="https://www.freecodecamp.org/news/terms-of-service/"
          >terms and conditions</a
        >
      </label>
    </fieldset>
    <fieldset>
      <label for="profile-picture"
        >Upload a profile picture:
        <input id="profile-picture" type="file" name="profile-picture"
      /></label>
      <label for="age"
        >Input your age (years):
        <input id="age" type="number" min="13" max="120" name="age"
      /></label>
      <label for="referrer"
        >How did you hear about us?
        <select id="referrer" name="referrer">
          <option value="">(select one)</option>
          <option value="1">freeCodeCamp News</option>
          <option value="2">freeCodeCamp YouTube Channel</option>
          <option value="3">freeCodeCamp Forum</option>
          <option value="4">Other</option>
        </select>
      </label>
      <label for="bio"
        >Provide a bio:
        <textarea
          id="bio"
          rows="3"
          cols="30"
          name="bio"
          placeholder="I like coding on the beach..."
        ></textarea>
      </label>
    </fieldset>

    <!-- The first input element with a type of submit is automatically set to submit its nearest parent form element. -->
    <input type="submit" value="Submit" />
  </form>
</body>

The related CSS stylesheet:

body {
  width: 100%;
  height: 100vh;
  margin: 0;
  background-color: #1b1b32;
  color: #f5f6f7;
  font-family: Tahoma, Geneva, Verdana, sans-serif;
  font-size: 16px;
}

label {
  display: block;
  margin: 0.5rem 0;
}

h1,
p {
  margin: 1em auto;
  text-align: center;
}

form {
  margin: 0 auto;
  max-width: 500px;
  min-width: 300px;
  width: 60vw;
  padding: 0 0 2em 0;
}

fieldset {
  border: none;
  padding: 2rem 0;
  border-bottom: 3px solid #3b3b4f;
}

fieldset:last-of-type {
  border-bottom: none;
}

/* 
fieldset:not(:last-of-type) {
   border-bottom: 3px solid #3b3b4f;
} */

input,
textarea,
select {
  width: 100%;
  margin: 10px 0 0 0;
  min-height: 2em;
}

.inline {
  /* unsets the 100% width */
  width: unset;
  margin: 0 0.5em 0 0;
  vertical-align: middle;
}

input,
textarea {
  background-color: #0a0a23;
  border: 1px solid #0a0a23;
  color: #fff;
}

input[type="submit"] {
  display: block;
  width: 60%;
  margin: 1em auto;
  height: 2em;
  min-width: 300px;
  font-size: 1.1rem;
  background-color: #3b3b4f;
  border-color: white;
}

input[type="file"] {
  padding: 1px 2px;
}

a {
  color: #dfdfe2;
}

HTML elements reference CSS Cheat sheet

Emmet

Official docs Emmet cheat sheet Keybindings plugin

Find key bindings with Ctrl + k then Ctrl + s.

Wrapper

.wrapper>h1{Title}+.content
<div class="wrapper">
  <h1>Title</h1>
  <div class="content"></div>
</div>

Auto-gen

Creates button:

button[type="button"]

Creates div

[data-selected]

Add text to auto-gen elements:

header>nav>ul>li*3{test}
<header>
  <nav>
    <ul>
      <li>test</li>
      <li>test</li>
      <li>test</li>
    </ul>
  </nav>
</header>

Dynamic auto-gen:

header>nav>ul>li*3{List Item $}
<header>
  <nav>
    <ul>
      <li>List Item 1</li>
      <li>List Item 2</li>
      <li>List Item 3</li>
    </ul>
  </nav>
</header>

Dynamic classes:

header>nav>ul>li*3.class-${List Item $}
<header>
  <nav>
    <ul>
      <li class="class-1">List Item 1</li>
      <li class="class-2">List Item 2</li>
      <li class="class-3">List Item 3</li>
    </ul>
  </nav>
</header>

Zero padding

header>nav>ul>li*3.class-${List Item $$}
<header>
  <nav>
    <ul>
      <li class="class-1">List Item 01</li>
      <li class="class-2">List Item 02</li>
      <li class="class-3">List Item 03</li>
    </ul>
  </nav>
</header>

Grouping

Group with parentheses:

(header>nav)+main+footer
<header>
  <nav></nav>
</header>
<main></main>
<footer></footer>

Complex example:

(header>h2{Heading}+nav>li*5>a{Link $})+main+footer
<header>
  <h2>Heading</h2>
  <nav>
    <li><a href="">Link 1</a></li>
    <li><a href="">Link 2</a></li>
    <li><a href="">Link 3</a></li>
    <li><a href="">Link 4</a></li>
    <li><a href="">Link 5</a></li>
  </nav>
</header>
<main></main>
<footer></footer>

Forms

form:post>.group>input:text
<form action="" method="post">
  <div class="group"><input type="text" name="" id="" /></div>
</form>
form:post>(.group>label+input:text)+(.group>label+input:number)
<form action="" method="post">
  <div class="group">
    <label for=""></label><input type="text" name="" id="" />
  </div>
  <div class="group">
    <label for=""></label><input type="number" name="" id="" />
  </div>
</form>

SVG (Scalable Vector Graphics)

SVGs scale to any size without losing quality or increasing file size, and you can modify them with CSS or JS.

Play around with it here: SvgPathEditor.

Free libraries

Misc

Use cases

  • Icons
  • Graphs/Charts
  • Large, simple images
  • Patterned backgrounds
  • Applying effects to other elements via SVG filters

Anti-use cases

Inefficient for storing complex images.

Anatomy

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <rect x="0" y="0" width="100" height="100" fill="burlywood" />
  <path
    d="M 10 10 H 90 V 90 L 10 60"
    fill="transparent"
    stroke="black"
    stroke-width="3"
  />
  <circle cx="50" cy="50" r="20" class="svg-circle" />
  <g class="svg-text-group">
    <text x="20" y="25" rotate="10" id="hello-text">Hello!</text>
    <use href="#hello-text" x="-10" y="65" fill="white" />
  </g>
</svg>
  • xmlns: XML namespace. Specifies the XML dialect that you are using so the browser can render the SVG correctly.

  • viewBox: Defines the bounds of the SVG—the positions of different points of the SVG elements in the following order:

    • min-x, min-y, width, and height

    Also defines the aspect ratio (ratio of width to height) and the origin (the image’s origin of motion for an animation).

  • class, id: Same funciton as in CSS or JS.

  • <circle>, <rect>, <path>, <text>, other elements: Defined by the SVG namespace that let you build SVGs.

    CSS tricks SVG Elements by Category

  • fill and stroke: Properties that you can edit with CSS and JS.

    Properties shared between CSS and SVG

    SVG CSS Properties

Embedding SVGs

  1. Link with an <img> tag or with background-image: url(./path/to/.svg);
    • You cannot edit these SVGs.
  2. Embed it in the HTML file.
    • Makes HTML harder to read
    • Page is less cacheable
    • Slows HTML loading

You can minimize these drawbacks with React or Webpack.

Tables

CSS properties

background

MDN docs CSS Tricks

Includes 8 properties that can do the following:

  • change background color
  • add background images
  • change position and size of background images
  • repeat or tile the images
  • create background layers

box-shadow

MDN docs

Adds effects around elements.

overflow

MDN docs CSS Tricks

How an elment behaves when its content is too big.

opacity

MDN docs

Sets the opacity.

Advanced selectors

MDN combinators

Pseudo-classes

MDN classes vs elements MDN docs

Classes use a single colon and target elements that already exist in the HTML. Some common ones are:

  • :focus
  • :hover
  • :active

Structural pseudo-classes:

  • :root that represents the very top level of your document

  • :first-child

  • :last-child

  • :empty for elements that have no children at all

  • :only-child for elements that do not have any siblings

  • :nth-child

    .myList:nth-child(5) {
      /* Selects the 5th element with class myList */
    }
    
    .myList:nth-child(3n) {
      /* Selects every 3rd element with class myList */
    }
    
    .myList:nth-child(3n + 3) {
      /* Selects every 3rd element with class myList, beginning with the 3rd */
    }
    
    .myList:nth-child(even) {
      /* Selects every even element with class myList */
    }
    

Pseudo-elements

MDN docs

Elements use a double colon and target elements that do not normally exist or are not elements at all:

  • ::marker style li bullets or numbers
  • ::first-letter
  • ::first-line
  • ::selection change styling when user selects text on the page.
  • ::before
  • ::after

Advanced selectors

Complete list MDN attribute selectors Complex Selectors CSS Tricks: Taming Advanced CSS Selectors CSS Tricks: The Skinny on CSS Attribute Selectors

Select and style any attribute:

  • [attribute]
  • selector[attribute]
  • [attribute="value"]
[src] {
  /* This will target any element that has a src attribute. */
}

img[src] {
  /* This will only target img elements that have a src attribute. */
}

img[src="puppy.jpg"] {
  /* This will target img elements with a src attribute that is exactly "puppy.jpg" */
}
  • [attribute^="value] match from the start
  • [attribute$="value"] match from the end
  • [attribute*="value] match anywhere inside the string
[class^="aus"] {
  /* Classes are attributes too!
    This will target any class that begins with 'aus':
    class='austria'
    class='australia'
  */
}

[src$=".jpg"] {
  /* This will target any src attribute that ends in '.jpg':
  src='puppy.jpg'
  src='kitten.jpg'
  */
}

[for*="ill"] {
  /* This will target any for attribute that has 'ill' anywhere inside it:
  for="bill"
  for="jill"
  for="silly"
  for="ill"
  */
}

CSS Functions

Practical use cases MDN complete list of functions min(), max(), clamp() info

calc()

You can nest calc():

:root {
  --header: 3rem;
  --footer: 40px;
  --main: calc(100vh - calc(var(--header) + var(--footer))); /*
  --main: calc(100vh - (3rem + 40px))
  */
}

min()

Applies the smaller value to the element:

img {
  width: min(150px, 100%);
}

If there is 150px available to the image, then it uses it. Otherwise, the image is set to 100% of its parent element.

You can also see this as “at maximum, the image is 150px wide”

max()

Applies the larger value to the element:

img {
  width: min(100px, 4em, 50%);
}

If there is enough viewport size to apply 4em or 50%, then it is applied. If there isn’t, the image is 100px wide.

clamp()

Makes elements fluid and responsive. Accepts 3 values:

  • smallest val
  • ideal val
  • largest val
h1 {
  font-size: clamp(320px, 80vw, 60rem); /*
  font-size: clamp(smallest, ideal, largest); */
}

Custom properties

CSS variables that you can use within the context or scope that they are defined.

Fallback values

.fallback {
  --color-text: white;

  background-color: var(--undeclared-property, black);
  color: var(--undeclared-again, var(--color-text, yellow));
}

Scope

The scope of a custom property includes the selector that the custom property was delcared in, and any descendants of that selector.

To make custom properties globally available, put them on the :root selector:

:root {
  --custom-prop: value;
}

Themes with custom properties

You can add dark and light themes with custom properties. First, create the theme colors with class styles on the :root element:

:root.dark {
  --border-btn: 1px solid rgb(220, 220, 220);
  --color-base-bg: rgb(18, 18, 18);
  --color-base-text: rgb(240, 240, 240);
  --color-btn-bg: rgb(36, 36, 36);
}

:root.light {
  --border-btn: 1px solid rgb(36, 36, 36);
  --color-base-bg: rgb(240, 240, 240);
  --color-base-text: rgb(18, 18, 18);
  --color-btn-bg: rgb(220, 220, 220);
}

/* apply custom props to elements below */

Then, use JS to grab the root element (documentElement), and toggle the theme:

let setTheme = () => {
  const root = document.documentElement;
  const newTheme = root.className === "dark" ? "light" : "dark";
  root.className = newTheme;

  document.querySelector(".theme-name").textContent = newTheme;
};

document.querySelector(".theme-toggle").addEventListener("click", setTheme);

prefers-color-scheme media query

You can also set the theme according to the user agent settings. If you have the user agent set to dark, then this media query sets the styles to the dark theme. The media query accepts only light and dark as arguments:

:root {
  --border-btn: 1px solid rgb(36, 36, 36);
  --color-base-bg: rgb(240, 240, 240);
  --color-base-text: rgb(18, 18, 18);
  --color-btn-bg: rgb(220, 220, 220);
  --theme-name: "light";
}

@media (prefers-color-scheme: dark) {
  :root {
    --border-btn: 1px solid rgb(220, 220, 220);
    --color-base-bg: rgb(18, 18, 18);
    --color-base-text: rgb(240, 240, 240);
    --color-btn-bg: rgb(36, 36, 36);
    --theme-name: "dark";
  }
}

/* element styles below */

Browser compatibility

Can I use

  • Major web browsers pretty much share the same compatibility features.

  • On IoS, Safari is the only supported browser. When you install Chrome or Firefox, they use the Safari rendering engine.

    For more info, read this.