Skip to content

Latest commit

 

History

History
240 lines (192 loc) · 7.37 KB

css.md

File metadata and controls

240 lines (192 loc) · 7.37 KB

CSS

Notes for CSS features.

ARIA (attribute selectors + accessibility state)

What it is / problem solved: ARIA attributes (aria-*) mark up accessibility state in HTML. CSS can select on these attributes directly, so the same attribute that tells screen readers "this is expanded" also drives the visual style — no need for a parallel .is-open class that can drift out of sync with real state.

Docs: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors and https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA

How it works:

HTML: <button aria-expanded="false">Menu</button>
CSS:  button[aria-expanded="true"] { ... }
                  ^ single source of truth for both
                    accessibility tree AND visual style

Examples:

/* Style an accordion trigger when expanded */
[aria-expanded="true"] { background: #eef; }

/* Visually + semantically hide an element */
[aria-hidden="true"] { display: none; }

/* Flag invalid form fields */
[aria-invalid="true"] { border-color: red; }

/* Highlight current page in nav */
[aria-current="page"] { font-weight: bold; }

/* Style a disabled-looking but focusable control */
[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }

Flexbox

What it is / problem solved: A one-dimensional layout model for arranging items along a single axis (row or column) and distributing extra space between them. Solves the "align/space these items in a line" problem that used to require floats/hacks.

Docs: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout

How it works:

        main axis (justify-content) →
      ┌──────────────────────────────┐
      │ [item1]  [item2]  [item3]    │  ↕ cross axis
      └──────────────────────────────┘     (align-items)
display: flex on the container; flex-* props on children

Examples:

.container {
  display: flex;
  justify-content: space-between; /* spacing along main axis */
  align-items: center;            /* alignment along cross axis */
  gap: 1rem;                      /* spacing between items */
}

.item {
  flex: 1 1 200px; /* grow shrink basis — item can grow/shrink from 200px */
}

.nav {
  display: flex;
  flex-direction: column; /* stack items vertically instead of in a row */
}

.card-footer {
  display: flex;
  margin-left: auto; /* push item to the far end of the flex line */
}

Grid

What it is / problem solved: A two-dimensional layout system — rows and columns at once. Solves page/component layouts (headers, sidebars, content areas) that flexbox can only approximate with nesting.

Docs: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout

How it works:

grid-template-columns: 1fr 2fr 1fr
grid-template-rows: auto 1fr auto

+--------+------------+--------+
| header (spans all 3 columns) |
+--------+------------+--------+
| side   |  content   | aside  |
+--------+------------+--------+
| footer (spans all 3 columns) |
+--------+------------+--------+

Examples:

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* 3 equal columns */
  grid-template-rows: auto 1fr auto;
  gap: 1rem;
}

.sidebar {
  grid-column: 1 / 2; /* place explicitly in column 1 */
}

/* Responsive grid without media queries: as many 200px+ columns as fit */
.responsive-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

.header {
  grid-area: header; /* place via named area (see grid-template-areas) */
}

.layout {
  grid-template-areas:
    "header header"
    "sidebar content"
    "footer footer";
}

Animation

What it is / problem solved: @keyframes + animation (and the related transition property) animate CSS property changes over time, without JS. Solves state-change feedback (hover, load, loading spinners) cheaply and performantly (especially transform/opacity, which are GPU-accelerated).

Docs: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animations and https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_transitions

How it works:

transition: interpolates between two states (A → B) on a trigger (e.g. :hover)

@keyframes: defines a timeline of states, animation plays it (once or looped)

0% ─────────────────── 50% ─────────────────── 100%
state A               state C                 state B

Examples:

/* Transition: simplest case, animate on hover */
.button {
  transition: background-color 0.2s ease;
}
.button:hover { background-color: #333; }

/* Keyframe animation: continuous spin */
@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
.spinner { animation: spin 1s linear infinite; }

/* Keyframes with multiple stages */
@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.1); }
}
.badge { animation: pulse 2s ease-in-out infinite; }

/* Entrance animation, plays once */
@keyframes fade-in-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.toast { animation: fade-in-up 0.3s ease-out; }

Components (scoping & theming CSS to a component)

What it is / problem solved: A set of native CSS features (not one single feature) that let styles behave the way component-based JS frameworks expect: scoped to a component, themeable via variables, and responsive to the component's own size rather than the viewport. Solves style leakage/collision and "global CSS doesn't know about my component boundaries."

Docs:

How it works:

┌─ .card (container) ───────────────────┐
│  --card-padding: 1rem;   ← theming    │
│                                       │
│  @container (min-width: 400px) {...}  │  ← responds to *its own*
│                                       │     size, not the viewport
│  &:hover { ... }         ← nesting    │
└───────────────────────────────────────┘

Examples:

/* Custom properties: design tokens scoped to a component, overridable per-instance */
.card {
  --card-padding: 1rem;
  padding: var(--card-padding);
}
.card--compact { --card-padding: 0.5rem; }

/* Container queries: layout reacts to the component's own width */
.card-wrapper { container-type: inline-size; }
@container (min-width: 400px) {
  .card { flex-direction: row; }
}

/* :where() keeps specificity at 0, so consumers can override easily */
:where(.card, .panel) h2 { margin-top: 0; }

/* Native nesting: keep component styles visually grouped */
.card {
  border-radius: 8px;

  &:hover {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  }

  & .title {
    font-weight: 600;
  }
}