Advanced CSS

Foundations · Prereqs: CSS Essentials
--- theme: default routerMode: hash favicon: https://oim3690.github.io/favicon.svg titleTemplate: "%s - OIM3690" title: "CSS Advanced (Reference)" info: | Reference deck: CSS variables, specificity & !important, transitions & animations, transforms, frameworks (Tailwind/Bootstrap), CSS art, modern CSS <br><br> <b>Custom:</b> <kbd>t</kbd> Timer · <kbd>T</kbd> Start/pause · <kbd>w</kbd> Draw <br> <b>Slidev:</b> <kbd>o</kbd> Overview · <kbd>d</kbd> Dark mode · <kbd>f</kbd> Fullscreen · <kbd>←</kbd> <kbd>→</kbd> Navigate --- # CSS Advanced ## Variables · Animation · Frameworks · Modern CSS --- layout: center --- # CSS Variables --- # CSS Variables (Custom Properties) Define a value once, reuse it everywhere: ```css :root { --brand: #3b82f6; --gap: 16px; } .button { background: var(--brand); } .card { padding: var(--gap); } ``` Change `--brand` in one place and every use updates. --- # Why Variables Matter - **Theming**: one source of truth for colors, spacing, fonts - **Dark mode**: swap variable values instead of rewriting rules - AI generates them constantly in design systems > 🤖 **AI tip:** When AI hands you a `:root` block of `--` variables, re-theme by editing those values, not by touching each component. --- layout: center --- # Specificity & `!important` --- # When Your CSS "Won't Apply" Usually specificity: a more specific rule is winning. ```css /* AI wrote this */ #header .nav a { color: blue; } /* You added this, but it loses */ a { color: red; } ``` The ID plus class selector outranks the plain `a`, so the link stays blue. --- # `!important` (Use Sparingly) `!important` overrides normal specificity: ```css a { color: red !important; } ``` It works, but it starts an "!important war" that is hard to undo later. > 🤖 **AI tip:** Before reaching for `!important`, open DevTools, find the winning rule, and match its specificity instead. --- layout: center --- # Transitions & Animations --- # Transitions: Smooth Changes A transition eases a property from one value to another: ```css .button { background: #3b82f6; transition: background 0.3s ease; } .button:hover { background: #1d4ed8; } ``` Instead of snapping, the color fades over 0.3 seconds. --- # ▶️ Transition Edit the CSS on the left, then hover the button. Try changing `0.2s` to `2s`: <CssPlayground :code="`.demo-btn { padding: 0.6rem 1.5rem; border: none; border-radius: 8px; background: #3b82f6; color: white; cursor: pointer; transition: transform 0.2s ease, background 0.2s ease; } .demo-btn:hover { transform: scale(1.1); background: #1d4ed8; }`"> <button class="demo-btn">Hover me</button> </CssPlayground> --- # Timing Functions ```css transition: transform 0.5s ease; /* slow start and end (default) */ transition: transform 0.5s linear; /* constant speed */ transition: transform 0.5s ease-in; /* slow start */ transition: transform 0.5s ease-out; /* slow end */ transition: transform 0.5s ease-in-out; /* slow both ends */ ``` `ease` is the default and fits most cases. --- # Keyframes: Multi-Step Animations Keyframes play automatically, in steps: ```css @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } } .badge { animation: pulse 2s ease-in-out infinite; } ``` --- # Animation Properties ```css .element { animation-name: pulse; animation-duration: 2s; animation-timing-function: ease-in-out; animation-iteration-count: infinite; animation-direction: alternate; } /* Shorthand */ .element { animation: pulse 2s ease-in-out infinite alternate; } ``` --- # ▶️ Keyframes Edit the animations and watch them loop. Try changing `1.4s` or `scale(1.4)`: <CssPlayground :code="`.demo-pulse { width: 44px; height: 44px; border-radius: 50%; background: #ef4444; animation: pulse 1.4s ease-in-out infinite; } @keyframes pulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.4); opacity: 0.5; } } .demo-spin { width: 44px; height: 44px; border-radius: 50%; border: 4px solid #cbd5e1; border-top-color: #3b82f6; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } }`"> <div class="flex gap-8 items-center"> <div class="demo-pulse"></div> <div class="demo-spin"></div> </div> </CssPlayground> --- # Transitions vs Keyframes | Use a transition when | Use keyframes when | |---|---| | Reacting to hover, click, focus | The animation runs on its own | | A simple one-step change | Multiple steps or a sequence | | Interactive feedback | Spinners, looping attention effects | --- # Performance & Accessibility - Animate **`transform`** and **`opacity`** (GPU-friendly) - Avoid animating `width`, `height`, `margin` (they trigger layout) - Respect users who prefer less motion: ```css @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } } ``` --- layout: center --- # Transforms --- # Transforms `transform` moves, scales, or rotates without affecting layout. Hover the boxes, then edit the values: <CssPlayground :code="`.tf-box { width: 78px; height: 78px; display: flex; align-items: center; justify-content: center; background: #3b82f6; color: white; border-radius: 8px; cursor: pointer; transition: transform 0.25s ease; } .tf-scale:hover { transform: scale(1.15); } .tf-rotate:hover { transform: rotate(15deg); } .tf-move:hover { transform: translateY(-12px); }`"> <div class="flex gap-4"> <div class="tf-box tf-scale">scale</div> <div class="tf-box tf-rotate">rotate</div> <div class="tf-box tf-move">move</div> </div> </CssPlayground> --- layout: center --- # CSS Frameworks --- # Why CSS Frameworks? Writing CSS from scratch for every project is slow. Frameworks give you: - **Pre-built styles**: buttons, cards, forms ready to use - **Consistent design** out of the box - **Responsive by default** > Frameworks are what AI reaches for. Learning to **read** them matters more than memorizing them. --- # Two Approaches | Component-based | Utility-first | |---|---| | Pre-built components | Small single-purpose classes | | Add a class, get a component | Combine classes to build anything | | **[Bootstrap](https://getbootstrap.com/)** | **[Tailwind CSS](https://tailwindcss.com/)** | | Sites tend to look similar | Unique designs, more classes in HTML | --- # Recognize the Framework **Bootstrap** (component classes): ```html <button class="btn btn-primary">Click</button> ``` **Tailwind** (utility classes, what AI usually generates): ```html <button class="bg-blue-500 text-white px-4 py-2 rounded">Click</button> ``` `btn` and `container` and `col-` mean Bootstrap. `bg-`, `text-`, `px-`, `py-`, `rounded` mean Tailwind. --- # Reading Tailwind Classes Class names describe what they do: | Class | Meaning | Vanilla CSS | |---|---|---| | `bg-blue-500` | Blue background | `background: #3b82f6` | | `text-white` | White text | `color: white` | | `px-4` | Horizontal padding | `padding-left/right: 1rem` | | `rounded` | Rounded corners | `border-radius: 0.25rem` | | `hover:bg-blue-700` | Darker on hover | `:hover { background: ... }` | You do not need to memorize these. You need to **read** them. --- # Same Card: Vanilla vs Tailwind Both produce the same card. Tailwind keeps the styling in the HTML: <div class="grid grid-cols-[1.9fr_1fr] gap-8 items-center mt-4"> <div> ```css /* Vanilla CSS */ .card { padding: 20px; border-radius: 8px; background: #eff6ff; box-shadow: 0 2px 8px rgba(0,0,0,0.12); } ``` ```html <!-- Tailwind --> <div class="bg-blue-50 p-5 rounded-lg shadow-md">...</div> ``` </div> <div class="flex justify-center"> <div class="demo-cardx">Product card</div> </div> </div> <style scoped> .demo-cardx { padding: 18px 30px; border-radius: 8px; background: #eff6ff; box-shadow: 0 2px 8px rgba(0,0,0,0.12); font-weight: 600; } </style> --- # shadcn/ui and What AI Generates [shadcn/ui](https://ui.shadcn.com/) is a popular set of polished components built on **React plus Tailwind**. The buttons below mimic its clean, neutral look: <div class="flex gap-4 justify-center my-6"> <button class="sb-btn sb-primary">Button</button> <button class="sb-btn sb-outline">Outline</button> </div> When **Copilot**, **Cursor**, or **v0.dev** generate UI, expect: - **Tailwind** classes most of the time - **shadcn/ui** components for more complex UIs - Sometimes plain CSS or Bootstrap <style scoped> .sb-btn { padding: 8px 18px; border-radius: 6px; font-size: 0.85em; font-weight: 500; cursor: pointer; border: 1px solid transparent; transition: background 0.15s; } .sb-primary { background: #18181b; color: white; } .sb-primary:hover { background: #2e2e35; } .sb-outline { background: white; color: #18181b; border-color: #e4e4e7; } .sb-outline:hover { background: #f4f4f5; } </style> --- # What You Need to Know You do **not** need to: - Memorize Tailwind classes - Set up a framework yourself You **do** need to: - **Recognize** framework classes - **Understand** what the AI-generated code does - **Modify** it confidently (change a color, adjust spacing) > 🤖 **AI tip:** Ask AI *"explain each class in this line"* to decode unfamiliar Tailwind fast. --- layout: center --- # CSS Art --- # CSS Art: No JavaScript, Just CSS Pure CSS can draw surprisingly complex images: - [Pure CSS Landscape](https://codepen.io/ivorjetski/pen/xxGYWQG) ([how it was built](https://www.youtube.com/watch?v=rUCVBNNyjC4)) - [Portrait](https://codepen.io/ivorjetski/pen/dBYWWZ) - [Still life](https://codepen.io/ivorjetski/pen/xMJoYO) These are built entirely from gradients, shadows, and shapes. Not practical for daily work, but they show how far CSS reaches. --- layout: center --- # Modern CSS --- # Dark Mode Adapt to the user's system preference, or let them toggle it. Try the toggle: ```css @media (prefers-color-scheme: dark) { :root { --bg: #111; --text: #eee; } } ``` <div class="dm-demo flex flex-col items-center gap-3 my-5"> <label class="cursor-pointer select-none"><input type="checkbox"> toggle dark mode</label> <div class="dm-box">Preview text</div> </div> <style scoped> .dm-demo .dm-box { background: #f5f5f5; color: #111; padding: 14px 32px; border-radius: 8px; transition: background 0.3s, color 0.3s; } .dm-demo:has(input:checked) .dm-box { background: #111; color: #eee; } </style> --- # Pseudo-Elements `::before` and `::after` insert content without touching the HTML. Edit the star and the badge: <CssPlayground :code="`.pe-tag { position: relative; font-weight: 600; font-size: 1.4em; } .pe-tag::before { content: '★ '; color: #f59e0b; } .pe-tag::after { content: 'NEW'; position: absolute; top: -12px; right: -46px; background: #ef4444; color: white; font-size: 0.5em; padding: 2px 6px; border-radius: 4px; }`"> <span class="pe-tag">Inbox</span> </CssPlayground> --- # Fluid Sizing: clamp() and Container Queries ```css /* Font scales with the viewport, within bounds */ h1 { font-size: clamp(1.5rem, 4vw, 3rem); } /* Style based on the container's width, not the screen */ @container (min-width: 400px) { .card { display: flex; } } ``` `clamp()` replaces many media queries. Container queries make a component responsive to its own space. --- # References - [MDN: CSS Custom Properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) - [MDN: CSS Transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions) · [CSS Animations](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations) - [Tailwind CSS](https://tailwindcss.com/) · [Bootstrap](https://getbootstrap.com/) · [shadcn/ui](https://ui.shadcn.com/) - [Animate.css](https://animate.style/): a pre-built animation library

Topics Covered

  • transitions and keyframe animations
  • CSS variables
  • frameworks (Tailwind intro)
  • dark mode, pseudo-elements, clamp

Content Slides Open fullscreen ↗