Skip to content
Go back

CSS Styling Pattern

Table of contents

Open Table of contents

Modern CSS

Modern CSS refers to the various tooling and support that has grown to support CSS for ease of modern development.

<div class="container">
  <div class="card">
    <h2>Adaptive Title</h2>
    <p>This text stays the same, but the title responds to the box size!</p>
  </div>
</div>
/* 1. Define the container 
    container-type designates this as a container
*/
.container {
  container-type: inline-size;
  width: 100%; /* Or any width; the child reacts to this */
}

/* 2. Default mobile-first style */
.card h2 {
  font-size: 1rem;
  color: gray;
}

/* 3. Style based on the container's width (not the screen!) 
    Notice we can define a conditional based on the container width not the screen width; so we don't have to care about screen rules
*/
@container (width > 500px) {
  .card h2 {
    font-size: 2rem;
    color: blue;
  }
}
/* Default style for all articles */
article {
  border: 1px solid #ccc;
  padding: 1rem;
  margin-bottom: 1rem;
}

/* Styles applied ONLY to an article that has an <img> descendant */
article:has(img) {
  border: 2px solid blue;
  background-color: #f0f8ff; /* Light blue background */
}

Before nesting, you would have to write it like so above. You can declare a conditional styling based on .card and then condition further style for a specific element tag as .card header. Note this will condition EVERY header even multiple children away.

/* Without nesting */
.card {
  border: 1px solid lightgrey;
}

.card header {
  border-bottom: 1px solid lightgrey;
  background: #f1f3f4;
}

/* With native CSS nesting */
.card {
  border: 1px solid lightgrey;
  border-radius: 6px;
  overflow: hidden;

  header {
    border-bottom: 1px solid lightgrey;
    background: #f1f3f4;
    padding: 16px;
  }
}
/* Styling a link inside a paragraph, including hover effects */
p.example {
  font-family: system-ui;

  & > a {
    /* Equivalent to p.example > a */
    color: tomato;

    &:hover, /* Equivalent to p.example > a:hover */
    &:focus {
      /* Equivalent to p.example > a:focus */
      color: ivory;
      background-color: tomato;
    }
  }
}

The above css declare styling for a paragraph tag (p) with class “example” AND > (child combinator) will ONLY apply to the direct child.

<p class="example">
  <a href="#">This link WILL be styled</a>
</p>

This styles based a media query that the viewport is 960px or larger.

article {
  padding: 1rem;

  @media (width >= 960px) {
    font-size: 2rem;
  }
}
/* 1. Declare the order of layers (lowest to highest precedence) */
@layer base, theme;

/* 2. Styles in the 'base' layer (lower precedence) */
@layer base {
  .text {
    color: grey; /* This will be overridden */
  }
  p {
    font-size: 1rem;
  }
}

/* 3. Styles in the 'theme' layer (higher precedence) */
@layer theme {
  p {
    color: aqua; /* This color wins, even with a less specific selector */
  }
  .text {
    font-style: italic;
  }
}
.box {
  margin-inline-start: 20px;
  padding-block-start: 10px;
  border-inline-end: 2px solid red;
  inline-size: 100px; /* Use inline-size instead of width */
}

Additional Tricks

Common Pattern

You define a globals.css file which will contain the theme.

@layer theme {
  :root {
    /* Colors & Textures */
    --ink-black: #1a1a1a;
    --washi-paper: #f9f7f2;
    --washi-texture: url("/4093px-texture.webp");

    /* Fonts */
    --font-sumi: "Geist Mono", monospace;
  }
}
/* global.css*/

For every component, you write two files:

.container {
  /* Use the global DNA */
  background-color: var(--washi-paper); /*Notice it pulls from global*/
  font-family: var(--font-sumi);

  /* Create a local "hook" for density */
  opacity: var(--ink-density, 1);

  /* Layout logic */
  display: grid;
  position: relative;
}
import styles from "./Panel.module.css";

export default function SumiPanel({ density = 1.0, children }) {
  return (
    <article className={styles.container} style={{ "--ink-density": density }}>
      {children}
    </article>
  );
}

Share this post on:

Next Post
WaterStrokes