Complete CSS Mastery
Master Cascading Style Sheets to build responsive, elegant interfaces.
Getting Started with CSS
Learn how to add CSS to your web pages and start styling
What is CSS?
CSS (Cascading Style Sheets) is a stylesheet language used to control the presentation of HTML documents. It separates content from design, making websites easier to maintain and more flexible.
Three Ways to Add CSS
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Website</title>
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<h1 class="hero-title">Hello CSS!</h1>
<p class="intro-text">Welcome to web styling</p>
</body>
</html>
Benefits: Reusable across multiple pages, cached by browsers, keeps HTML clean.
<!DOCTYPE html>
<html>
<head>
<title>Internal CSS</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
h1 {
color: #2c3e50;
border-bottom: 3px solid #3498db;
padding-bottom: 10px;
}
.highlight {
background-color: yellow;
padding: 5px;
}
</style>
</head>
<body>
<h1>Internal Styles</h1>
<p>This is <span class="highlight">highlighted</span> text.</p>
</body>
</html>
Use case: Single-page applications or page-specific styles.
<h1 style="color: blue; font-size: 32px; margin-bottom: 20px;">
Inline Styled Heading
</h1>
<p style="color: #666; line-height: 1.6;">
This paragraph has inline styles.
</p>
<button style="background-color: #3498db; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer;">
Click Me
</button>
Warning: Hard to maintain, not reusable, overrides external styles.
Creating Your First CSS File
/* Global Reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Body Styles */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background-color: #fff;
}
/* Typography */
h1 {
font-size: 2.5rem;
color: #2c3e50;
margin-bottom: 1rem;
}
p {
font-size: 1rem;
margin-bottom: 1rem;
}
/* Utility Classes */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.btn {
display: inline-block;
padding: 10px 30px;
background-color: #3498db;
color: white;
text-decoration: none;
border-radius: 5px;
transition: background-color 0.3s;
}
.btn:hover {
background-color: #2980b9;
}
CSS Loading Order
<head>
<!-- Load in order: Reset → Base → Components → Pages -->
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/base.css">
<link rel="stylesheet" href="css/components.css">
<link rel="stylesheet" href="css/pages.css">
</head>
/* main.css */
@import url('reset.css');
@import url('typography.css');
@import url('layout.css');
@import url('components.css');
/* Your custom styles */
body {
background-color: #f8f9fa;
}
Note: @import can slow down page loading. Link tags are preferred.
Browser Developer Tools
Chrome DevTools (F12 or Right-click → Inspect):
1. Select Elements tab
2. Click on an element or use element picker
3. View applied styles in the Styles panel
4. Edit styles in real-time
5. Toggle styles on/off with checkboxes
6. Add new properties directly
Firefox DevTools:
- Similar interface with Rules panel
- Shows computed values
- Font editor for typography
- Animation inspector
Edge DevTools:
- Based on Chromium
- CSS Overview tool
- Issues tab for CSS warnings
CSS Comments and Organization
/* ==========================================================================
Website Styles
Author: Your Name
Version: 1.0
========================================================================== */
/* --------------------------------------------------------------------------
Global Styles
-------------------------------------------------------------------------- */
* {
box-sizing: border-box;
}
/* --------------------------------------------------------------------------
Typography
-------------------------------------------------------------------------- */
h1, h2, h3, h4, h5, h6 {
font-weight: bold;
line-height: 1.2;
}
/* --------------------------------------------------------------------------
Layout Components
-------------------------------------------------------------------------- */
.header {
background-color: #2c3e50;
color: white;
padding: 20px 0;
}
.main-content {
padding: 40px 0;
}
/* TODO: Add footer styles */
/* FIXME: Navigation needs responsive improvements */
Complete Example
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My First CSS Website</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<header class="site-header">
<h1>Welcome to CSS</h1>
<nav class="navigation">
<a href="#" class="nav-link">Home</a>
<a href="#" class="nav-link">About</a>
<a href="#" class="nav-link">Contact</a>
</nav>
</header>
<main class="main-content">
<article class="card">
<h2>Article Title</h2>
<p>This is a sample article with CSS styling.</p>
<a href="#" class="btn">Read More</a>
</article>
</main>
</div>
</body>
</html>
/* styles.css */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.site-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px 0;
text-align: center;
}
.site-header h1 {
margin-bottom: 15px;
}
.navigation {
display: flex;
justify-content: center;
gap: 20px;
}
.nav-link {
color: white;
text-decoration: none;
padding: 5px 10px;
transition: opacity 0.3s;
}
.nav-link:hover {
opacity: 0.8;
}
.main-content {
padding: 40px 0;
}
.card {
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.card h2 {
color: #667eea;
margin-bottom: 15px;
}
.card p {
margin-bottom: 20px;
}
.btn {
display: inline-block;
padding: 10px 25px;
background-color: #667eea;
color: white;
text-decoration: none;
border-radius: 5px;
transition: background-color 0.3s;
}
.btn:hover {
background-color: #764ba2;
}
Practice Tasks
- Create an HTML file and link an external CSS file to it.
- Style a simple webpage with a header, navigation, and main content area.
- Use browser developer tools to inspect and modify styles in real-time.
- Create a CSS file with organized sections using comments.
- Build a button with hover effects using CSS transitions.
Key Takeaways
- External stylesheets are the recommended method for adding CSS to web pages.
- Always include a CSS reset to ensure consistent rendering across browsers.
- Use browser developer tools to debug and experiment with CSS.
- Organize CSS files with clear comments and logical sections.
- The link tag should be placed in the <head> section of HTML.
- CSS loads from top to bottom; later rules can override earlier ones.
What's Next?
Next Topics: Learn about CSS syntax and structure, then explore the CSS cascade and specificity rules.
CSS Introduction
Understanding the Cascade, Specificity, and Inheritance
What is CSS?
CSS (Cascading Style Sheets) is a style sheet language that controls how HTML elements are displayed. It works by applying rules consisting of selectors and declarations to target and style elements on a webpage.
CSS Rule Structure
/* Selector: targets HTML elements */
.card {
/* Property: value; (declaration) */
background-color: #ffffff;
border-radius: 12px;
box-shadow: 0 10px 30px -18px rgba(0, 0, 0, 0.35);
padding: 20px;
margin: 15px;
}
/* Multiple selectors can share styles */
h1, h2, h3 {
font-family: 'Georgia', serif;
color: #2c3e50;
line-height: 1.3;
}
The Cascade Algorithm
/* The cascade resolves conflicts in this order:
1. Origin and Importance
2. Specificity
3. Source Order */
/* User-agent styles (browser defaults) */
p {
margin: 1em 0; /* Browser default */
}
/* Author styles (your CSS) override defaults */
p {
margin: 0;
margin-bottom: 1rem;
}
/* !important overrides normal declarations */
p.special {
color: blue !important; /* Avoid using !important */
}
Priority Order (Low to High):
1. User-agent styles (browser defaults)
2. User styles (browser settings/accessibility)
3. Author styles (your CSS files)
4. Author !important declarations
5. User !important declarations
6. User-agent !important declarations
Note: !important reverses the priority order!
Specificity Rules
/* Specificity: (inline, IDs, classes/attributes/pseudo-classes, elements) */
/* (0, 0, 0, 1) - Element selector */
p {
color: black;
}
/* (0, 0, 1, 0) - Class selector */
.text {
color: blue;
}
/* (0, 0, 1, 1) - Class + element */
p.text {
color: green;
}
/* (0, 1, 0, 0) - ID selector */
#main {
color: red;
}
/* (0, 1, 1, 1) - ID + class + element */
div#main.content {
color: purple;
}
/* (1, 0, 0, 0) - Inline style (in HTML) */
/* <p style="color: orange;">Text</p> */
/* Specificity: 0,0,1,0 (10) */
.button {
background-color: blue;
}
/* Specificity: 0,0,2,0 (20) - WINS */
.button.primary {
background-color: green;
}
/* Specificity: 0,0,1,1 (11) */
div.button {
background-color: red;
}
/* Specificity: 0,1,0,0 (100) - WINS over all above */
#submit {
background-color: purple;
}
/* Avoid this anti-pattern */
div#submit.button.primary {
/* Specificity: 0,1,2,1 (121) - Too specific! */
background-color: yellow;
}
Inheritance
/* Text properties inherit by default */
body {
font-family: Arial, sans-serif; /* Inherits to all children */
font-size: 16px; /* Inherits */
color: #333; /* Inherits */
line-height: 1.6; /* Inherits */
}
/* Layout properties do NOT inherit */
div {
margin: 20px; /* Does NOT inherit */
padding: 15px; /* Does NOT inherit */
border: 1px solid; /* Does NOT inherit */
width: 100%; /* Does NOT inherit */
}
/* Force inheritance with 'inherit' keyword */
.child {
border: inherit; /* Explicitly inherit parent's border */
}
/* Reset to initial value */
.reset {
color: initial; /* Browser default color */
}
/* Use computed value from parent */
.inherit-all {
all: inherit; /* Inherit all properties (rarely used) */
}
Source Order
/* When specificity is equal, last rule wins */
.button {
background-color: blue;
color: white;
}
.button {
background-color: green; /* This wins! */
/* color: white is still applied (not overridden) */
}
/* Practical example: utility classes */
.text-blue {
color: blue;
}
.text-red {
color: red;
}
/* <div class="text-blue text-red"> will be RED */
/* <div class="text-red text-blue"> will be BLUE */
CSS Versions and Evolution
CSS1 (1996):
- Basic selectors and properties
- Font, color, text, box properties
CSS2 (1998) / CSS2.1 (2011):
- Positioning (absolute, relative, fixed)
- Z-index and stacking
- Media types
- More selectors (child, adjacent)
CSS3 (Modular, 2011+):
- Divided into modules (Selectors Level 3, Backgrounds & Borders, etc.)
- Border-radius, box-shadow, gradients
- Transitions and animations
- Flexbox, Grid Layout
- Custom properties (CSS variables)
- Media queries
Modern CSS (2020+):
- Container queries
- :has() selector
- Cascade layers (@layer)
- Subgrid
- Color functions (oklch, color-mix)
Practical Examples
<!-- HTML -->
<div class="card featured" id="main-card">
<h2 class="card-title">Title</h2>
<p>Content text</p>
</div>
/* CSS */
/* Specificity: 0,0,1,0 */
.card {
background-color: white;
padding: 20px;
color: #333;
}
/* Specificity: 0,0,1,0 - Same as above, but later = wins */
.featured {
background-color: #f0f0f0;
}
/* Specificity: 0,1,0,0 - ID wins */
#main-card {
background-color: #e8f4f8;
}
/* Inherited from .card */
.card-title {
/* color: #333 is inherited from .card */
font-size: 1.5rem;
}
p {
/* Also inherits color: #333 from .card */
line-height: 1.6;
}
Practice Tasks
- Create three CSS rules with different specificity levels and observe which one wins.
- Use browser DevTools to inspect the computed specificity of different selectors.
- Set font-family on the body element and observe how it inherits to all text elements.
- Create a conflict between two rules with equal specificity and test source order.
- Calculate specificity for:
div.container #main > p.intro::first-line
Key Takeaways
- The cascade resolves conflicts using origin, importance, specificity, and source order.
- Specificity hierarchy: inline styles > IDs > classes/attributes/pseudo-classes > elements.
- Text-related properties (font, color, line-height) inherit; layout properties don't.
- Avoid !important; it breaks the natural cascade and makes CSS harder to maintain.
- When specificity is equal, the last rule in source order wins.
- Keep specificity low by using classes instead of IDs for styling.
What's Next?
Next Topics: Explore CSS history and evolution, then dive deep into selectors and specificity calculations.
CSS History & Evolution
From basic styling to modern layout systems and beyond
The Birth of CSS (1996)
CSS was proposed by Håkon Wium Lie in 1994 and became a W3C recommendation in December 1996. It was created to separate presentation from content, solving the problem of maintaining HTML styling attributes across large websites.
CSS1 (1996) - The Foundation
/* CSS1 introduced basic styling capabilities */
/* Font properties */
body {
font-family: Arial, sans-serif;
font-size: 14px;
font-weight: bold;
font-style: italic;
}
/* Color and background */
h1 {
color: #333333;
background-color: #f0f0f0;
}
/* Text properties */
p {
text-align: center;
text-decoration: underline;
line-height: 1.5;
text-indent: 20px;
}
/* Box model basics */
div {
margin: 10px;
padding: 15px;
border: 1px solid black;
width: 300px;
height: 200px;
}
/* Classification */
.hidden {
display: none;
}
.inline {
display: inline;
}
CSS1 Capabilities:
✓ Font properties (family, size, weight, style)
✓ Color and background
✓ Text formatting (alignment, decoration, spacing)
✓ Box model (margin, padding, border)
✓ Basic layout (float, clear, display)
✓ Simple selectors (element, class, ID)
✗ No positioning
✗ No media queries
✗ Limited selectors
✗ No rounded corners or shadows
CSS2 (1998) - Expanding Capabilities
/* Positioning - Revolutionary for layouts */
.absolute {
position: absolute;
top: 20px;
left: 50px;
z-index: 100;
}
.relative {
position: relative;
top: 10px;
}
.fixed {
position: fixed;
bottom: 0;
right: 0;
}
/* Advanced selectors */
/* Child selector */
nav > ul {
list-style: none;
}
/* Adjacent sibling */
h2 + p {
font-weight: bold;
}
/* Attribute selector */
input[type="text"] {
border: 1px solid #ccc;
}
/* Pseudo-classes */
a:hover {
color: red;
}
a:visited {
color: purple;
}
li:first-child {
font-weight: bold;
}
/* Pseudo-elements */
p::first-letter {
font-size: 2em;
float: left;
}
p::first-line {
font-variant: small-caps;
}
/* Media types */
@media print {
.no-print {
display: none;
}
}
/* Generated content */
.note::before {
content: "Note: ";
font-weight: bold;
}
CSS2.1 (2011) - Standardization
CSS2.1 Goals:
• Fixed errors and ambiguities in CSS2
• Removed features that weren't widely implemented
• Added some widely-supported features that weren't in CSS2
• Better browser compatibility
Key Changes:
✓ Clarified the cascade algorithm
✓ Better box model definition
✓ Improved positioning rules
✓ Fixed selector specificity calculations
✓ Better handling of overflow
✓ Standardized rendering behavior
This became the stable foundation most browsers implemented.
CSS3 (2011+) - Modular Revolution
/* Border radius and shadows */
.card {
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
/* Gradients */
.gradient-bg {
background: linear-gradient(to right, #667eea, #764ba2);
}
/* Transitions */
.button {
transition: all 0.3s ease;
}
.button:hover {
transform: scale(1.05);
}
/* Animations */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate {
animation: fadeIn 0.5s ease-out;
}
/* Multiple backgrounds */
.hero {
background-image:
url('overlay.png'),
url('background.jpg');
background-size: cover;
background-position: center;
}
/* RGBA and HSLA colors */
.transparent {
background-color: rgba(0, 0, 0, 0.5);
color: hsla(200, 100%, 50%, 0.8);
}
/* Text effects */
.fancy-text {
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
word-wrap: break-word;
}
/* Media queries */
@media(max-width: 768px) {
.container {
width: 100%;
padding: 10px;
}
}
/* Multiple columns */
.article {
column-count: 2;
column-gap: 20px;
}
Flexbox (2012+) - Modern Layout
/* Flexbox revolutionized layouts */
.flex-container {
display: flex;
justify-content: space-between;
align-items: center;
gap: 20px;
}
.flex-item {
flex: 1;
}
/* Responsive navigation with Flexbox */
.navbar {
display: flex;
flex-wrap: wrap;
}
@media(max-width: 768px) {
.navbar {
flex-direction: column;
}
}
CSS Grid (2017) - Two-Dimensional Layouts
/* Grid enabled complex 2D layouts */
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto;
gap: 20px;
}
/* Named grid areas */
.layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
grid-template-columns: 200px 1fr 1fr;
gap: 15px;
}
.header {
grid-area: header;
}
.sidebar {
grid-area: sidebar;
}
.main {
grid-area: main;
}
.footer {
grid-area: footer;
}
Custom Properties (2015+) - CSS Variables
/* Define variables */
:root {
--primary-color: #667eea;
--secondary-color: #764ba2;
--spacing: 20px;
--border-radius: 8px;
}
/* Use variables */
.button {
background-color: var(--primary-color);
padding: var(--spacing);
border-radius: var(--border-radius);
}
/* Dynamic theming */
[data-theme="dark"] {
--primary-color: #9f7aea;
--text-color: #ffffff;
--background-color: #1a202c;
}
Modern CSS (2020+) - Cutting Edge
/* Container queries */
@container(min-width: 400px) {
.card {
display: flex;
}
}
/* :has() - Parent selector */
.card:has(img) {
padding: 0;
}
/* clamp() - Responsive sizing */
h1 {
font-size: clamp(1.5rem, 5vw, 3rem);
}
/* Cascade layers */
@layer reset, base, components, utilities;
@layer base {
body {
font-family: system-ui;
}
}
/* Subgrid */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.grid-item {
display: grid;
grid-template-columns: subgrid;
}
/* New color functions */
.modern-colors {
background: oklch(0.7 0.2 180);
color: color-mix(in srgb, blue 50%, white);
}
Practice Tasks
- Create a layout using only CSS2 features (floats and positioning), then remake it with Flexbox.
- Build a responsive grid layout using CSS Grid with named areas.
- Implement a dark/light theme switcher using CSS custom properties.
- Use browser DevTools to check which CSS features are supported in your browser.
- Create an animation using @keyframes and test different timing functions.
Key Takeaways
- CSS1 (1996) introduced basic styling: fonts, colors, box model.
- CSS2 (1998) added positioning, z-index, pseudo-classes, and media types.
- CSS2.1 (2011) fixed errors and standardized implementations.
- CSS3 (2011+) introduced modules: border-radius, shadows, gradients, transitions, animations.
- Flexbox (2012) and Grid (2017) revolutionized layout design.
- Custom Properties (2015+) brought variables and dynamic theming to CSS.
- Modern CSS (2020+) includes container queries, :has(), clamp(), and cascade layers.
What's Next?
Next Topics: Master selectors and specificity to understand how CSS targets and styles elements effectively.
CSS Syntax & Structure
Master CSS rule syntax, declarations, and code organization
CSS Rule Anatomy
A CSS rule consists of a selector (what to style) and a declaration block (how to style it). Understanding this structure is fundamental to writing effective CSS.
/* Selector */
h1 {
/* Declaration: property: value; */
color: #2c3e50;
font-size: 2.5rem;
margin-bottom: 1rem;
}
/* Multiple selectors (comma-separated) */
h1, h2, h3, h4, h5, h6 {
font-family: 'Georgia', serif;
font-weight: bold;
line-height: 1.2;
}
/* Nested descendants */
.card .title {
color: #3498db;
}
Properties and Values
/* Property: value pairs */
.element {
/* Keywords */
display: block;
position: relative;
/* Numbers with units */
width: 300px;
padding: 1.5rem;
margin: 0 auto;
/* Colors */
color: #333;
background-color: rgb(255, 255, 255);
border-color: rgba(0, 0, 0, 0.1);
/* Multiple values */
font-family: Arial, Helvetica, sans-serif;
box-shadow: 0 2px 4px rgba(0,0,0,0.1), 0 4px 8px rgba(0,0,0,0.05);
/* URLs */
background-image: url('image.jpg');
/* Functions */
transform: translateX(10px) rotate(45deg);
width: calc(100% - 40px);
}
Shorthand Properties
/* Margin shorthand */
.box-1 {
margin: 20px; /* All sides */
margin: 10px 20px; /* Vertical | Horizontal */
margin: 10px 20px 15px; /* Top | Horizontal | Bottom */
margin: 10px 20px 15px 25px; /* Top | Right | Bottom | Left */
}
/* Padding shorthand (same pattern as margin) */
.box-2 {
padding: 20px 30px;
}
/* Border shorthand: width style color */
.box-3 {
border: 2px solid #333;
/* Equivalent to: */
border-width: 2px;
border-style: solid;
border-color: #333;
}
/* Background shorthand */
.hero {
background: url('bg.jpg') center/cover no-repeat fixed;
/* Equivalent to: */
background-image: url('bg.jpg');
background-position: center;
background-size: cover;
background-repeat: no-repeat;
background-attachment: fixed;
}
/* Font shorthand: style variant weight size/line-height family */
.text {
font: italic small-caps bold 16px/1.5 Georgia, serif;
/* Equivalent to: */
font-style: italic;
font-variant: small-caps;
font-weight: bold;
font-size: 16px;
line-height: 1.5;
font-family: Georgia, serif;
}
/* Animation shorthand */
.animated {
animation: fadeIn 1s ease-in 0.5s infinite alternate;
/* name | duration | timing-function | delay | iteration | direction */
}
/* Transition shorthand */
.smooth {
transition: all 0.3s ease-in-out;
/* property | duration | timing-function | delay */
}
CSS Comments
/* Single line comment */
/*
Multi-line comment
Can span multiple lines
Useful for documentation
*/
/* ==========================================================================
Section Title
========================================================================== */
/* --------------------------------------------------------------------------
Subsection Title
-------------------------------------------------------------------------- */
/* Component: Card
Description: Reusable card component with shadow
Author: Your Name
========================================================================== */
.card {
padding: 20px;
/* TODO: Add responsive breakpoints */
/* FIXME: Border-radius not working in IE11 */
/* NOTE: This component is used in homepage and dashboard */
border-radius: 10px;
}
/* ❌ Invalid - No nested comments */
/* This is a comment /* This won't work */ */
At-Rules
/* @import - Import other stylesheets */
@import url('reset.css');
@import url('typography.css');
/* @media - Media queries for responsive design */
@media(max-width: 768px) {
.container {
width: 100%;
}
}
/* @keyframes - Define animations */
@keyframes slideIn {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
/* @font-face - Custom fonts */
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2'),
url('font.woff') format('woff');
font-weight: normal;
font-style: normal;
}
/* @supports - Feature detection */
@supports(display: grid) {
.layout {
display: grid;
}
}
/* @layer - Cascade layers (modern CSS) */
@layer reset, base, components, utilities;
@layer base {
body {
font-family: system-ui;
}
}
/* @charset - Character encoding */
@charset "UTF-8";
Vendor Prefixes
/* Vendor prefixes for cross-browser support */
.element {
/* Webkit (Chrome, Safari, newer Edge) */
-webkit-transform: rotate(45deg);
/* Mozilla Firefox */
-moz-transform: rotate(45deg);
/* Microsoft (old Edge, IE) */
-ms-transform: rotate(45deg);
/* Opera (old versions) */
-o-transform: rotate(45deg);
/* Standard (always last) */
transform: rotate(45deg);
}
/* Modern approach: Use autoprefixer */
.gradient {
background: linear-gradient(to right, #667eea, #764ba2);
/* Autoprefixer will add necessary prefixes automatically */
}
/* Common properties that may need prefixes */
.prefixed {
/* Flexbox (old syntax needed prefixes) */
display: flex;
/* Appearance */
-webkit-appearance: none;
appearance: none;
/* User select */
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
/* Backdrop filter */
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
}
CSS Validation
/* ✅ Valid CSS */
.valid {
color: #333;
margin: 20px;
padding: 10px 15px;
}
/* ❌ Invalid - Missing semicolon (will break next declaration) */
.invalid {
color: #333
margin: 20px; /* This won't work */
}
/* ❌ Invalid - Missing colon */
.invalid {
color #333;
}
/* ❌ Invalid - Missing closing brace */
.invalid {
color: #333;
/* Oops, forgot closing brace */
/* ❌ Invalid - Wrong property name */
.invalid {
colour: red; /* Should be 'color' */
}
/* ✅ Valid - Last property doesn't need semicolon (but recommended) */
.optional-semicolon {
color: blue;
margin: 10px /* Technically valid but bad practice */
}
/* ✅ Valid - Multiple values */
.multiple {
font-family: Arial, "Helvetica Neue", sans-serif;
box-shadow:
0 1px 3px rgba(0,0,0,0.1),
0 2px 6px rgba(0,0,0,0.05);
}
CSS File Organization
/* ==========================================================================
Main Stylesheet
Description: Primary styles for website
Author: Your Name
Version: 1.0.0
========================================================================== */
/* --------------------------------------------------------------------------
Table of Contents
1. Variables & Custom Properties
2. Reset & Normalize
3. Base Styles
4. Typography
5. Layout
6. Components
7. Utilities
8. Media Queries
-------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
1. Variables & Custom Properties
-------------------------------------------------------------------------- */
:root {
--primary-color: #3498db;
--secondary-color: #2ecc71;
--text-color: #333;
--spacing-unit: 8px;
}
/* --------------------------------------------------------------------------
2. Reset & Normalize
-------------------------------------------------------------------------- */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* --------------------------------------------------------------------------
3. Base Styles
-------------------------------------------------------------------------- */
body {
font-family: -apple-system, system-ui, sans-serif;
line-height: 1.6;
color: var(--text-color);
}
/* ... More sections ... */
/* --------------------------------------------------------------------------
8. Media Queries
-------------------------------------------------------------------------- */
@media(max-width: 768px) {
/* Mobile styles */
}
CSS Naming Conventions
/* Block Element Modifier (BEM) */
/* Block: component name */
.card {
padding: 20px;
}
/* Element: child of block */
.card__header {
font-size: 1.5rem;
margin-bottom: 10px;
}
.card__body {
line-height: 1.6;
}
.card__footer {
border-top: 1px solid #ddd;
padding-top: 15px;
}
/* Modifier: variation of block or element */
.card--featured {
border: 2px solid #3498db;
}
.card--large {
padding: 40px;
}
.card__header--primary {
color: #3498db;
}
/* Complete example */
/* HTML:
Title
Content
*/
Practice Tasks
- Create a CSS file with proper organization: variables, reset, base styles, and components.
- Write selectors using BEM naming convention for a card component.
- Use shorthand properties to reduce code: margin, padding, background, font.
- Add comprehensive comments to document your CSS code structure.
- Create a @keyframes animation and apply it to an element.
- Validate your CSS using W3C CSS Validator or browser DevTools.
Key Takeaways
- CSS rules consist of selectors and declaration blocks with property-value pairs.
- Use shorthand properties to write cleaner, more maintainable code.
- Comments are essential for documenting complex CSS and team collaboration.
- At-rules (@media, @keyframes, @import) provide special functionality.
- Vendor prefixes may be needed for cutting-edge features; use autoprefixer.
- Organize CSS files logically: variables, reset, base, components, utilities.
- Follow naming conventions like BEM for scalable, maintainable CSS.
What's Next?
Next Topics: Learn about spacing and layout systems, then master positioning and z-index for complex layouts.
Selectors & Specificity
Master CSS selectors and understand specificity rules
Basic Selectors
Selectors are patterns that match HTML elements. Understanding selectors is fundamental to writing efficient and maintainable CSS.
/* Element selector - targets all matching elements */
p {
color: #333;
line-height: 1.6;
}
h1, h2, h3 {
font-family: Georgia, serif;
font-weight: bold;
}
/* Class selector - targets elements with class attribute */
.button {
padding: 10px 20px;
background-color: #3498db;
color: white;
border-radius: 5px;
}
.card {
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* ID selector - targets single element (use sparingly for styling) */
#header {
background-color: #2c3e50;
padding: 20px;
}
#main-content {
max-width: 1200px;
margin: 0 auto;
}
Attribute Selectors
/* Exact match */
input[type="text"] {
border: 1px solid #ccc;
padding: 8px;
}
input[type="email"] {
border: 1px solid #3498db;
}
/* Contains word */
[class~="btn"] {
cursor: pointer;
}
/* Starts with */
a[href^="https://"] {
color: green;
}
a[href^="mailto:"] {
color: #e74c3c;
}
/* Ends with */
a[href$=".pdf"] {
padding-left: 20px;
background: url('pdf-icon.png') left center no-repeat;
}
/* Contains substring */
[class*="icon"] {
font-family: 'FontAwesome';
}
/* Attribute exists */
[data-tooltip] {
position: relative;
cursor: help;
}
/* Language-specific */
[lang|="en"] {
quotes: '"' '"';
}
Pseudo-Classes
/* User interaction states */
a:link {
color: #3498db;
}
a:visited {
color: #9b59b6;
}
a:hover {
color: #2980b9;
text-decoration: underline;
}
a:active {
color: #e74c3c;
}
input:focus {
outline: 2px solid #3498db;
border-color: #3498db;
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Structural pseudo-classes */
li:first-child {
font-weight: bold;
}
li:last-child {
border-bottom: none;
}
li:nth-child(odd) {
background-color: #f5f5f5;
}
li:nth-child(even) {
background-color: white;
}
li:nth-child(3n) {
/* Every third item */
color: #e74c3c;
}
/* Type-specific */
p:first-of-type {
font-size: 1.2em;
}
p:last-of-type {
margin-bottom: 0;
}
/* Form states */
input:required {
border-left: 3px solid #e74c3c;
}
input:valid {
border-color: #27ae60;
}
input:invalid {
border-color: #e74c3c;
}
/* Negation */
button:not(.primary) {
background-color: #95a5a6;
}
Combinators
/* Descendant combinator (space) - all descendants */
.card p {
margin-bottom: 15px;
}
nav a {
text-decoration: none;
}
/* Child combinator (>) - direct children only */
.menu > li {
display: inline-block;
}
article > h2 {
color: #2c3e50;
}
/* Adjacent sibling combinator (+) - immediate next sibling */
h2 + p {
font-weight: bold;
font-size: 1.1em;
}
.alert + .alert {
margin-top: 10px;
}
/* General sibling combinator (~) - all following siblings */
h2 ~ p {
color: #666;
}
.active ~ li {
opacity: 0.7;
}
Pseudo-Elements
/* ::before and ::after */
.icon::before {
content: "→ ";
color: #3498db;
}
.external-link::after {
content: " ↗";
font-size: 0.8em;
}
/* Decorative elements */
.quote::before {
content: """;
font-size: 3em;
color: #ccc;
position: absolute;
left: -20px;
top: -10px;
}
/* ::first-letter */
.article::first-letter {
font-size: 3em;
float: left;
line-height: 1;
margin-right: 5px;
color: #e74c3c;
}
/* ::first-line */
.intro::first-line {
font-weight: bold;
font-variant: small-caps;
}
/* ::selection */
::selection {
background-color: #3498db;
color: white;
}
/* ::placeholder */
input::placeholder {
color: #999;
font-style: italic;
}
Specificity Calculation
/* Specificity: (inline, IDs, classes/attrs/pseudo-classes, elements/pseudo-elements) */
/* 0,0,0,1 */
p {
color: black;
}
/* 0,0,0,2 */
div p {
color: gray;
}
/* 0,0,1,0 */
.text {
color: blue;
}
/* 0,0,1,1 */
p.text {
color: green;
}
/* 0,0,2,0 */
.container .text {
color: purple;
}
/* 0,1,0,0 */
#main {
color: red;
}
/* 0,1,1,1 */
div#main.content {
color: orange;
}
/* 0,0,2,1 */
div.container .text {
color: navy;
}
/* 1,0,0,0 - Inline style (in HTML) */
/* <p style="color: yellow;">Wins over all above</p> */
Advanced Selectors
/* :is() - Selector list (keeps specificity of most specific) */
:is(h1, h2, h3) {
line-height: 1.2;
}
:is(.card, .panel) > h2 {
margin-top: 0;
}
/* :where() - Zero specificity (useful for defaults) */
:where(h1, h2, h3) {
margin: 0; /* Easy to override */
}
/* :has() - Parent selector (CSS4) */
.card:has(img) {
display: grid;
grid-template-columns: 200px 1fr;
}
a:has(> img) {
display: block;
}
/* :not() - Negation */
button:not(.primary):not(.secondary) {
background-color: gray;
}
li:not(:last-child) {
border-bottom: 1px solid #ddd;
}
/* Multiple :not() */
input:not([type="checkbox"]):not([type="radio"]) {
padding: 8px;
}
Specificity Best Practices
/* ❌ BAD - Too specific */
div#container .sidebar ul.menu li.item a.link {
color: blue;
}
/* ✅ GOOD - Use classes */
.menu-link {
color: blue;
}
/* ❌ BAD - Overqualified */
div.card {
padding: 20px;
}
/* ✅ GOOD - Just the class */
.card {
padding: 20px;
}
/* ❌ BAD - !important */
.text {
color: red !important;
}
/* ✅ GOOD - Increase specificity naturally */
.container .text {
color: red;
}
/* ✅ BETTER - Use a more specific class */
.text-error {
color: red;
}
Practice Tasks
- Create a list and use :nth-child() to create zebra striping (alternating colors).
- Style all external links (starting with http://) differently from internal links.
- Calculate the specificity of:
div#main.content > p.intro::first-line - Use ::before and ::after to add decorative elements without extra HTML.
- Refactor a selector chain like
.nav ul li ato use a single class selector. - Use the :has() selector to style a card differently when it contains an image.
Key Takeaways
- Keep specificity low by preferring classes over IDs for styling.
- Specificity hierarchy: inline (1000) > ID (100) > class/attribute/pseudo-class (10) > element (1).
- Avoid overqualifying selectors (e.g., div.class is unnecessary).
- Use combinators (>, +, ~) to create precise relationships between elements.
- :is() maintains specificity while :where() has zero specificity.
- Pseudo-elements (::before, ::after) create virtual elements for styling.
- !important should be avoided; increase specificity naturally instead.
What's Next?
Next Topics: Dive into the CSS Box Model to understand how elements are sized and spaced, then explore CSS syntax and structure.
CSS Box Model
Understanding content, padding, border, and margin
What is the Box Model?
Every HTML element is rendered as a rectangular box. The CSS box model describes how these boxes are sized and spaced, consisting of four areas: content, padding, border, and margin.
┌─────────────────────────────────────────┐
│ MARGIN (transparent) │
│ ┌───────────────────────────────────┐ │
│ │ BORDER (visible) │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ PADDING (transparent) │ │ │
│ │ │ ┌───────────────────────┐ │ │ │
│ │ │ │ CONTENT (visible) │ │ │ │
│ │ │ │ width × height │ │ │ │
│ │ │ └───────────────────────┘ │ │ │
│ │ └─────────────────────────────┘ │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
Total Width = margin-left + border-left + padding-left +
width + padding-right + border-right + margin-right
Content Area
/* Content box (default) */
.box {
width: 300px; /* Content width */
height: 200px; /* Content height */
background-color: #3498db;
}
/* Min and max constraints */
.responsive-box {
width: 100%;
max-width: 800px; /* Won't exceed this */
min-width: 300px; /* Won't shrink below this */
min-height: 200px;
}
/* Auto sizing */
.auto-width {
width: auto; /* Default behavior */
height: auto; /* Fits content */
}
Padding
/* Padding creates space inside the border */
/* All sides equal */
.box-1 {
padding: 20px; /* 20px on all sides */
}
/* Vertical | Horizontal */
.box-2 {
padding: 20px 40px; /* 20px top/bottom, 40px left/right */
}
/* Top | Horizontal | Bottom */
.box-3 {
padding: 10px 20px 15px; /* 10px top, 20px sides, 15px bottom */
}
/* Top | Right | Bottom | Left (clockwise) */
.box-4 {
padding: 10px 20px 15px 25px;
}
/* Individual sides */
.box-5 {
padding-top: 10px;
padding-right: 20px;
padding-bottom: 15px;
padding-left: 25px;
}
/* Percentage padding (relative to parent width) */
.responsive-padding {
padding: 5%; /* Responsive spacing */
}
/* Creating aspect ratio boxes */
.aspect-ratio-16-9 {
width: 100%;
padding-bottom: 56.25%; /* 9/16 = 0.5625 */
position: relative;
}
Border
/* Border shorthand: width style color */
.bordered {
border: 2px solid #3498db;
}
/* Individual sides */
.custom-borders {
border-top: 3px solid #e74c3c;
border-right: 1px dashed #95a5a6;
border-bottom: 2px dotted #27ae60;
border-left: 5px double #9b59b6;
}
/* Border styles */
.border-styles {
border-width: 3px;
border-style: solid; /* solid, dashed, dotted, double, groove, ridge, inset, outset */
border-color: #333;
}
/* No border */
.no-border {
border: none;
}
/* Border radius (rounded corners) */
.rounded {
border-radius: 10px; /* All corners */
}
.pill {
border-radius: 50px; /* Pill shape */
}
.circle {
width: 100px;
height: 100px;
border-radius: 50%; /* Perfect circle */
}
/* Individual corners */
.custom-radius {
border-top-left-radius: 20px;
border-top-right-radius: 10px;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 0;
}
/* Elliptical corners */
.ellipse {
border-radius: 50px / 25px; /* horizontal / vertical */
}
Margin
/* Margin creates space outside the border */
/* All sides equal */
.spaced {
margin: 20px;
}
/* Vertical | Horizontal */
.spaced-2 {
margin: 30px 15px;
}
/* Centering horizontally */
.centered {
width: 800px;
margin: 0 auto; /* 0 top/bottom, auto left/right */
}
/* Individual sides */
.custom-margin {
margin-top: 20px;
margin-right: 15px;
margin-bottom: 25px;
margin-left: 10px;
}
/* Negative margins */
.overlap {
margin-top: -20px; /* Pulls element up */
margin-left: -10px; /* Pulls element left */
}
/* Remove default margins */
.no-margin {
margin: 0;
}
Margin Collapsing
/* Vertical margins collapse between block elements */
.box-a {
margin-bottom: 30px;
}
.box-b {
margin-top: 20px;
}
/* Actual space between box-a and box-b is 30px (not 50px)
The larger margin wins */
/* Prevent margin collapse */
.no-collapse {
/* Use padding instead */
padding-bottom: 30px;
}
.flex-container {
/* Flexbox prevents margin collapse */
display: flex;
flex-direction: column;
}
.parent {
/* Border or padding prevents collapse */
border-top: 1px solid transparent;
/* or */
padding-top: 1px;
/* or */
overflow: auto;
}
Box-Sizing
/* Default: content-box */
.content-box {
box-sizing: content-box;
width: 300px; /* Content width */
padding: 20px; /* +40px */
border: 5px solid; /* +10px */
/* Total width: 350px */
}
/* Better: border-box (includes padding and border in width) */
.border-box {
box-sizing: border-box;
width: 300px; /* Total width including padding and border */
padding: 20px;
border: 5px solid;
/* Total width: 300px (content is 250px) */
}
/* Global reset (recommended) */
*, *::before, *::after {
box-sizing: border-box;
}
/* Alternative reset */
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
Outline vs Border
/* Outline does NOT affect layout (doesn't add to dimensions) */
.outlined {
outline: 2px solid #3498db;
outline-offset: 5px; /* Space between outline and border */
}
/* Focus styles */
button:focus {
outline: 3px solid #3498db;
outline-offset: 2px;
}
/* Remove outline (provide alternative focus style) */
.custom-focus:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.5);
}
/* Outline vs Border */
.comparison {
border: 2px solid red; /* Adds to element size */
outline: 2px solid blue; /* Doesn't affect size or layout */
}
Practical Examples
/* Complete card using all box model properties */
.card {
/* Content sizing */
width: 350px;
max-width: 100%;
/* Box-sizing */
box-sizing: border-box;
/* Padding (inner space) */
padding: 25px;
/* Border */
border: 1px solid #e0e0e0;
border-radius: 12px;
/* Margin (outer space) */
margin: 20px;
/* Visual styling */
background-color: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.card-header {
margin: -25px -25px 20px -25px; /* Negative margin extends to edges */
padding: 20px 25px;
background-color: #3498db;
color: white;
border-radius: 12px 12px 0 0;
}
.card-body {
padding: 0; /* Card already has padding */
}
.card-footer {
margin: 20px -25px -25px -25px;
padding: 15px 25px;
border-top: 1px solid #e0e0e0;
background-color: #f8f9fa;
border-radius: 0 0 12px 12px;
}
Logical Properties
/* Traditional (physical) properties */
.physical {
margin-left: 20px;
padding-right: 15px;
border-top: 2px solid;
}
/* Logical properties (adapt to writing mode) */
.logical {
margin-inline-start: 20px; /* Left in LTR, right in RTL */
padding-inline-end: 15px; /* Right in LTR, left in RTL */
border-block-start: 2px solid; /* Top in horizontal writing */
}
/* Inline = horizontal direction */
.inline-spacing {
padding-inline: 20px; /* Left and right */
margin-inline-start: 10px; /* Start of inline direction */
margin-inline-end: 10px; /* End of inline direction */
}
/* Block = vertical direction */
.block-spacing {
padding-block: 30px; /* Top and bottom */
margin-block-start: 15px; /* Top */
margin-block-end: 15px; /* Bottom */
}
Practice Tasks
- Create a box with specific dimensions and apply the box model to see how padding and border affect total size.
- Set
box-sizing: border-boxglobally and observe the difference in sizing behavior. - Build a card component with header, body, and footer using margin/padding effectively.
- Experiment with margin collapsing by creating two stacked divs with different margins.
- Use outline instead of border for focus states to avoid layout shifts.
- Create a centered container using
margin: 0 auto.
Key Takeaways
- The box model consists of content, padding, border, and margin (from inside out).
- Use
box-sizing: border-boxto make width/height include padding and border. - Vertical margins collapse between block elements; the larger margin wins.
- Padding adds space inside the element; margin adds space outside.
- Outline doesn't affect layout or box dimensions (unlike border).
- Use
margin: 0 autoto center block elements horizontally. - Logical properties (margin-inline, padding-block) support RTL layouts.
What's Next?
Next Topics: Learn about CSS syntax and structure, then explore spacing and layout techniques in depth.
CSS Units & Values
Master the different measurement units and values in CSS
CSS offers a variety of units for sizing elements, spacing, typography, and more. Choosing the right unit is crucial for creating flexible, maintainable, and responsive designs. Each unit type serves different purposes and contexts.
Absolute Units
Absolute units have fixed sizes and don't scale based on other elements or viewport sizes. While less flexible, they're useful for precise control.
/* Pixels (px) - most common absolute unit */
.border {
border: 2px solid #ccc;
border-radius: 8px;
}
/* Points (pt) - mainly for print */
@media print {
body { font-size: 12pt; }
}
/* Other absolute units (rarely used) */
.example {
/* 1in = 96px, 1cm = 37.8px, 1mm = 3.78px */
width: 2in; /* inches */
height: 5cm; /* centimeters */
}
Relative Units - Font-Based
These units scale relative to font sizes, making them perfect for typography and spacing that should scale together.
/* em - relative to parent element's font size */
.parent {
font-size: 20px;
}
.child {
font-size: 1.5em; /* 30px (1.5 × 20px) */
padding: 0.5em; /* 15px (0.5 × 30px) */
margin-bottom: 1em; /* 30px (1 × 30px) */
}
/* em compounds with nesting */
.nested {
font-size: 1.2em; /* 36px (1.2 × 30px) */
}
/* rem - relative to root element's font size */
:root {
font-size: 16px; /* Browser default */
}
/* All rem values based on root (16px) */
.container {
padding: 2rem; /* 32px */
margin-bottom: 1.5rem; /* 24px */
}
.heading {
font-size: 2.5rem; /* 40px */
margin-bottom: 1rem; /* 16px */
}
.text {
font-size: 1rem; /* 16px */
line-height: 1.5; /* 24px */
}
/* Benefit: predictable sizing, respects user font preferences */
Viewport Units
Viewport units are relative to the browser window size, perfect for creating full-screen sections and responsive layouts.
/* vw - viewport width (1vw = 1% of viewport width) */
.full-width {
width: 100vw;
margin-left: -50vw;
left: 50%;
}
/* vh - viewport height (1vh = 1% of viewport height) */
.hero {
height: 100vh; /* Full screen height */
min-height: 500px; /* Fallback for small screens */
}
.section {
min-height: 60vh; /* 60% of viewport height */
}
/* vmin - smaller of vw or vh */
.square {
width: 80vmin;
height: 80vmin; /* Always a square */
}
/* vmax - larger of vw or vh */
.responsive-text {
font-size: 5vmax; /* Scales with larger dimension */
}
/* Large viewport units (lvh, lvw) - ignore UI elements */
.hero {
height: 100lvh; /* Full height including browser UI */
}
/* Small viewport units (svh, svw) - account for UI elements */
.mobile-hero {
height: 100svh; /* Full height excluding browser UI */
}
/* Dynamic viewport units (dvh, dvw) - adjust as UI shows/hides */
.dynamic-hero {
height: 100dvh; /* Adjusts when mobile browser chrome appears */
}
Percentage Units
Percentages are relative to the parent element's corresponding property.
/* Width percentage - relative to parent's width */
.parent {
width: 1000px;
}
.child {
width: 50%; /* 500px */
}
/* Fluid layouts */
.sidebar {
width: 25%;
float: left;
}
.content {
width: 75%;
float: left;
}
/* Padding/margin percentage - relative to parent's WIDTH */
.box {
width: 500px;
padding: 10%; /* 50px on all sides (10% of 500px) */
}
Special Units
/* ch - width of the '0' character */
.monospace {
font-family: 'Courier New', monospace;
width: 60ch; /* Optimal reading width (60 characters) */
}
.input {
width: 20ch; /* Width of 20 characters */
}
/* ex - height of the 'x' character */
.superscript {
vertical-align: 1ex;
}
Using calc() for Calculations
/* Mix different units */
.header {
width: calc(100% - 250px);
height: calc(100vh - 80px);
}
/* Responsive spacing */
.container {
width: calc(100% - 2rem);
max-width: 1200px;
margin: 0 auto;
}
/* Fluid typography */
.title {
font-size: calc(1.5rem + 2vw);
}
/* Complex calculations */
.grid-item {
width: calc((100% - (3 * 20px)) / 4);
/* 4 items with 20px gaps */
}
Using clamp() for Responsive Values
/* clamp(minimum, preferred, maximum) */
/* Fluid typography without media queries */
h1 {
font-size: clamp(2rem, 5vw, 4rem);
/* Never smaller than 2rem or larger than 4rem */
}
p {
font-size: clamp(1rem, 0.95rem + 0.25vw, 1.25rem);
}
/* Fluid spacing */
.container {
padding: clamp(1rem, 5vw, 3rem);
gap: clamp(0.5rem, 2vw, 2rem);
}
/* Fluid widths */
.card {
width: clamp(300px, 50vw, 600px);
}
Best Practices by Use Case
/* Typography - use rem */
body {
font-size: 1rem; /* 16px */
line-height: 1.5; /* Unitless for flexibility */
}
h1 { font-size: 2.5rem; } /* 40px */
h2 { font-size: 2rem; } /* 32px */
p { font-size: 1rem; } /* 16px */
small { font-size: 0.875rem; } /* 14px */
/* Spacing - use rem for consistency */
.section {
padding: 4rem 2rem;
margin-bottom: 2rem;
}
/* Borders - use px for precision */
.card {
border: 1px solid #ddd;
border-radius: 8px;
}
/* Layout widths - use % or fr (in grid) */
.sidebar { width: 25%; }
.content { width: 75%; }
/* Hero sections - use vh */
.hero {
min-height: 100vh;
padding: 0 5vw;
}
/* Media - use % for responsiveness */
img {
max-width: 100%;
height: auto;
}
Responsive Unit Strategies
/* Set base font size (optional) */
:root {
font-size: 16px;
}
/* Use rem for all typography and spacing */
body {
font-size: 1rem;
line-height: 1.6;
padding: 2rem;
}
/* Fluid typography with clamp() */
h1 {
font-size: clamp(2rem, 3vw + 1rem, 3.5rem);
margin-bottom: 1rem;
}
/* Container with max-width */
.container {
width: calc(100% - 2rem);
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
/* Viewport-based hero */
.hero {
min-height: 60vh;
padding: 4rem 5vw;
}
/* Grid with flexible units */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: clamp(1rem, 2vw, 2rem);
}
Practice Task
- Create a card component using rem for spacing and typography
- Build a hero section that's 80vh tall with fluid padding using vw
- Use
clamp()to create a heading that scales smoothly from 2rem to 4rem - Create a container that's 100% width minus 2rem using
calc() - Build a text block with a max-width of 60ch for optimal readability
Key Takeaways
- rem: Best for typography and spacing (respects user preferences)
- px: Use for borders, shadows, and precise control
- %: Perfect for fluid layouts relative to parent
- vh/vw: Great for full-screen sections and viewport-based sizing
- clamp(): Create fluid, responsive values without media queries
- calc(): Perform calculations mixing different units
- ch: Ideal for text width (60ch for optimal reading)
What's Next?
Learn about Responsive Media Queries for breakpoints, explore Typography & Fonts for text styling, or dive into CSS Functions for advanced calculations.
Colors & Typography
Master color theory and typography principles for beautiful, readable designs
Color and typography are fundamental to visual design. Understanding color formats, accessibility requirements, and typographic hierarchy ensures your interfaces are both beautiful and functional. This section covers modern color systems and typography best practices.
Color Formats and Values
CSS supports multiple color formats, each with specific use cases and advantages.
/* Named colors */
.named {
color: rebeccapurple;
background-color: white;
border-color: transparent;
}
/* Hexadecimal - most common */
.hex {
color: #3b82f6; /* 6-digit */
background: #fff; /* 3-digit shorthand */
border-color: #3b82f680; /* 8-digit with alpha */
}
/* RGB and RGBA */
.rgb {
color: rgb(59, 130, 246);
background: rgba(59, 130, 246, 0.5);
/* Modern syntax with alpha */
border-color: rgb(59 130 246 / 0.5);
}
/* HSL and HSLA - best for variations */
.hsl {
/* hue, saturation, lightness */
color: hsl(217, 91%, 60%);
background: hsla(217, 91%, 60%, 0.2);
/* Modern syntax */
border-color: hsl(217 91% 60% / 0.2);
}
/* CurrentColor keyword */
.current {
color: #3b82f6;
border: 2px solid currentColor;
box-shadow: 0 4px 12px currentColor;
}
Building Color Systems
Create comprehensive color palettes with consistent shades and tints.
:root {
/* Primary color scale */
--primary-50: #eff6ff;
--primary-100: #dbeafe;
--primary-200: #bfdbfe;
--primary-300: #93c5fd;
--primary-400: #60a5fa;
--primary-500: #3b82f6; /* Base */
--primary-600: #2563eb;
--primary-700: #1d4ed8;
--primary-800: #1e40af;
--primary-900: #1e3a8a;
/* Semantic colors */
--color-success: #22c55e;
--color-warning: #f59e0b;
--color-error: #ef4444;
--color-info: #3b82f6;
/* Neutral scale */
--gray-50: #f9fafb;
--gray-100: #f3f4f6;
--gray-200: #e5e7eb;
--gray-300: #d1d5db;
--gray-400: #9ca3af;
--gray-500: #6b7280;
--gray-600: #4b5563;
--gray-700: #374151;
--gray-800: #1f2937;
--gray-900: #111827;
}
/* Usage */
.button-primary {
background-color: var(--primary-600);
color: white;
}
.button-primary:hover {
background-color: var(--primary-700);
}
.alert-success {
background-color: hsl(142, 77%, 95%);
color: var(--color-success);
border-left: 4px solid var(--color-success);
}
HSL for Color Variations
HSL makes it easy to create color variations by adjusting hue, saturation, or lightness.
:root {
/* Base HSL values */
--primary-h: 217;
--primary-s: 91%;
--primary-l: 60%;
/* Generate variations */
--primary: hsl(var(--primary-h), var(--primary-s), var(--primary-l));
--primary-light: hsl(var(--primary-h), var(--primary-s), 75%);
--primary-lighter: hsl(var(--primary-h), var(--primary-s), 90%);
--primary-dark: hsl(var(--primary-h), var(--primary-s), 45%);
--primary-darker: hsl(var(--primary-h), var(--primary-s), 30%);
/* With opacity */
--primary-alpha-10: hsl(var(--primary-h) var(--primary-s) var(--primary-l) / 0.1);
--primary-alpha-20: hsl(var(--primary-h) var(--primary-s) var(--primary-l) / 0.2);
}
/* Color mixing with filters */
.tinted {
background-color: var(--primary);
filter: brightness(1.2) saturate(0.8);
}
/* Complementary color */
.complementary {
/* Opposite hue (180deg) */
background: hsl(calc(var(--primary-h) + 180), var(--primary-s), var(--primary-l));
}
/* Analogous colors */
.analogous-1 {
background: hsl(calc(var(--primary-h) + 30), var(--primary-s), var(--primary-l));
}
.analogous-2 {
background: hsl(calc(var(--primary-h) - 30), var(--primary-s), var(--primary-l));
}
Typography Fundamentals
Establish a solid typographic foundation with proper font selection and sizing.
:root {
/* Font families */
--font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-serif: 'Merriweather', Georgia, serif;
--font-mono: 'Fira Code', 'Courier New', monospace;
/* Base size */
--font-size-base: 16px;
/* Type scale (1.25 ratio) */
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */
--font-size-base: 1rem; /* 16px */
--font-size-lg: 1.125rem; /* 18px */
--font-size-xl: 1.25rem; /* 20px */
--font-size-2xl: 1.5rem; /* 24px */
--font-size-3xl: 1.875rem; /* 30px */
--font-size-4xl: 2.25rem; /* 36px */
--font-size-5xl: 3rem; /* 48px */
/* Line heights */
--leading-none: 1;
--leading-tight: 1.25;
--leading-snug: 1.375;
--leading-normal: 1.5;
--leading-relaxed: 1.625;
--leading-loose: 2;
}
body {
font-family: var(--font-sans);
font-size: var(--font-size-base);
line-height: var(--leading-normal);
color: var(--gray-900);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code{
pre {
font-family: var(--font-mono);
}
Typographic Hierarchy
Create clear visual hierarchy with consistent heading styles and spacing.
/* Heading styles */
h1{ .h1 {
font-size: clamp(2rem, 5vw, 3rem);
font-weight: 800;
line-height: var(--leading-tight);
letter-spacing: -0.025em;
color: var(--gray-900);
margin-bottom: 0.5em;
}
h2{ .h2 {
font-size: clamp(1.5rem, 3.5vw, 2.25rem);
font-weight: 700;
line-height: var(--leading-tight);
letter-spacing: -0.02em;
color: var(--gray-900);
margin-top: 2em;
margin-bottom: 0.75em;
}
h3{ .h3 {
font-size: clamp(1.25rem, 2.5vw, 1.875rem);
font-weight: 600;
line-height: var(--leading-snug);
color: var(--gray-800);
margin-top: 1.5em;
margin-bottom: 0.5em;
}
h4{ .h4 {
font-size: var(--font-size-xl);
font-weight: 600;
line-height: var(--leading-snug);
color: var(--gray-800);
margin-top: 1.25em;
margin-bottom: 0.5em;
}
/* Body text variants */
.lead {
font-size: var(--font-size-lg);
line-height: var(--leading-relaxed);
color: var(--gray-700);
}
.text-small {
font-size: var(--font-size-sm);
line-height: var(--leading-normal);
}
.text-xs {
font-size: var(--font-size-xs);
line-height: var(--leading-normal);
}
Font Weights and Styles
Use appropriate font weights for emphasis and hierarchy.
:root {
--font-thin: 100;
--font-extralight: 200;
--font-light: 300;
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
--font-extrabold: 800;
--font-black: 900;
}
/* Utility classes */
.font-light { font-weight: var(--font-light); }
.font-normal { font-weight: var(--font-normal); }
.font-medium { font-weight: var(--font-medium); }
.font-semibold { font-weight: var(--font-semibold); }
.font-bold { font-weight: var(--font-bold); }
/* Font styles */
.italic { font-style: italic; }
.not-italic { font-style: normal; }
/* Text decorations */
.underline { text-decoration: underline; }
.line-through { text-decoration: line-through; }
.no-underline { text-decoration: none; }
/* Text transform */
.uppercase { text-transform: uppercase; letter-spacing: 0.05em; }
.lowercase { text-transform: lowercase; }
.capitalize { text-transform: capitalize; }
Text Alignment and Spacing
Control text flow, alignment, and spacing for optimal readability.
/* Text alignment */
.text-left { text-align: left; }
.text-center { text-align: center; }
.text-right { text-align: right; }
.text-justify { text-align: justify; }
/* Letter spacing */
.tracking-tighter { letter-spacing: -0.05em; }
.tracking-tight { letter-spacing: -0.025em; }
.tracking-normal { letter-spacing: 0; }
.tracking-wide { letter-spacing: 0.025em; }
.tracking-wider { letter-spacing: 0.05em; }
.tracking-widest { letter-spacing: 0.1em; }
/* Line height */
.leading-none { line-height: 1; }
.leading-tight { line-height: 1.25; }
.leading-normal { line-height: 1.5; }
.leading-relaxed { line-height: 1.625; }
.leading-loose { line-height: 2; }
/* Text overflow */
.truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Word break */
.break-words {
overflow-wrap: break-word;
word-break: break-word;
}
.break-all {
word-break: break-all;
}
Color Contrast and Accessibility
Ensure sufficient color contrast for readability and accessibility compliance.
/* WCAG AA compliant combinations */
.text-high-contrast {
color: #111827; /* Gray 900 */
background-color: #ffffff; /* White */
/* Contrast ratio: 16.8:1 */
}
.text-body {
color: #374151; /* Gray 700 */
background-color: #ffffff;
/* Contrast ratio: 10.7:1 (AA for normal text) */
}
.text-muted {
color: #6b7280; /* Gray 500 */
background-color: #ffffff;
/* Contrast ratio: 4.6:1 (AA for large text) */
}
/* Dark mode accessible colors */
[data-theme="dark"] {
--text-primary: #f9fafb;
--text-secondary: #d1d5db;
--bg-primary: #111827;
--bg-secondary: #1f2937;
}
/* Link colors with proper contrast */
a {
color: #2563eb; /* Primary 600 */
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 2px;
}
a:hover {
color: #1d4ed8; /* Primary 700 */
text-decoration-thickness: 2px;
}
/* Focus indicators */
:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
Variable Fonts
Leverage variable fonts for flexible, performant typography.
/* Load variable font */
@font-face {
font-family: 'Inter Variable';
src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-display: swap;
}
:root {
--font-sans: 'Inter Variable', sans-serif;
}
/* Use font-variation-settings */
.custom-weight {
font-variation-settings: 'wght' 450;
}
.custom-width {
font-variation-settings: 'wdth' 85;
}
/* Combine multiple axes */
.custom-variant {
font-variation-settings: 'wght' 600, 'wdth' 90, 'slnt' -5;
}
/* Optical sizing */
@supports(font-variation-settings: normal) {
body {
font-optical-sizing: auto;
}
}
Practice Exercises
- Color Palette: Create a complete color system with primary, secondary, and neutral scales (10 shades each) using HSL.
- Type Scale: Design a typography system with 6 heading levels and body text variants using clamp() for fluid sizing.
- Dark Mode: Implement a color theme that switches between light and dark modes with accessible contrast ratios.
- Readable Article: Style a blog post with proper typographic hierarchy, optimal line length (45-75 characters), and adequate spacing.
- Accessible Links: Create link styles that meet WCAG AA standards with visible focus indicators and hover states.
- Use HSL for creating color variations programmatically
- Maintain WCAG AA contrast ratios (4.5:1 for text, 3:1 for large text)
- Establish a consistent type scale with proportional sizing
- Use fluid typography with clamp() for responsive text
- Apply proper line-height (1.5-1.75) for body text readability
- Leverage currentColor and CSS variables for maintainable color systems
What's Next?
Continue to Backgrounds & Borders to enhance visual design, or explore Accessibility for comprehensive accessibility guidelines.
Backgrounds & Borders
Master background properties and border techniques for rich visual designs
Backgrounds and borders are essential for creating visual depth and defining element boundaries. CSS provides powerful properties for gradients, multiple backgrounds, custom border styles, and creative effects that bring designs to life.
Background Properties
Master the fundamental background properties for colors, images, and positioning.
/* Background color */
.bg-solid {
background-color: #3b82f6;
}
/* Background image */
.bg-image {
background-image: url('/images/hero.jpg');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
/* Background size options */
.bg-contain {
background-size: contain; /* Fit entire image */
}
.bg-cover {
background-size: cover; /* Cover entire area */
}
.bg-custom {
background-size: 300px 200px; /* Specific dimensions */
background-size: 50% auto; /* Percentage */
}
/* Background position */
.bg-positioned {
background-position: top left;
background-position: center center;
background-position: bottom right;
background-position: 20% 50%;
background-position: 100px 50px;
}
/* Background attachment */
.bg-fixed {
background-attachment: fixed; /* Parallax effect */
}
.bg-scroll {
background-attachment: scroll; /* Scrolls with page */
}
/* Shorthand */
.bg-shorthand {
background: #3b82f6 url('/img/pattern.png') repeat-x center top;
}
Multiple Backgrounds
Layer multiple background images and gradients for complex designs.
/* Multiple images (first = top layer) */
.multi-bg {
background-image:
url('/images/overlay.png'),
url('/images/texture.jpg'),
url('/images/base.jpg');
background-position:
center center,
top left,
center center;
background-repeat:
no-repeat,
repeat,
no-repeat;
background-size:
cover,
auto,
cover;
}
/* Gradient over image */
.gradient-overlay {
background:
linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.7)),
url('/images/hero.jpg') center/cover;
}
/* Pattern with gradient */
.pattern-gradient {
background-image:
linear-gradient(135deg, rgba(59, 130, 246, 0.1) 25%, transparent 25%),
linear-gradient(225deg, rgba(59, 130, 246, 0.1) 25%, transparent 25%),
linear-gradient(to bottom, #ffffff, #f3f4f6);
background-size: 40px 40px, 40px 40px, 100% 100%;
background-position: 0 0, 20px 20px, 0 0;
}
/* Decorative corners */
.corner-decorations {
background-image:
radial-gradient(circle at top left, #3b82f6 0, transparent 50%),
radial-gradient(circle at bottom right, #8b5cf6 0, transparent 50%);
background-size: 300px 300px;
background-position: top left, bottom right;
background-repeat: no-repeat;
}
Gradient Backgrounds
Create smooth color transitions with linear, radial, and conic gradients.
/* Linear gradients */
.gradient-linear {
background: linear-gradient(to right, #3b82f6, #8b5cf6);
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
background: linear-gradient(90deg, #ff6b6b, #feca57, #48dbfb);
}
/* Multi-stop gradients */
.gradient-multi {
background: linear-gradient(
to bottom,
#3b82f6 0%,
#8b5cf6 50%,
#ec4899 100%
);
}
/* Radial gradients */
.gradient-radial {
background: radial-gradient(circle, #3b82f6, #1e40af);
background: radial-gradient(ellipse at top, #667eea, #764ba2);
background: radial-gradient(circle at center, transparent 0, #000 100%);
}
/* Conic gradients */
.gradient-conic {
background: conic-gradient(from 0deg, #3b82f6, #8b5cf6, #ec4899, #3b82f6);
}
/* Repeating gradients */
.gradient-repeating {
background: repeating-linear-gradient(
45deg,
#3b82f6,
#3b82f6 10px,
#60a5fa 10px,
#60a5fa 20px
);
}
/* Mesh gradient effect */
.gradient-mesh {
background:
radial-gradient(at 40% 20%, #3b82f6 0, transparent 50%),
radial-gradient(at 80% 0%, #8b5cf6 0, transparent 50%),
radial-gradient(at 0% 50%, #ec4899 0, transparent 50%),
radial-gradient(at 80% 50%, #10b981 0, transparent 50%),
radial-gradient(at 0% 100%, #f59e0b 0, transparent 50%),
#f3f4f6;
}
Border Styles
Apply various border styles, widths, and colors to define element boundaries.
/* Basic borders */
.border-solid {
border: 2px solid #3b82f6;
}
/* Border styles */
.border-styles {
border-style: solid; /* ──── */
border-style: dashed; /* ---- */
border-style: dotted; /* .... */
border-style: double; /* ════ */
border-style: groove; /* 3D grooved */
border-style: ridge; /* 3D ridged */
border-style: inset; /* 3D inset */
border-style: outset; /* 3D outset */
}
/* Individual sides */
.border-individual {
border-top: 2px solid #3b82f6;
border-right: 1px dashed #6b7280;
border-bottom: 3px double #8b5cf6;
border-left: 2px solid #3b82f6;
}
/* Logical properties */
.border-logical {
border-inline: 2px solid #3b82f6;
border-block-start: 1px solid #6b7280;
border-block-end: 1px solid #6b7280;
}
/* Border width scale */
.border-thin { border-width: 1px; }
.border-medium { border-width: 2px; }
.border-thick { border-width: 4px; }
/* Transparent borders (for spacing) */
.border-transparent {
border: 4px solid transparent;
background-clip: padding-box;
}
Border Radius
Create rounded corners with various border-radius techniques.
/* Uniform radius */
.rounded-sm { border-radius: 4px; }
.rounded { border-radius: 8px; }
.rounded-lg { border-radius: 12px; }
.rounded-xl { border-radius: 16px; }
.rounded-2xl { border-radius: 24px; }
.rounded-full { border-radius: 9999px; }
/* Individual corners */
.custom-corners {
border-top-left-radius: 20px;
border-top-right-radius: 20px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
/* Elliptical corners */
.elliptical {
border-radius: 50px / 25px; /* horizontal / vertical */
}
/* Complex shapes */
.organic-shape {
border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
}
/* Pill shape */
.pill {
border-radius: 50px;
padding: 8px 24px;
}
/* Logical radius */
.logical-radius {
border-start-start-radius: 12px;
border-start-end-radius: 12px;
border-end-start-radius: 0;
border-end-end-radius: 0;
}
Border Images
Use images as borders for decorative effects.
/* Basic border image */
.border-image-basic {
border: 10px solid;
border-image-source: url('/images/border.png');
border-image-slice: 30;
border-image-repeat: round;
}
/* Gradient border */
.border-gradient {
border: 3px solid;
border-image: linear-gradient(135deg, #667eea, #764ba2) 1;
}
/* Animated gradient border */
.border-gradient-animated {
position: relative;
border: 3px solid transparent;
background-clip: padding-box;
}
.border-gradient-animated::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
padding: 3px;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
}
/* Corner decorations */
.corner-border {
position: relative;
}
.corner-border::before{
.corner-border::after {
content: '';
position: absolute;
width: 20px;
height: 20px;
border: 2px solid #3b82f6;
}
.corner-border::before {
top: 0;
left: 0;
border-right: 0;
border-bottom: 0;
}
.corner-border::after {
bottom: 0;
right: 0;
border-left: 0;
border-top: 0;
}
Outline Properties
Use outlines for focus indicators and overlays without affecting layout.
/* Basic outline */
.with-outline {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* Focus indicators */
button:focus-visible {
outline: 3px solid #3b82f6;
outline-offset: 3px;
}
/* Dashed outline */
.dashed-outline {
outline: 2px dashed #6b7280;
outline-offset: 4px;
}
/* Double border effect with outline */
.double-border {
border: 2px solid #3b82f6;
outline: 2px solid #8b5cf6;
outline-offset: 2px;
}
/* Negative offset for inset effect */
.inset-outline {
outline: 2px solid rgba(255, 255, 255, 0.5);
outline-offset: -4px;
}
Creative Background Patterns
Create CSS-only patterns without images.
/* Stripes */
.stripes {
background: repeating-linear-gradient(
45deg,
#f3f4f6,
#f3f4f6 10px,
#e5e7eb 10px,
#e5e7eb 20px
);
}
/* Dots */
.dots {
background-image: radial-gradient(circle, #3b82f6 1px, transparent 1px);
background-size: 20px 20px;
}
/* Grid */
.grid-pattern {
background-image:
linear-gradient(#e5e7eb 1px, transparent 1px),
linear-gradient(90deg, #e5e7eb 1px, transparent 1px);
background-size: 20px 20px;
}
/* Checkerboard */
.checkerboard {
background-image:
linear-gradient(45deg, #e5e7eb 25%, transparent 25%),
linear-gradient(-45deg, #e5e7eb 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #e5e7eb 75%),
linear-gradient(-45deg, transparent 75%, #e5e7eb 75%);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0;
}
/* Waves */
.waves {
background:
radial-gradient(circle at 50% 0, transparent 50%, #3b82f6 50.5%),
#60a5fa;
background-size: 40px 20px;
background-repeat: repeat-x;
}
Advanced Background Techniques
Combine properties for sophisticated visual effects.
/* Glassmorphism effect */
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 16px;
}
/* Neumorphism */
.neomorphic {
background: #e0e5ec;
border-radius: 16px;
box-shadow:
9px 9px 16px rgba(163, 177, 198, 0.6),
-9px -9px 16px rgba(255, 255, 255, 0.5);
}
/* Card with gradient border */
.gradient-border-card {
position: relative;
background: white;
border-radius: 16px;
padding: 2px;
}
.gradient-border-card::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
padding: 2px;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
mask-composite: exclude;
}
/* Animated background */
@keyframes gradient-shift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.animated-gradient {
background: linear-gradient(-45deg, #667eea, #764ba2, #f093fb, #4facfe);
background-size: 400% 400%;
animation: gradient-shift 15s ease infinite;
}
Practice Exercises
- Hero Section: Create a hero banner with a gradient overlay on a background image and custom border radius.
- Pattern Design: Design three different CSS-only patterns (stripes, dots, grid) without using images.
- Glassmorphism Card: Build a card component with frosted glass effect using backdrop-filter and semi-transparent backgrounds.
- Gradient Border: Create a button with an animated gradient border that shifts colors.
- Multi-layer Background: Design a section with multiple layered backgrounds combining gradients, patterns, and transparency.
- Layer multiple backgrounds for complex visual effects
- Use background-size: cover for responsive images
- Combine gradients with images for overlays
- Border-radius creates rounded corners and shapes
- Outline doesn't affect layout, perfect for focus indicators
- CSS gradients can create patterns without images
What's Next?
Continue to Shadows & Gradients for advanced depth effects, or explore Transforms & Effects for dynamic visual transformations.
Spacing & Layout
Create consistent spacing systems and layout patterns
Why Spacing Systems Matter
Consistent spacing creates visual rhythm and hierarchy in your designs. A systematic approach to spacing makes layouts feel cohesive and professional.
Spacing Scale
/* Define spacing scale using CSS custom properties */
:root {
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
--space-20: 5rem; /* 80px */
--space-24: 6rem; /* 96px */
}
/* Apply spacing consistently */
.section {
padding: var(--space-16) var(--space-8);
}
.card {
padding: var(--space-6);
margin-bottom: var(--space-4);
}
.button {
padding: var(--space-3) var(--space-6);
}
Margin Techniques
/* Margin for element spacing */
.element {
margin-bottom: 20px; /* Space below */
}
/* Auto margins for centering */
.container {
max-width: 1200px;
margin: 0 auto; /* Center horizontally */
}
/* Negative margins for overlapping */
.overlap {
margin-top: -30px; /* Pull up */
}
/* Directional margins */
.section {
margin-top: 60px;
margin-bottom: 40px;
}
/* Responsive margins */
.responsive {
margin: 5%;
}
@media(min-width: 768px) {
.responsive {
margin: 40px;
}
}
Padding Patterns
/* Uniform padding */
.box {
padding: 20px;
}
/* Asymmetric padding */
.header {
padding: 30px 20px; /* More vertical padding */
}
/* Individual sides */
.custom {
padding-top: 40px;
padding-right: 20px;
padding-bottom: 40px;
padding-left: 20px;
}
/* Percentage padding for aspect ratios */
.video-wrapper {
position: relative;
padding-bottom: 56.25%; /* 16:9 aspect ratio */
height: 0;
overflow: hidden;
}
.video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
Box-Sizing
/* Global box-sizing reset */
*, *::before, *::after {
box-sizing: border-box;
}
/* Example showing the difference */
.content-box {
box-sizing: content-box;
width: 300px;
padding: 20px;
border: 5px solid;
/* Total width: 350px (300 + 40 + 10) */
}
.border-box {
box-sizing: border-box;
width: 300px;
padding: 20px;
border: 5px solid;
/* Total width: 300px (padding/border included) */
}
Stack Layout Pattern
/* Space all direct children except first */
.stack > * + * {
margin-top: var(--space-4);
}
/* Variable stack spacing */
.stack-small > * + * {
margin-top: var(--space-2);
}
.stack-large > * + * {
margin-top: var(--space-8);
}
/* Recursive stack (all descendants) */
.stack-recursive * + * {
margin-top: var(--space-4);
}
/* Example usage */
/* HTML:
Title
Paragraph 1
Paragraph 2
*/
Logical Properties
/* Traditional physical properties */
.physical {
margin-left: 20px;
margin-right: 10px;
padding-top: 15px;
padding-bottom: 15px;
}
/* Modern logical properties */
.logical {
margin-inline-start: 20px; /* Left in LTR, right in RTL */
margin-inline-end: 10px; /* Right in LTR, left in RTL */
padding-block-start: 15px; /* Top */
padding-block-end: 15px; /* Bottom */
}
/* Shorthand logical properties */
.shorthand {
margin-inline: 20px 10px; /* start | end */
margin-block: 15px; /* start and end */
padding-inline: 20px; /* Both inline sides */
padding-block: 30px; /* Both block sides */
}
/* Benefit: Automatically adapts to RTL */
[dir="rtl"] .logical {
/* margin-inline-start becomes right margin */
/* No additional CSS needed! */
}
Container Patterns
/* Centered container with max-width */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Full-width container */
.container-fluid {
width: 100%;
padding: 0 20px;
}
/* Narrow container for reading */
.container-narrow {
max-width: 720px;
margin: 0 auto;
padding: 0 20px;
}
/* Wide container */
.container-wide {
max-width: 1600px;
margin: 0 auto;
padding: 0 40px;
}
/* Responsive padding */
@media(max-width: 768px) {
.container {
padding: 0 15px;
}
}
Gap Property (Modern)
/* Gap with Flexbox */
.flex-container {
display: flex;
gap: 20px; /* Space between items */
}
.flex-container-varied {
display: flex;
gap: 20px 40px; /* row-gap | column-gap */
}
/* Gap with Grid */
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 30px; /* Space between grid items */
}
.grid-asymmetric {
display: grid;
grid-template-columns: repeat(3, 1fr);
row-gap: 40px; /* Vertical gap */
column-gap: 20px; /* Horizontal gap */
}
/* Benefits over margins:
- No margin on outer edges
- Cleaner code
- Works automatically with wrapping */
Spacing Utilities
/* Margin utilities */
.m-0 { margin: 0; }
.m-1 { margin: var(--space-1); }
.m-2 { margin: var(--space-2); }
.m-4 { margin: var(--space-4); }
.m-8 { margin: var(--space-8); }
/* Directional margins */
.mt-4 { margin-top: var(--space-4); }
.mr-4 { margin-right: var(--space-4); }
.mb-4 { margin-bottom: var(--space-4); }
.ml-4 { margin-left: var(--space-4); }
/* Horizontal/Vertical margins */
.mx-auto { margin-left: auto; margin-right: auto; }
.my-4 { margin-top: var(--space-4); margin-bottom: var(--space-4); }
/* Padding utilities */
.p-0 { padding: 0; }
.p-4 { padding: var(--space-4); }
.p-8 { padding: var(--space-8); }
/* Directional padding */
.pt-4 { padding-top: var(--space-4); }
.px-4 { padding-left: var(--space-4); padding-right: var(--space-4); }
.py-8 { padding-top: var(--space-8); padding-bottom: var(--space-8); }
Practical Layout Example
/* Page structure with consistent spacing */
.page {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header {
padding: var(--space-4) var(--space-8);
background-color: #2c3e50;
}
.main {
flex: 1;
padding: var(--space-12) 0;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 var(--space-6);
}
.section {
margin-bottom: var(--space-16);
}
.section:last-child {
margin-bottom: 0;
}
.card {
padding: var(--space-6);
margin-bottom: var(--space-4);
background: white;
border-radius: 8px;
}
.footer {
padding: var(--space-8);
background-color: #34495e;
margin-top: auto;
}
Practice Tasks
- Create a spacing scale using CSS custom properties with values from 4px to 96px.
- Build a centered container with max-width and horizontal auto margins.
- Implement the stack pattern to add consistent vertical spacing between elements.
- Create utility classes for margin and padding (m-0, m-4, p-0, p-4, etc.).
- Use the gap property with flexbox to space navigation items.
- Build a responsive layout that adjusts padding based on screen size.
Key Takeaways
- Use a consistent spacing scale (e.g., 8-point grid) for visual rhythm.
- box-sizing: border-box makes layout calculations predictable.
- The stack pattern (> * + *) creates consistent vertical spacing.
- Logical properties (margin-inline, padding-block) support internationalization.
- The gap property simplifies spacing in flexbox and grid layouts.
- Center containers horizontally with max-width and margin: 0 auto.
- Use spacing utilities for quick, consistent spacing adjustments.
What's Next?
Next Topics: Master positioning and z-index for layered layouts, then explore display and visibility properties.
Display & Visibility
Control how elements are rendered and displayed
The Display Property
The display property controls how an element generates boxes and participates in layout. It's one of the most fundamental CSS properties for controlling layout behavior.
Block vs Inline
/* Block elements */
.block {
display: block;
/* Takes full width available */
/* Starts on new line */
/* Respects width, height, margin, padding */
}
/* Examples of default block elements: */
div, h1, p, section, article {
display: block;
}
/* Inline elements */
.inline {
display: inline;
/* Only takes up necessary width */
/* Flows with text */
/* Ignores width/height */
/* Vertical margin/padding doesn't push other elements */
}
/* Examples of default inline elements: */
span, a, strong, em, img {
display: inline;
}
Inline-Block
/* Inline-block: flows inline but accepts block properties */
.inline-block {
display: inline-block;
/* Flows horizontally like inline */
/* But respects width, height, margin, padding like block */
}
/* Common use case: navigation buttons */
.nav-button {
display: inline-block;
padding: 10px 20px;
margin: 5px;
background-color: #3498db;
color: white;
text-decoration: none;
border-radius: 5px;
}
/* Creating grid-like layouts (before flexbox) */
.box {
display: inline-block;
width: 30%;
margin: 1.5%;
vertical-align: top; /* Align to top */
}
Display: None
/* Completely removes element from layout */
.hidden {
display: none;
/* Element is not rendered */
/* Takes up no space */
/* Not accessible to screen readers */
}
/* Toggle visibility with JavaScript */
.modal.hidden {
display: none;
}
.modal.visible {
display: block; /* or flex, grid, etc. */
}
/* Hide at specific breakpoints */
@media(max-width: 768px) {
.desktop-only {
display: none;
}
}
@media(min-width: 769px) {
.mobile-only {
display: none;
}
}
Flex and Grid Display
/* Flexbox: one-dimensional layout */
.flex-container {
display: flex;
gap: 20px;
justify-content: space-between;
align-items: center;
}
/* Inline flex: flex container that flows inline */
.inline-flex {
display: inline-flex;
gap: 10px;
}
/* Grid: two-dimensional layout */
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
/* Inline grid: grid container that flows inline */
.inline-grid {
display: inline-grid;
grid-template-columns: auto auto;
}
Visibility Property
/* visibility: hidden - hides but preserves space */
.invisible {
visibility: hidden;
/* Element is invisible */
/* But still takes up space in layout */
/* Layout doesn't shift */
}
/* visibility: visible - default */
.visible {
visibility: visible;
}
/* Comparison */
.display-none {
display: none;
/* Removed from layout - no space */
}
.visibility-hidden {
visibility: hidden;
/* Hidden but space preserved */
}
/* visibility: collapse (tables only) */
table tr.collapsed {
visibility: collapse;
/* Removes row from table like display: none */
}
Opacity
/* Opacity: 0 to 1 */
.transparent {
opacity: 0;
/* Completely transparent */
/* Still takes up space */
/* Still receives clicks/interactions */
}
.semi-transparent {
opacity: 0.5;
/* 50% transparent */
}
.opaque {
opacity: 1;
/* Fully visible (default) */
}
/* Comparison of hiding methods */
.method-1 {
display: none;
/* Invisible, no space, no interaction */
}
.method-2 {
visibility: hidden;
/* Invisible, space preserved, no interaction */
}
.method-3 {
opacity: 0;
/* Invisible, space preserved, STILL interactive */
}
/* Fade transitions work with opacity */
.fade {
opacity: 0;
transition: opacity 0.3s;
}
.fade.active {
opacity: 1;
}
Screen Reader Only
/* Hide visually but keep for screen readers */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
/* Show on focus (for keyboard navigation) */
.sr-only-focusable:focus {
position: static;
width: auto;
height: auto;
overflow: visible;
clip: auto;
white-space: normal;
}
/* Example usage */
/* HTML: */
Display: Contents
/* display: contents - removes element's box */
.wrapper {
display: contents;
/* Element itself produces no box */
/* Children participate in parent's layout */
}
/* Example: Grid spanning across wrapper */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.grid .wrapper {
display: contents;
/* Wrapper disappears, children become grid items */
}
/* Useful for conditional wrapping */
@media(max-width: 768px) {
.conditional-wrapper {
display: contents; /* Remove wrapper on mobile */
}
}
Other Display Values
/* Table display modes */
.table {
display: table;
}
.table-row {
display: table-row;
}
.table-cell {
display: table-cell;
vertical-align: middle;
}
/* List item */
.list-item {
display: list-item;
list-style-type: disc;
}
/* Flow-root (creates block formatting context) */
.clearfix {
display: flow-root;
/* Contains floats without clearfix hack */
}
/* Run-in (rarely used) */
.run-in {
display: run-in;
}
Practical Examples
/* Utility classes for display */
.d-none { display: none; }
.d-block { display: block; }
.d-inline { display: inline; }
.d-inline-block { display: inline-block; }
.d-flex { display: flex; }
.d-inline-flex { display: inline-flex; }
.d-grid { display: grid; }
/* Responsive utilities */
@media(max-width: 767px) {
.d-mobile-none { display: none; }
.d-mobile-block { display: block; }
}
@media(min-width: 768px) and (max-width: 1023px) {
.d-tablet-none { display: none; }
.d-tablet-flex { display: flex; }
}
@media(min-width: 1024px) {
.d-desktop-none { display: none; }
.d-desktop-grid { display: grid; }
}
Practice Tasks
- Create a navigation bar using display: inline-block for menu items.
- Build a responsive layout that hides certain elements on mobile using display: none.
- Implement a fade-in animation using opacity and transitions.
- Create screen-reader-only text for accessibility (.sr-only class).
- Compare the visual effects of display: none, visibility: hidden, and opacity: 0.
- Use display: flex to create a centered card layout.
Key Takeaways
- display: block makes elements take full width and start on new lines.
- display: inline makes elements flow with text, ignoring width/height.
- display: inline-block combines inline flow with block sizing.
- display: none removes elements from layout entirely.
- visibility: hidden hides elements but preserves their space.
- opacity: 0 makes elements transparent but still interactive.
- Use .sr-only class to hide content visually while keeping it accessible.
- display: flex and display: grid create powerful layout contexts.
What's Next?
Next Topics: Master Flexbox for one-dimensional layouts, then learn CSS Grid for two-dimensional layouts.
Positioning & Z-Index
Control element positioning and layering in CSS
Position Property Values
The position property determines how an element is positioned in the document. Each value creates different positioning behavior and stacking context rules.
Static Positioning (Default)
/* Static is the default - follows normal flow */
.element {
position: static; /* Default value */
/* top, right, bottom, left have no effect */
}
/* Block elements stack vertically */
div {
position: static;
/* Each div takes full width and stacks */
}
/* Inline elements flow horizontally */
span {
position: static;
/* Spans flow left-to-right inline */
}
Relative Positioning
/* Relative to its normal position */
.relative-box {
position: relative;
top: 20px; /* Move down 20px from normal position */
left: 30px; /* Move right 30px from normal position */
}
/* Original space is preserved */
.shifted {
position: relative;
top: -10px; /* Move up (negative value) */
/* Other elements act as if this is in original position */
}
/* Common use: positioning context for absolute children */
.container {
position: relative; /* Creates positioning context */
}
.container .badge {
position: absolute;
top: -10px;
right: -10px;
}
/* Z-index works with relative positioning */
.relative-layered {
position: relative;
z-index: 10;
}
Absolute Positioning
/* Absolute positioning removes element from flow */
.absolute-box {
position: absolute;
top: 0;
left: 0;
/* Positioned relative to nearest positioned ancestor */
}
/* Centered absolutely positioned element */
.centered-absolute {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* Stretch to fill container */
.overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* Or use: */
inset: 0; /* Shorthand for top, right, bottom, left */
}
/* Badge positioned on corner */
.card {
position: relative; /* Positioning context */
}
.badge {
position: absolute;
top: 10px;
right: 10px;
background-color: #e74c3c;
color: white;
padding: 5px 10px;
border-radius: 12px;
}
/* Dropdown positioning */
.dropdown {
position: relative;
}
.dropdown-menu {
position: absolute;
top: 100%; /* Below the dropdown button */
left: 0;
min-width: 200px;
background: white;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
Fixed Positioning
/* Fixed to viewport - doesn't scroll */
.fixed-header {
position: fixed;
top: 0;
left: 0;
right: 0;
background-color: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
z-index: 100;
}
/* Fixed footer */
.fixed-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #2c3e50;
color: white;
padding: 20px;
}
/* Floating action button */
.fab {
position: fixed;
bottom: 30px;
right: 30px;
width: 60px;
height: 60px;
border-radius: 50%;
background-color: #3498db;
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
z-index: 999;
}
/* Modal backdrop */
.modal-backdrop {
position: fixed;
inset: 0; /* Covers entire viewport */
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
}
/* Remember: Fixed elements don't scroll with page */
Sticky Positioning
/* Sticky: Relative until threshold, then fixed */
.sticky-header {
position: sticky;
top: 0; /* Sticks when scrolled to top */
background-color: white;
z-index: 10;
}
/* Sticky sidebar */
.sidebar {
position: sticky;
top: 20px; /* 20px from top when stuck */
align-self: flex-start;
}
/* Sticky table headers */
thead th {
position: sticky;
top: 0;
background-color: #f8f9fa;
z-index: 10;
}
/* Sticky navigation tabs */
.tabs {
position: sticky;
top: 60px; /* Below fixed header */
background-color: white;
border-bottom: 1px solid #ddd;
}
/* Important: Parent must have height/overflow for sticky to work */
.container {
height: 100vh;
overflow-y: auto;
}
Z-Index and Stacking Context
/* Z-index only works with positioned elements */
.layer-1 {
position: relative;
z-index: 1;
}
.layer-2 {
position: relative;
z-index: 2; /* Appears above layer-1 */
}
/* Common z-index scale */
.dropdown {
z-index: 1000;
}
.modal {
z-index: 2000;
}
.tooltip {
z-index: 3000;
}
.notification {
z-index: 4000;
}
/* Negative z-index */
.background-decoration {
position: absolute;
z-index: -1; /* Behind normal flow elements */
}
/* Z-index variables for consistency */
:root {
--z-dropdown: 1000;
--z-sticky: 1020;
--z-fixed: 1030;
--z-modal-backdrop: 1040;
--z-modal: 1050;
--z-popover: 1060;
--z-tooltip: 1070;
}
Stacking Context
/* These properties create new stacking context: */
/* 1. Positioned elements with z-index */
.context-1 {
position: relative;
z-index: 1; /* Creates stacking context */
}
/* 2. Opacity less than 1 */
.context-2 {
opacity: 0.99; /* Creates stacking context */
}
/* 3. Transform */
.context-3 {
transform: translateZ(0); /* Creates stacking context */
}
/* 4. Filter */
.context-4 {
filter: blur(5px); /* Creates stacking context */
}
/* 5. Flexbox/Grid children with z-index */
.flex-container {
display: flex;
}
.flex-item {
z-index: 1; /* Creates stacking context (no position needed) */
}
/* Stacking context isolation example */
.parent {
position: relative;
z-index: 1;
}
.parent .child {
position: relative;
z-index: 9999; /* Only affects stacking within .parent */
}
.sibling {
position: relative;
z-index: 2; /* Will appear above .parent and all children */
}
Practical Examples
/* Complete modal positioning */
.modal-backdrop {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1040;
display: flex;
align-items: center;
justify-content: center;
}
.modal {
position: relative;
max-width: 600px;
width: 90%;
background: white;
border-radius: 8px;
padding: 30px;
z-index: 1050;
max-height: 90vh;
overflow-y: auto;
}
.modal-close {
position: absolute;
top: 15px;
right: 15px;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
}
Inset Property
/* Old way */
.overlay-old {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
/* New way with inset */
.overlay-new {
position: absolute;
inset: 0; /* All sides */
}
/* Inset with values */
.inset-values {
position: absolute;
inset: 10px; /* 10px from all sides */
}
.inset-asymmetric {
position: absolute;
inset: 10px 20px; /* vertical | horizontal */
}
.inset-all {
position: absolute;
inset: 10px 20px 30px 40px; /* top right bottom left */
}
/* Logical inset properties */
.inset-logical {
position: absolute;
inset-block: 10px; /* top and bottom */
inset-inline: 20px; /* left and right (adapts to writing mode) */
}
Practice Tasks
- Create a card with an absolutely positioned badge in the top-right corner.
- Build a fixed header that stays at the top while scrolling.
- Implement a sticky sidebar that stays in view while scrolling content.
- Create a modal dialog with fixed backdrop and centered content.
- Build a floating action button (FAB) in the bottom-right corner.
- Test z-index stacking by creating overlapping positioned elements.
Key Takeaways
- static: default positioning, follows normal document flow.
- relative: offset from normal position, preserves space, creates positioning context.
- absolute: removed from flow, positioned relative to nearest positioned ancestor.
- fixed: positioned relative to viewport, doesn't scroll with page.
- sticky: relative until scroll threshold, then fixed.
- z-index only works on positioned elements (not static).
- Many properties create stacking contexts: opacity, transform, filter, z-index.
- Use inset shorthand instead of top/right/bottom/left for cleaner code.
What's Next?
Next Topics: Explore display and visibility properties, then master Flexbox for flexible one-dimensional layouts.
Floats & Clearfix
Understanding legacy layout techniques and when to use modern alternatives
Floats were originally designed for wrapping text around images, not for layouts. While modern CSS provides better layout tools (Flexbox and Grid), understanding floats remains important for maintaining legacy code and specific text-wrapping scenarios. Learn when to use floats and how to properly clear them.
Float Basics
The float property allows elements to be taken out of normal flow and positioned to the left or right.
/* Float left */
.float-left {
float: left;
margin-right: 1rem;
margin-bottom: 1rem;
}
/* Float right */
.float-right {
float: right;
margin-left: 1rem;
margin-bottom: 1rem;
}
/* No float */
.float-none {
float: none;
}
/* Image with text wrap */
.article img {
float: left;
max-width: 300px;
margin: 0 1.5rem 1rem 0;
border-radius: 8px;
}
<article class="article">
<img src="image.jpg" alt="Article image">
<p>This text will wrap around the floated image. The float property removes the image from normal document flow and positions it to the left, allowing text content to flow around it naturally.</p>
<p>Multiple paragraphs will continue to wrap around the image until it's cleared.</p>
</article>
Clearing Floats
The clear property prevents elements from wrapping around floated elements.
/* Clear both sides */
.clear {
clear: both;
}
/* Clear specific side */
.clear-left {
clear: left;
}
.clear-right {
clear: right;
}
/* Example usage */
.sidebar {
float: left;
width: 250px;
}
.content {
float: right;
width: calc(100% - 270px);
}
.footer {
clear: both;
/* Footer appears below both floated elements */
}
Clearfix Technique
The clearfix hack forces a container to wrap around its floated children.
/* Modern clearfix (recommended) */
.clearfix::after {
content: "";
display: table;
clear: both;
}
/* Alternative clearfix */
.clearfix::before{
.clearfix::after {
content: "";
display: table;
}
.clearfix::after {
clear: both;
}
/* Legacy clearfix (older browser support) */
.clearfix {
*zoom: 1;
}
.clearfix::before{
.clearfix::after {
content: " ";
display: table;
}
.clearfix::after {
clear: both;
}
/* Usage */
.container {
/* Container has floated children */
}
.container.clearfix {
/* Now properly contains floated children */
}
<div class="container clearfix">
<div class="box float-left">Box 1</div>
<div class="box float-left">Box 2</div>
<!-- Container will properly wrap these floated elements -->
</div>
Float-Based Layouts (Legacy)
Understanding how floats were used for multi-column layouts before Flexbox and Grid.
/* Two-column layout with floats */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.container::after {
content: "";
display: table;
clear: both;
}
.sidebar {
float: left;
width: 25%;
padding-right: 20px;
box-sizing: border-box;
}
.main-content {
float: left;
width: 75%;
box-sizing: border-box;
}
/* Three-column layout */
.col-3 {
float: left;
width: 33.333%;
padding: 0 10px;
box-sizing: border-box;
}
.row::after {
content: "";
display: table;
clear: both;
}
/* Responsive float layout */
@media(max-width: 768px) {
.sidebar{
.main-content{
.col-3 {
float: none;
width: 100%;
padding: 0;
}
}
Float Issues and Solutions
Common problems with floats and how to fix them.
/* Issue 1: Parent collapse */
.parent {
/* Without clearfix, height collapses to 0 */
border: 1px solid #ccc;
}
.child {
float: left;
}
/* Solution: Add clearfix */
.parent.clearfix::after {
content: "";
display: table;
clear: both;
}
/* Issue 2: Margin collapse */
.floated {
float: left;
margin-bottom: 20px; /* Margins may not behave as expected */
}
/* Solution: Use padding on parent or avoid floats */
.parent {
padding-bottom: 20px;
}
/* Issue 3: Z-index doesn't work */
.floated-element {
float: left;
z-index: 10; /* Has no effect */
}
/* Solution: Add position */
.floated-element {
float: left;
position: relative;
z-index: 10; /* Now works */
}
/* Issue 4: Equal height columns */
.column {
float: left;
width: 50%;
/* Heights don't match automatically */
}
/* Solution: Use Flexbox instead */
.flex-container {
display: flex;
}
.flex-column {
flex: 1;
/* Heights match automatically */
}
Modern Alternatives
When to use Flexbox or Grid instead of floats.
/* FLOATS - Use only for text wrapping */
.text-with-image img {
float: left;
margin: 0 1rem 1rem 0;
}
/* FLEXBOX - Use for one-dimensional layouts */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
}
.card-row {
display: flex;
gap: 1rem;
}
.card {
flex: 1;
}
/* GRID - Use for two-dimensional layouts */
.page-layout {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
gap: 20px;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
/* Comparison: Two-column layout */
/* OLD WAY (Float) */
.float-layout .sidebar {
float: left;
width: 25%;
}
.float-layout .content {
float: right;
width: 75%;
}
.float-layout::after {
content: "";
display: table;
clear: both;
}
/* NEW WAY (Flexbox) - Simpler! */
.flex-layout {
display: flex;
gap: 20px;
}
.flex-layout .sidebar {
flex: 0 0 25%;
}
.flex-layout .content {
flex: 1;
}
/* NEW WAY (Grid) - Even better! */
.grid-layout {
display: grid;
grid-template-columns: 1fr 3fr;
gap: 20px;
}
Practical Float Usage
Real-world scenarios where floats are still appropriate.
/* 1. Magazine-style text wrapping */
.article {
font-size: 1.125rem;
line-height: 1.75;
}
.article .featured-image {
float: left;
max-width: 40%;
margin: 0 2rem 1rem 0;
shape-outside: margin-box;
}
/* 2. Pull quotes */
.pull-quote {
float: right;
width: 40%;
margin: 0 0 1rem 2rem;
padding: 1rem;
border-left: 4px solid #3b82f6;
font-size: 1.25rem;
font-style: italic;
}
/* 3. Drop caps */
.article p:first-of-type::first-letter {
float: left;
font-size: 4rem;
line-height: 0.8;
margin: 0.1rem 0.2rem 0 0;
font-weight: bold;
color: #3b82f6;
}
/* 4. Image galleries with text (but Grid is better) */
.legacy-gallery img {
float: left;
width: calc(33.333% - 1rem);
margin-right: 1rem;
margin-bottom: 1rem;
}
.legacy-gallery img:nth-child(3n) {
margin-right: 0;
}
.legacy-gallery::after {
content: "";
display: table;
clear: both;
}
/* Modern alternative */
.modern-gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
Shape-Outside with Floats
Create advanced text wrapping effects with shape-outside.
/* Circular text wrap */
.circular-image {
float: left;
width: 200px;
height: 200px;
border-radius: 50%;
shape-outside: circle(50%);
margin: 0 2rem 1rem 0;
}
/* Polygon shape */
.triangular {
float: left;
width: 200px;
height: 200px;
shape-outside: polygon(0 0, 100% 0, 100% 100%);
clip-path: polygon(0 0, 100% 0, 100% 100%);
background: #3b82f6;
margin-right: 1rem;
}
/* Image with transparent background */
.shaped-image {
float: left;
max-width: 300px;
shape-outside: url('shape.png');
shape-margin: 1rem;
}
/* Inset shape */
.inset-shape {
float: right;
width: 300px;
height: 300px;
shape-outside: inset(20px round 20px);
background: linear-gradient(135deg, #667eea, #764ba2);
margin-left: 2rem;
}
Responsive Float Layouts
Make float-based layouts responsive with media queries.
/* Desktop float layout */
.content-sidebar {
max-width: 1200px;
margin: 0 auto;
}
.content-sidebar::after {
content: "";
display: table;
clear: both;
}
.sidebar {
float: left;
width: 30%;
padding-right: 2rem;
}
.main {
float: right;
width: 70%;
}
/* Tablet */
@media(max-width: 1024px) {
.sidebar {
width: 35%;
}
.main {
width: 65%;
}
}
/* Mobile - stack vertically */
@media(max-width: 768px) {
.sidebar{
.main {
float: none;
width: 100%;
padding: 0;
}
.sidebar {
margin-bottom: 2rem;
}
}
/* Mobile-first approach (better) */
.responsive-sidebar {
width: 100%;
}
.responsive-main {
width: 100%;
}
@media(min-width: 768px) {
.responsive-sidebar {
float: left;
width: 30%;
}
.responsive-main {
float: right;
width: 70%;
}
}
Practice Exercises
- Magazine Article: Create an article with a floated featured image and text wrapping around it naturally.
- Pull Quote: Implement a styled pull quote that floats within article text with proper clearfix.
- Legacy Grid: Build a three-column layout using floats, then refactor it using CSS Grid.
- Shape-Outside: Create circular images with text flowing around them using shape-outside.
- Responsive Float: Design a sidebar layout with floats that stacks vertically on mobile devices.
- Floats are primarily for text wrapping, not layout
- Always use clearfix to contain floated elements
- Prefer Flexbox for one-dimensional layouts
- Prefer Grid for two-dimensional layouts
- Shape-outside creates advanced wrapping effects
- Understanding floats helps maintain legacy code
What's Next?
Learn modern layout techniques with Flexbox and CSS Grid, or explore Best Practices for choosing the right layout method.
Flexbox
Master flexible one-dimensional layouts with Flexbox
What is Flexbox?
Flexbox (Flexible Box Layout) is a one-dimensional layout method for arranging items in rows or columns. Items flex to fill available space or shrink to fit into smaller spaces.
Flex Container Basics
/* Enable flexbox */
.container {
display: flex;
/* All direct children become flex items */
}
/* Inline flex container */
.inline-container {
display: inline-flex;
/* Container itself is inline */
}
/* Simple horizontal layout */
.nav {
display: flex;
gap: 20px;
}
.nav-item {
/* Flex items automatically arranged horizontally */
}
Flex Direction
/* Horizontal (default) */
.row {
display: flex;
flex-direction: row; /* Left to right */
}
/* Horizontal reversed */
.row-reverse {
display: flex;
flex-direction: row-reverse; /* Right to left */
}
/* Vertical */
.column {
display: flex;
flex-direction: column; /* Top to bottom */
}
/* Vertical reversed */
.column-reverse {
display: flex;
flex-direction: column-reverse; /* Bottom to top */
}
/* Responsive direction change */
.responsive-flex {
display: flex;
flex-direction: row;
}
@media(max-width: 768px) {
.responsive-flex {
flex-direction: column;
}
}
Justify Content (Main Axis)
/* Start (default) */
.justify-start {
display: flex;
justify-content: flex-start;
}
/* End */
.justify-end {
display: flex;
justify-content: flex-end;
}
/* Center */
.justify-center {
display: flex;
justify-content: center;
}
/* Space between items */
.justify-between {
display: flex;
justify-content: space-between;
/* First item at start, last at end, equal space between */
}
/* Space around items */
.justify-around {
display: flex;
justify-content: space-around;
/* Equal space around each item */
}
/* Space evenly */
.justify-evenly {
display: flex;
justify-content: space-evenly;
/* Equal space between items and edges */
}
Align Items (Cross Axis)
/* Stretch (default) */
.align-stretch {
display: flex;
align-items: stretch;
/* Items stretch to fill container height */
}
/* Start */
.align-start {
display: flex;
align-items: flex-start;
/* Align to top (in row direction) */
}
/* End */
.align-end {
display: flex;
align-items: flex-end;
/* Align to bottom (in row direction) */
}
/* Center */
.align-center {
display: flex;
align-items: center;
/* Vertically center items */
}
/* Baseline */
.align-baseline {
display: flex;
align-items: baseline;
/* Align to text baseline */
}
/* Perfect centering */
.center-both {
display: flex;
justify-content: center;
align-items: center;
/* Perfectly centered horizontally and vertically */
}
Flex Wrap
/* No wrap (default) */
.nowrap {
display: flex;
flex-wrap: nowrap;
/* Items stay on one line */
}
/* Wrap to multiple lines */
.wrap {
display: flex;
flex-wrap: wrap;
/* Items wrap to next line */
}
/* Wrap in reverse */
.wrap-reverse {
display: flex;
flex-wrap: wrap-reverse;
}
/* Responsive card grid */
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.card {
flex: 1 1 300px; /* Grow, shrink, base width */
/* Cards wrap when they can't fit */
}
Flex Items: Flex Property
/* flex: flex-grow flex-shrink flex-basis */
/* Equal width items */
.equal-items > * {
flex: 1;
/* flex: 1 1 0 - All items equal width */
}
/* Fixed and flexible items */
.sidebar {
flex: 0 0 250px;
/* Don't grow, don't shrink, 250px wide */
}
.main {
flex: 1;
/* Takes remaining space */
}
/* Proportional sizing */
.col-2 {
flex: 2; /* Takes 2x space */
}
.col-1 {
flex: 1; /* Takes 1x space */
}
/* Common patterns */
.auto {
flex: auto; /* flex: 1 1 auto */
}
.none {
flex: none; /* flex: 0 0 auto - Fixed size */
}
/* Responsive flex items */
.responsive-item {
flex: 1 1 300px;
/* Grow, shrink, but at least 300px */
}
Align Self
/* Override container's align-items for individual item */
.container {
display: flex;
align-items: flex-start;
}
.item-center {
align-self: center;
/* This item centers itself */
}
.item-end {
align-self: flex-end;
}
.item-stretch {
align-self: stretch;
}
.item-baseline {
align-self: baseline;
}
/* Auto (default) - use container's align-items */
.item-auto {
align-self: auto;
}
Gap Property
/* Gap between items (no outer margins) */
.container {
display: flex;
gap: 20px;
/* 20px between all items */
}
/* Different horizontal and vertical gaps */
.container-2 {
display: flex;
flex-wrap: wrap;
gap: 30px 20px; /* row-gap column-gap */
}
/* Individual gap properties */
.container-3 {
display: flex;
flex-wrap: wrap;
row-gap: 30px;
column-gap: 20px;
}
/* Gap with responsive values */
.responsive-gap {
display: flex;
gap: clamp(10px, 2vw, 30px);
}
Order
/* Change visual order without changing HTML */
.item-1 {
order: 2; /* Appears second */
}
.item-2 {
order: 1; /* Appears first */
}
.item-3 {
order: 3; /* Appears third */
}
/* Default order is 0 */
/* Lower numbers appear first */
/* Negative values allowed */
/* Move to end */
.last {
order: 999;
}
/* Move to start */
.first {
order: -1;
}
/* Responsive reordering */
@media(max-width: 768px) {
.sidebar {
order: 2; /* Move sidebar below main on mobile */
}
.main {
order: 1;
}
}
Practical Examples
/* Responsive navigation */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 30px;
background-color: #2c3e50;
}
.nav-brand {
font-size: 1.5rem;
color: white;
}
.nav-menu {
display: flex;
gap: 30px;
list-style: none;
}
.nav-link {
color: white;
text-decoration: none;
}
@media(max-width: 768px) {
.navbar {
flex-direction: column;
gap: 15px;
}
.nav-menu {
flex-direction: column;
gap: 10px;
width: 100%;
text-align: center;
}
}
Flexbox Card Layout
/* Flexible card grid */
.card-container {
display: flex;
flex-wrap: wrap;
gap: 25px;
padding: 20px;
}
.card {
flex: 1 1 300px; /* Grow, shrink, min 300px */
max-width: 400px; /* Don't get too wide */
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
/* Make card a flex container for its content */
display: flex;
flex-direction: column;
}
.card-header {
margin-bottom: 15px;
}
.card-body {
flex: 1; /* Takes available space */
}
.card-footer {
margin-top: auto; /* Push to bottom */
padding-top: 15px;
border-top: 1px solid #ddd;
}
Practice Tasks
- Create a centered flex container with justify-content and align-items.
- Build a responsive navigation bar that switches from row to column on mobile.
- Create a card grid that automatically wraps using flex-wrap and gap.
- Build a layout with fixed sidebar (250px) and flexible main content.
- Use align-self to make one item in a flex container align differently.
- Implement a footer that sticks to the bottom using flexbox on the body.
Key Takeaways
- Flexbox is one-dimensional: arranges items in a row or column.
- justify-content aligns items along the main axis.
- align-items aligns items along the cross axis.
- flex-wrap allows items to wrap to multiple lines.
- flex property controls how items grow, shrink, and size.
- gap provides clean spacing between flex items.
- order can reorder items visually without changing HTML.
- Flexbox is perfect for navigation bars, toolbars, and card layouts.
What's Next?
Next Topics: Learn CSS Grid for two-dimensional layouts, then explore floats and clearfix for legacy support.
CSS Grid Layout
Master the powerful two-dimensional layout system for complex web designs
CSS Grid is a powerful two-dimensional layout system that lets you create complex responsive layouts with rows and columns. Unlike Flexbox (which is one-dimensional), Grid excels at creating structured layouts where you need precise control over both axes.
Creating a Grid Container
To use CSS Grid, set display: grid on a parent element. This element becomes the grid container, and its direct children become grid items.
{
display: grid;
grid-template-columns: 200px 200px 200px;
grid-template-rows: 100px 100px;
gap: 20px;
background-color: #f0f0f0;
padding: 20px;
}
.grid-item {
background-color: #3b82f6;
color: white;
padding: 20px;
text-align: center;
border-radius: 8px;
}
<div class="grid-container">
<div class="grid-item">Item 1</div>
<div class="grid-item">Item 2</div>
<div class="grid-item">Item 3</div>
<div class="grid-item">Item 4</div>
<div class="grid-item">Item 5</div>
<div class="grid-item">Item 6</div>
</div>
The FR Unit (Fraction)
The fr unit represents a fraction of the available space in the grid container. It's one of the most powerful features of CSS Grid, allowing flexible and responsive layouts without media queries.
/* Three equal columns */
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 16px;
}
/* Sidebar layout: sidebar takes 1 part, main takes 3 parts */
.layout {
display: grid;
grid-template-columns: 1fr 3fr;
gap: 24px;
}
/* Mixed units */
.mixed {
display: grid;
grid-template-columns: 250px 1fr 2fr;
gap: 20px;
}
Repeat Function
The repeat() function simplifies grid definitions when you have repeating patterns. It's especially useful for creating equal-width columns.
/* 4 equal columns */
.grid {
grid-template-columns: repeat(4, 1fr);
}
/* 6 columns of 100px each */
.grid {
grid-template-columns: repeat(6, 100px);
}
/* Alternating pattern */
.grid {
grid-template-columns: repeat(3, 200px 1fr);
/* Results in: 200px 1fr 200px 1fr 200px 1fr */
}
Auto-Fit and Auto-Fill
These keywords create responsive grids that automatically adjust the number of columns based on available space.
/* Auto-fit: collapses empty tracks */
.grid-auto-fit {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
/* Auto-fill: preserves empty tracks */
.grid-auto-fill {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
}
/* Card grid that adapts automatically */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 24px;
padding: 20px;
}
Grid Gap (Gutter)
The gap property (formerly grid-gap) creates space between grid items without affecting the outer edges.
/* Equal gap for rows and columns */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
/* Different row and column gaps */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
row-gap: 30px;
column-gap: 15px;
}
/* Shorthand: row-gap column-gap */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 30px 15px;
}
Grid Template Areas
Named grid areas provide a visual way to define layouts, making your CSS more readable and maintainable.
.page-layout {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
gap: 20px;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
/* Responsive: stack on small screens */
@media(max-width: 768px) {
.page-layout {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
}
}
Placing Grid Items
You can explicitly position items using grid lines or span across multiple cells.
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 100px);
gap: 10px;
}
/* Place item from column 1 to 3, row 1 to 2 */
.item-1 {
grid-column: 1 / 3;
grid-row: 1 / 2;
}
/* Span 2 columns, 2 rows */
.item-2 {
grid-column: span 2;
grid-row: span 2;
}
/* Place from line 2 to the end */
.item-3 {
grid-column: 2 / -1;
grid-row: 2 / -1;
}
Alignment in Grid
CSS Grid provides powerful alignment properties for both the grid container and individual items.
/* Align all items within their grid cells */
.grid {
display: grid;
grid-template-columns: repeat(3, 200px);
gap: 20px;
/* Align items horizontally */
justify-items: center;
/* Align items vertically */
align-items: center;
/* Shorthand for both */
place-items: center;
}
/* Align the grid within the container */
.grid-container {
display: grid;
grid-template-columns: repeat(3, 200px);
height: 600px;
/* Align grid horizontally */
justify-content: center;
/* Align grid vertically */
align-content: center;
/* Shorthand */
place-content: center;
}
/* Align individual item */
.item {
justify-self: end;
align-self: start;
}
Practical Grid Layouts
.holy-grail {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav content aside"
"footer footer footer";
gap: 16px;
min-height: 100vh;
}
.header { grid-area: header; }
.nav { grid-area: nav; }
.content { grid-area: content; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
@media(max-width: 768px) {
.holy-grail {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"nav"
"content"
"aside"
"footer";
}
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-auto-rows: 250px;
gap: 16px;
}
.gallery-item {
position: relative;
overflow: hidden;
border-radius: 8px;
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Feature image spans 2 columns and 2 rows */
.gallery-item--featured {
grid-column: span 2;
grid-row: span 2;
}
.dashboard {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-auto-rows: minmax(100px, auto);
gap: 20px;
padding: 20px;
}
.widget-large { grid-column: span 8; }
.widget-medium { grid-column: span 6; }
.widget-small { grid-column: span 4; }
.widget-full { grid-column: span 12; }
@media(max-width: 1024px) {
.widget-large, .widget-medium {
grid-column: span 12;
}
.widget-small { grid-column: span 6; }
}
@media(max-width: 640px) {
.widget-small { grid-column: span 12; }
}
Practice Task
- Create a responsive card grid that displays 4 cards per row on large screens, 2 on tablets, and 1 on mobile using
repeat(auto-fit, minmax()) - Build a blog layout using named grid areas with header, sidebar, main content, and footer
- Create an image gallery where the first image spans 2 columns and 2 rows (featured image)
- Build a dashboard with different sized widgets using a 12-column grid system
Key Takeaways
- Two-dimensional: Grid is perfect for layouts that need control over rows AND columns
- FR unit: Use
frfor flexible, proportional sizing - Auto-fit/Auto-fill: Create responsive grids without media queries
- Named areas: Make complex layouts readable with
grid-template-areas - Gap property: Easily add spacing between grid items
- Grid lines: Position items precisely using line numbers or
span - Alignment: Powerful alignment options for both container and items
What's Next?
Now that you understand CSS Grid, explore Flexbox for one-dimensional layouts, learn about Responsive Design with Media Queries, or dive into CSS Positioning for advanced layout control.
Responsive Design & Media Queries
Create fluid layouts that adapt beautifully to any screen size
Responsive web design ensures your website looks great and functions properly on all devices, from smartphones to large desktop monitors. Media queries are the cornerstone of responsive design, allowing you to apply different styles based on screen characteristics.
Mobile-First Approach
The mobile-first strategy starts with styles for small screens, then uses min-width media queries to enhance the design for larger screens. This approach prioritizes performance and ensures a solid foundation for all devices.
/* Base styles (mobile) */
.container {
width: 100%;
padding: 16px;
}
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
}
/* Tablet and up (min-width: 768px) */
@media(min-width: 768px) {
.container {
padding: 24px;
}
.grid {
grid-template-columns: repeat(2, 1fr);
gap: 24px;
}
}
/* Desktop and up (min-width: 1024px) */
@media(min-width: 1024px) {
.container {
max-width: 1200px;
margin: 0 auto;
padding: 32px;
}
.grid {
grid-template-columns: repeat(3, 1fr);
gap: 32px;
}
}
Common Breakpoints
While breakpoints should ideally be content-driven, these standard breakpoints work well for most projects:
/* Extra small devices (portrait phones) */
/* Default styles - no media query needed */
/* Small devices (landscape phones, 576px and up) */
@media(min-width: 576px) {
.container { max-width: 540px; }
}
/* Medium devices (tablets, 768px and up) */
@media(min-width: 768px) {
.container { max-width: 720px; }
.navbar { display: flex; }
}
/* Large devices (desktops, 992px and up) */
@media(min-width: 992px) {
.container { max-width: 960px; }
.sidebar { display: block; }
}
/* Extra large devices (large desktops, 1200px and up) */
@media(min-width: 1200px) {
.container { max-width: 1140px; }
}
/* Extra extra large devices (larger desktops, 1400px and up) */
@media(min-width: 1400px) {
.container { max-width: 1320px; }
}
Desktop-First Approach
Some projects start with desktop styles and use max-width media queries to adapt for smaller screens. This approach is less common but can work for desktop-focused applications.
/* Base styles (desktop) */
.navigation {
display: flex;
gap: 32px;
}
.nav-item {
padding: 12px 24px;
}
/* Tablet and smaller (max-width: 1023px) */
@media(max-width: 1023px) {
.navigation {
gap: 16px;
}
.nav-item {
padding: 10px 16px;
}
}
/* Mobile (max-width: 767px) */
@media(max-width: 767px) {
.navigation {
flex-direction: column;
gap: 8px;
}
.nav-item {
padding: 8px 12px;
}
}
Media Query Features
Media queries can test for many device characteristics beyond just width:
/* Orientation */
@media(orientation: landscape) {
.hero { height: 60vh; }
}
@media(orientation: portrait) {
.hero { height: 80vh; }
}
/* Aspect ratio */
@media(min-aspect-ratio: 16/9) {
.video-container { max-width: 1200px; }
}
/* High DPI screens (Retina displays) */
@media(min-resolution: 2dppx) {
.logo {
background-image: url('logo@2x.png');
background-size: 200px 50px;
}
}
/* Hover capability (mouse/trackpad present) */
@media(hover: hover) {
.button:hover {
background-color: #2563eb;
transform: translateY(-2px);
}
}
/* Touch devices */
@media(hover: none) and (pointer: coarse) {
.button {
padding: 14px 24px; /* Larger for touch */
}
}
/* Reduced motion preference */
@media(prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
/* Dark mode preference */
@media(prefers-color-scheme: dark) {
body {
background-color: #1a1a1a;
color: #f0f0f0;
}
}
Combining Media Queries
You can combine multiple conditions using logical operators:
/* AND: both conditions must be true */
@media(min-width: 768px) and (max-width: 1023px) {
.tablet-only { display: block; }
}
/* OR: at least one condition must be true */
@media(max-width: 767px), (orientation: portrait) {
.mobile-portrait { display: block; }
}
/* NOT: inverts the condition */
@media not all and (min-width: 768px) {
.mobile-only { display: block; }
}
/* Complex combination */
@media(min-width: 768px) and (max-width: 1199px) and (orientation: landscape) {
.tablet-landscape {
grid-template-columns: repeat(3, 1fr);
}
}
Container Queries (Modern CSS)
Container queries allow components to respond to their container's size rather than the viewport, enabling true component-based responsive design.
/* Define container */
.card-container {
container-type: inline-size;
container-name: card;
}
/* Query the container */
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
gap: 20px;
}
.card-image {
height: 100%;
}
}
@container card (min-width: 600px) {
.card {
grid-template-columns: 300px 1fr;
}
}
Responsive Typography
/* Traditional approach with media queries */
h1 {
font-size: 28px;
}
@media(min-width: 768px) {
h1 { font-size: 36px; }
}
@media(min-width: 1200px) {
h1 { font-size: 48px; }
}
/* Modern approach with clamp() */
h1 {
font-size: clamp(28px, 2.5vw + 1rem, 48px);
}
h2 {
font-size: clamp(24px, 2vw + 0.75rem, 36px);
}
p {
font-size: clamp(16px, 1.2vw, 18px);
line-height: 1.6;
}
Print Styles
@media print {
/* Hide navigation and non-essential elements */
nav, footer, .sidebar, .ads {
display: none;
}
/* Optimize for print */
body {
font-size: 12pt;
color: #000;
background: #fff;
}
a {
text-decoration: underline;
color: #000;
}
/* Show URLs after links */
a::after {
content: " (" attr(href) ")";
}
/* Page breaks */
h1, h2, h3 {
page-break-after: avoid;
}
img {
max-width: 100%;
page-break-inside: avoid;
}
}
Responsive Images
<!-- Using srcset for different resolutions -->
<img
src="image-800.jpg"
srcset="image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w"
sizes="(max-width: 600px) 400px,
(max-width: 900px) 800px,
1200px"
alt="Responsive image">
<!-- Using picture element for art direction -->
<picture>
<source media="(min-width: 1200px)" srcset="hero-large.jpg">
<source media="(min-width: 768px)" srcset="hero-medium.jpg">
<img src="hero-small.jpg" alt="Hero image">
</picture>
/* Responsive images */
img {
max-width: 100%;
height: auto;
display: block;
}
/* Maintain aspect ratio with object-fit */
.hero-image {
width: 100%;
height: 400px;
object-fit: cover;
}
@media(min-width: 768px) {
.hero-image {
height: 600px;
}
}
Practice Task
- Create a mobile-first layout that displays 1 column on mobile, 2 on tablet (768px+), and 4 on desktop (1200px+)
- Build a navigation that shows a hamburger menu on mobile and a horizontal menu on desktop
- Implement dark mode using
prefers-color-schememedia query - Create print-friendly styles that hide navigation and show link URLs
- Use
clamp()to create fluid typography that scales with viewport width
Key Takeaways
- Mobile-first: Start with mobile styles and enhance for larger screens
- Standard breakpoints: 576px, 768px, 992px, 1200px, 1400px work for most projects
- Beyond width: Use orientation, hover, resolution, and preference media queries
- Container queries: Modern approach for component-based responsive design
- Fluid typography: Use
clamp()for responsive text without media queries - Responsive images: Use
srcset,sizes, andpictureelements - Print styles: Don't forget about print media queries for better printed pages
What's Next?
Continue with CSS Units & Values to learn about responsive units like rem, vh, and vw. Then explore CSS Grid and Flexbox for powerful responsive layouts.
Typography & Web Fonts
Create beautiful, readable text with modern font techniques
Typography is one of the most important aspects of web design. Good typography improves readability, establishes hierarchy, and creates visual appeal. CSS provides extensive control over fonts, sizing, spacing, and text effects.
Font Families
The font-family property specifies which fonts to use. Always provide fallback fonts in case the primary font fails to load.
/* System font stack (fast, no loading) */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen, Ubuntu, Cantarell, sans-serif;
}
/* Serif fonts */
.serif {
font-family: Georgia, 'Times New Roman', Times, serif;
}
/* Monospace fonts */
.code {
font-family: 'Courier New', Courier, monospace;
font-size: 0.9em;
}
/* Modern font with fallbacks */
.heading {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
}
Loading Web Fonts
Web fonts allow you to use custom typography beyond system fonts. Use @font-face to load fonts from your server or link to hosted fonts.
/* Load a web font */\n@@font-face {\n font-family: 'Inter';\n src: url('/fonts/Inter-Regular.woff2') format('woff2'),\n url('/fonts/Inter-Regular.woff') format('woff');\n font-weight: 400;\n font-style: normal;\n font-display: swap; /* Show fallback font while loading */\n}\n\n@@font-face {\n font-family: 'Inter';\n src: url('/fonts/Inter-Bold.woff2') format('woff2');\n font-weight: 700;\n font-style: normal;\n font-display: swap;\n}\n\nbody {\n font-family: 'Inter', sans-serif;\n}\n <!-- In HTML head -->\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap\" rel=\"stylesheet\">\n\n/* Use in CSS */\nbody {\n font-family: 'Inter', sans-serif;\n}\n Font Size
\n/* Use rem for scalable typography */\n:root { font-size: 16px; }\n\nh1 { font-size: 2.5rem; } /* 40px */\nh2 { font-size: 2rem; } /* 32px */\nh3 { font-size: 1.5rem; } /* 24px */\np { font-size: 1rem; } /* 16px */\nsmall { font-size: 0.875rem; } /* 14px */\n\n/* Fluid typography with clamp() */\nh1 {\n font-size: clamp(2rem, 5vw, 4rem);\n}\n\n/* Responsive with media queries */\n.title {\n font-size: 2rem;\n}\n\n@@media (min-width: 768px) {\n .title { font-size: 3rem; }\n}\n Font Weight
\n/* Numeric values (100-900) */\n.thin { font-weight: 100; } /* Thin */\n.light { font-weight: 300; } /* Light */\n.regular { font-weight: 400; } /* Normal/Regular */\n.medium { font-weight: 500; } /* Medium */\n.semibold { font-weight: 600; } /* Semi-bold */\n.bold { font-weight: 700; } /* Bold */\n.extrabold { font-weight: 800; } /* Extra-bold */\n.black { font-weight: 900; } /* Black */\n\n/* Keyword values */\n.normal { font-weight: normal; } /* 400 */\n.bold { font-weight: bold; } /* 700 */\n.bolder { font-weight: bolder; } /* Relative to parent */\n.lighter { font-weight: lighter; } /* Relative to parent */\n Line Height
\nLine height (leading) affects readability significantly. Use unitless values for flexibility.
\n\n/* Unitless (recommended) - multiplies font-size */\np {\n font-size: 1rem;\n line-height: 1.6; /* 1.6 \u00d7 16px = 25.6px */\n}\n\n/* Different contexts need different line heights */\n.heading {\n font-size: 3rem;\n line-height: 1.2; /* Tight for headings */\n}\n\n.body-text {\n font-size: 1rem;\n line-height: 1.6; /* Comfortable for reading */\n}\n\n.caption {\n font-size: 0.875rem;\n line-height: 1.4;\n}\n\n/* Fixed line height (less flexible) */\n.fixed {\n line-height: 24px;\n}\n Text Properties
\n/* Text alignment */\n.left { text-align: left; }\n.center { text-align: center; }\n.right { text-align: right; }\n.justify { text-align: justify; }\n\n/* Text decoration */\n.underline { text-decoration: underline; }\n.line-through { text-decoration: line-through; }\n.no-underline { text-decoration: none; }\n\na {\n text-decoration: none;\n text-decoration-color: #3b82f6;\n text-decoration-thickness: 2px;\n text-underline-offset: 4px;\n}\n\n/* Text transform */\n.uppercase { text-transform: uppercase; }\n.lowercase { text-transform: lowercase; }\n.capitalize { text-transform: capitalize; }\n\n/* Font style */\n.italic { font-style: italic; }\n.oblique { font-style: oblique; }\n Letter and Word Spacing
\n/* Letter spacing (tracking) */\n.tight { letter-spacing: -0.05em; }\n.normal { letter-spacing: 0; }\n.wide { letter-spacing: 0.1em; }\n\n.heading {\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n/* Word spacing */\n.spaced {\n word-spacing: 0.2em;\n}\n Text Overflow & White Space
\n/* Ellipsis for overflowing text */\n.truncate {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 200px;\n}\n\n/* Multi-line ellipsis */\n.line-clamp {\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* White space control */\n.nowrap { white-space: nowrap; }\n.pre { white-space: pre; }\n.pre-wrap { white-space: pre-wrap; }\n.pre-line { white-space: pre-line; }\n Variable Fonts
\nVariable fonts contain multiple variations in a single file, reducing file size and providing smooth transitions between weights and styles.
\n\n@font-face {\n font-family: 'Inter';\n src: url('/fonts/Inter-Variable.woff2') format('woff2');\n font-weight: 100 900; /* Range of weights */\n font-display: swap;\n}\n\n/* Use any weight value */\n.custom-weight {\n font-family: 'Inter', sans-serif;\n font-weight: 550; /* Any value between 100-900 */\n}\n\n/* Animate font weight */\n.animated {\n font-weight: 400;\n transition: font-weight 0.3s;\n}\n\n.animated:hover {\n font-weight: 700;\n}\n Creating Readable Typography
\n.prose {\n /* Optimal line length (45-75 characters) */\n max-width: 65ch;\n \n /* Comfortable line height */\n line-height: 1.6;\n \n /* Adequate font size */\n font-size: 1.125rem; /* 18px */\n \n /* Improve readability */\n color: #1a1a1a;\n \n /* Margins between paragraphs */\n p {\n margin-bottom: 1.5em;\n }\n \n /* Heading hierarchy */\n h2 {\n font-size: 2rem;\n font-weight: 700;\n line-height: 1.2;\n margin-top: 2em;\n margin-bottom: 0.75em;\n }\n \n h3 {\n font-size: 1.5rem;\n font-weight: 600;\n line-height: 1.3;\n margin-top: 1.5em;\n margin-bottom: 0.5em;\n }\n}\n Practice Task
\n- \n
- Load a Google Font and apply it to your page with appropriate fallbacks \n
- Create a typography scale using rem units (h1 through h6) \n
- Build a card with truncated text using ellipsis after 2 lines \n
- Implement fluid typography using
clamp()for responsive text sizing \n - Create an article layout with optimal line length (65ch) and readability \n
Key Takeaways
\n- \n
- Font stacks: Always provide fallback fonts for reliability \n
- font-display: swap: Prevent invisible text while fonts load \n
- rem units: Use for font sizes to respect user preferences \n
- Line height: Use unitless values (1.5-1.6 for body text) \n
- Line length: Keep around 65ch for optimal readability \n
- Variable fonts: One file, multiple weights and styles \n
- Web fonts: Use WOFF2 format for best compression \n
What's Next?
\nExplore Icons & Web Fonts for font icons, learn about Pseudo-elements for advanced text effects, or check out Responsive Design for adaptive typography.
\nIcons & Webfonts
Integrate icon systems and custom fonts for rich, expressive interfaces
Icons and web fonts are crucial for modern web design. Choose between icon fonts (Font Awesome, Material Icons) and SVG icons based on your needs. Custom web fonts enhance brand identity and improve typography. Learn to implement both effectively while maintaining performance and accessibility.
Web Font Loading
Load custom fonts efficiently using @font-face with proper font-display strategies.
/* Basic @font-face */
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter-Regular.woff2') format('woff2'),
url('/fonts/Inter-Regular.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
/* Multiple weights */
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter-Bold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
/* Italic variant */
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter-Italic.woff2') format('woff2');
font-weight: 400;
font-style: italic;
font-display: swap;
}
/* Variable font */
@font-face {
font-family: 'Inter Variable';
src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-display: swap;
}
/* Unicode range for subset */
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter-Latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153;
font-display: swap;
}
Font Display Strategies
Control font loading behavior to balance performance and user experience.
/* Auto - browser decides */
@font-face {
font-family: 'MyFont';
src: url('/fonts/font.woff2') format('woff2');
font-display: auto;
}
/* Block - invisible text during load (up to 3s) */
@font-face {
font-family: 'MyFont';
src: url('/fonts/font.woff2') format('woff2');
font-display: block;
}
/* Swap - fallback immediately, swap when loaded (RECOMMENDED) */
@font-face {
font-family: 'MyFont';
src: url('/fonts/font.woff2') format('woff2');
font-display: swap;
}
/* Fallback - short block period, then swap */
@font-face {
font-family: 'MyFont';
src: url('/fonts/font.woff2') format('woff2');
font-display: fallback;
}
/* Optional - no layout shift, font optional */
@font-face {
font-family: 'MyFont';
src: url('/fonts/font.woff2') format('woff2');
font-display: optional;
}
/* Usage with fallback stack */
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont,
'Segoe UI', Helvetica, Arial, sans-serif;
}
Variable Fonts
Use variable fonts for flexible typography with a single font file.
/* Load variable font */
@font-face {
font-family: 'Inter Variable';
src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-stretch: 75% 125%;
font-display: swap;
}
/* Use font-variation-settings */
.heading {
font-family: 'Inter Variable', sans-serif;
font-variation-settings: 'wght' 700, 'wdth' 100;
}
.subheading {
font-family: 'Inter Variable', sans-serif;
font-variation-settings: 'wght' 600, 'wdth' 95;
}
/* Animate variable font */
@keyframes weight-animation {
0%{ 100% { font-variation-settings: 'wght' 400; }
50% { font-variation-settings: 'wght' 700; }
}
.animated-text {
font-family: 'Inter Variable', sans-serif;
animation: weight-animation 2s ease-in-out infinite;
}
/* Optical sizing */
body {
font-family: 'Inter Variable', sans-serif;
font-optical-sizing: auto;
}
Icon Fonts
Integrate popular icon fonts like Font Awesome and Material Icons.
<!-- Load Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
/* Icon styles */
.icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 1.5rem;
height: 1.5rem;
}
/* Icon sizes */
.icon-sm { font-size: 0.875rem; }
.icon-md { font-size: 1rem; }
.icon-lg { font-size: 1.5rem; }
.icon-xl { font-size: 2rem; }
/* Icon with text */
.btn-icon {
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
/* Icon button */
.icon-button {
width: 40px;
height: 40px;
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
background: transparent;
border-radius: 50%;
cursor: pointer;
transition: background-color 200ms;
}
.icon-button:hover {
background-color: rgba(0, 0, 0, 0.05);
}
/* Spinning icon (loader) */
.icon-spin {
animation: fa-spin 1s linear infinite;
}
@keyframes fa-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
<!-- Usage examples -->
<i class="fas fa-home"></i>
<i class="fas fa-heart icon-lg"></i>
<button class="btn-icon">
<i class="fas fa-search"></i>
Search
</button>
<button class="icon-button" aria-label="Settings">
<i class="fas fa-cog" aria-hidden="true"></i>
</button>
SVG Icons
SVG icons offer better scalability, styling flexibility, and accessibility.
<!-- Inline SVG -->
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M3 12h18M12 3v18"/>
</svg>
/* SVG icon styles */
.icon-svg {
width: 1.5rem;
height: 1.5rem;
display: inline-block;
vertical-align: middle;
}
/* Color control */
.icon-svg {
color: currentColor;
fill: currentColor;
}
.icon-svg.icon-stroke {
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
/* Interactive SVG */
.icon-svg {
transition: transform 200ms, color 200ms;
}
.icon-button:hover .icon-svg {
transform: scale(1.1);
color: #3b82f6;
}
<!-- SVG Sprite (recommended for multiple icons) -->
<svg style="display: none;">
<symbol id="icon-home" viewBox="0 0 24 24">
<path d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
</symbol>
<symbol id="icon-search" viewBox="0 0 24 24">
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</symbol>
</svg>
<!-- Usage -->
<svg class="icon-svg">
<use href="#icon-home"></use>
</svg>
Icon Fonts vs SVG
Understand the trade-offs between icon fonts and SVG icons.
/* Icon Font Advantages:
* - Easy to implement
* - CSS styling (color, size, shadow)
* - Good browser support
* - Single HTTP request
*
* Icon Font Disadvantages:
* - Accessibility issues
* - Can't use multi-color
* - Font loading delays
* - Positioning issues
*/
/* SVG Advantages:
* - Perfect scalability
* - Multi-color support
* - Better accessibility
* - Precise control
* - Animation friendly
*
* SVG Disadvantages:
* - More verbose markup
* - Potential multiple requests (without sprites)
*/
/* Recommendation: Use SVG for most cases */
.icon-container {
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
/* Ensure icons are accessible */
.icon[aria-hidden="true"] {
pointer-events: none;
}
/* Icon with accessible label */
.accessible-icon {
position: relative;
}
.accessible-icon .sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
Google Fonts Integration
Load fonts from Google Fonts CDN with optimization techniques.
<!-- Optimized Google Fonts loading -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Multiple fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Merriweather:wght@400;700&display=swap" rel="stylesheet">
/* Use loaded fonts */
:root {
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--font-serif: 'Merriweather', Georgia, serif;
}
body {
font-family: var(--font-sans);
}
h1{ h2{ h3 {
font-family: var(--font-serif);
}
/* Self-hosted alternative (better performance) */
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-subset.woff2') format('woff2');
font-display: swap;
unicode-range: U+0000-00FF;
}
Icon Styling Techniques
Advanced techniques for styling and animating icons.
/* Gradient icon (SVG only) */
.icon-gradient {
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Icon with badge */
.icon-badge {
position: relative;
display: inline-block;
}
.icon-badge::after {
content: attr(data-count);
position: absolute;
top: -8px;
right: -8px;
background: #ef4444;
color: white;
border-radius: 10px;
padding: 2px 6px;
font-size: 0.75rem;
font-weight: bold;
min-width: 20px;
text-align: center;
}
/* Animated icon hover */
.icon-animated {
transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
.icon-animated:hover {
transform: rotate(15deg) scale(1.1);
}
/* Pulse effect */
@keyframes pulse {
0%{ 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(0.95); }
}
.icon-pulse {
animation: pulse 2s ease-in-out infinite;
}
/* Stack icons */
.icon-stack {
position: relative;
display: inline-block;
width: 2em;
height: 2em;
}
.icon-stack .icon-background {
position: absolute;
left: 0;
top: 0;
font-size: 2em;
}
.icon-stack .icon-foreground {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 1em;
}
Accessibility Considerations
Ensure icons are accessible to all users.
<!-- Decorative icon (hide from screen readers) -->
<button>
<i class="fas fa-save" aria-hidden="true"></i>
Save Document
</button>
<!-- Standalone icon (needs label) -->
<button aria-label="Close dialog">
<i class="fas fa-times" aria-hidden="true"></i>
</button>
<!-- SVG with title -->
<svg role="img" aria-labelledby="icon-title">
<title id="icon-title">Settings</title>
<use href="#icon-settings"></use>
</svg>
<!-- Visually hidden text -->
<button>
<i class="fas fa-download" aria-hidden="true"></i>
<span class="sr-only">Download File</span>
</button>
/* Screen reader only class */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Focus visible for icon buttons */
.icon-button:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* Minimum touch target size */
.icon-button {
min-width: 44px;
min-height: 44px;
}
Practice Exercises
- Custom Font: Load a custom Google Font with preconnect optimization and create a complete type system.
- Icon Library: Create a reusable SVG sprite system with 10 common icons (home, search, user, settings, etc.).
- Accessible Icons: Build a navigation menu with accessible icon buttons including proper ARIA labels and focus states.
- Animated Icons: Design icon hover effects including rotation, scaling, and color transitions.
- Variable Font: Implement a heading system using a variable font with animated weight changes.
- Use font-display: swap for faster text rendering
- Prefer SVG icons for scalability and accessibility
- Always provide text alternatives for standalone icons
- Use preconnect for external font CDNs
- Variable fonts reduce file size and offer flexibility
- Create icon sprites to minimize HTTP requests
What's Next?
Continue to Accessibility to learn more about inclusive design, or explore Performance & Architecture for optimization strategies.
Pseudo-classes & Pseudo-elements
Master interactive states and decorative content with pseudo-selectors
Pseudo-classes select elements based on their state or position, while pseudo-elements style specific parts of elements or add decorative content. Understanding these selectors is crucial for creating interactive, accessible, and visually rich interfaces without extra markup.
Interactive Pseudo-classes
Interactive pseudo-classes respond to user actions and are essential for feedback and accessibility.
/* Hover state - mouse over */
.button:hover {
background-color: #2563eb;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.4);
}
/* Focus state - keyboard navigation */
.button:focus {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* Focus-visible - only keyboard focus */
.button:focus-visible {
outline: 3px solid #3b82f6;
outline-offset: 3px;
}
.button:focus:not(:focus-visible) {
outline: none; /* Remove focus ring for mouse clicks */
}
/* Active state - being clicked */
.button:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(37, 99, 235, 0.3);
}
/* Disabled state */
.button:disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
/* Link states */
a:link { color: #3b82f6; }
a:visited { color: #7c3aed; }
a:hover { color: #2563eb; text-decoration: underline; }
a:active { color: #1e40af; }
Structural Pseudo-classes
Select elements based on their position in the document tree.
/* First and last child */
.list-item:first-child {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.list-item:last-child {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom: none;
}
/* Nth-child patterns */
.grid-item:nth-child(odd) {
background-color: #f9fafb;
}
.grid-item:nth-child(even) {
background-color: #ffffff;
}
/* Every third item */
.item:nth-child(3n) {
margin-right: 0;
}
/* Starting from specific position */
.item:nth-child(n+4) {
display: none; /* Hide items after 3rd */
}
/* First 3 items */
.item:nth-child(-n+3) {
font-weight: bold;
}
/* Only child */
.card:only-child {
width: 100%;
}
/* Nth of type */
p:nth-of-type(1) {
font-size: 1.25rem;
font-weight: 600;
}
/* Last of type */
.section p:last-of-type {
margin-bottom: 0;
}
Form and Input Pseudo-classes
Style form elements based on their state and validation status.
/* Checked state for checkboxes and radios */
input[type="checkbox"]:checked {
background-color: #3b82f6;
border-color: #3b82f6;
}
input[type="checkbox"]:checked::after {
content: "✓";
color: white;
display: block;
}
/* Indeterminate state */
input[type="checkbox"]:indeterminate {
background-color: #64748b;
}
/* Required and optional */
input:required {
border-left: 3px solid #ef4444;
}
input:optional {
border-left: 3px solid #94a3b8;
}
/* Valid and invalid */
input:valid {
border-color: #22c55e;
}
input:invalid {
border-color: #ef4444;
}
/* Only show validation after interaction */
input:not(:placeholder-shown):invalid {
border-color: #ef4444;
background-color: #fef2f2;
}
/* In-range and out-of-range */
input[type="number"]:in-range {
border-color: #22c55e;
}
input[type="number"]:out-of-range {
border-color: #f59e0b;
}
/* Read-only and read-write */
input:read-only {
background-color: #f3f4f6;
cursor: not-allowed;
}
/* Placeholder shown */
input:placeholder-shown {
font-style: italic;
}
::before and ::after Pseudo-elements
Add decorative content before or after elements without modifying HTML.
/* Basic content insertion */
.tag::before {
content: "#";
color: #94a3b8;
margin-right: 0.25rem;
}
.external-link::after {
content: " ↗";
font-size: 0.875em;
vertical-align: super;
}
/* Icon pseudo-elements */
.success::before {
content: "✓";
display: inline-flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
background-color: #22c55e;
color: white;
border-radius: 50%;
margin-right: 0.5rem;
font-size: 0.75rem;
}
/* Decorative elements */
.quote {
position: relative;
padding: 2rem;
}
.quote::before {
content: """;
position: absolute;
top: 0;
left: 0;
font-size: 4rem;
color: #e5e7eb;
line-height: 1;
}
/* Clearfix */
.clearfix::after {
content: "";
display: table;
clear: both;
}
/* Overlay effect */
.card::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.7));
opacity: 0;
transition: opacity 300ms;
}
.card:hover::after {
opacity: 1;
}
Text Pseudo-elements
Style specific parts of text content like first letter, first line, or selected text.
/* Drop cap effect */
.article p:first-of-type::first-letter {
float: left;
font-size: 4rem;
line-height: 0.8;
margin: 0.1em 0.1em 0 0;
font-weight: bold;
color: #3b82f6;
}
/* First line styling */
.intro::first-line {
font-weight: 600;
font-size: 1.125rem;
color: #1f2937;
}
/* Selection styling */
::selection {
background-color: #dbeafe;
color: #1e40af;
}
/* Firefox specific */
::-moz-selection {
background-color: #dbeafe;
color: #1e40af;
}
/* Placeholder styling */
::placeholder {
color: #9ca3af;
opacity: 1;
font-style: italic;
}
input:focus::placeholder {
opacity: 0.5;
}
Relational Pseudo-classes
Select elements based on their relationship to other elements.
/* Not selector */
.button:not(.button--disabled):hover {
background-color: #2563eb;
}
/* Multiple exclusions */
li:not(:first-child):not(:last-child) {
border-block: 1px solid #e5e7eb;
}
/* Is selector (matches any) */
:is(h1, h2, h3):hover {
color: #3b82f6;
}
/* Where selector (zero specificity) */
:where(.card, .panel) {
border-radius: 8px;
padding: 1rem;
}
/* Has selector (parent selector) */
.card:has(img) {
display: grid;
grid-template-rows: auto 1fr;
}
.form:has(input:invalid) {
border-color: #ef4444;
}
/* Empty selector */
.message:empty {
display: none;
}
.list:empty::before {
content: "No items to display";
color: #9ca3af;
font-style: italic;
}
Advanced Pseudo-element Techniques
Create complex visual effects using pseudo-elements creatively.
/* Animated underline */
.nav-link {
position: relative;
}
.nav-link::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background-color: #3b82f6;
transition: width 300ms ease;
}
.nav-link:hover::after {
width: 100%;
}
/* Badge counter */
.notification {
position: relative;
}
.notification::after {
content: attr(data-count);
position: absolute;
top: -8px;
right: -8px;
background-color: #ef4444;
color: white;
border-radius: 10px;
padding: 2px 6px;
font-size: 0.75rem;
font-weight: bold;
min-width: 20px;
text-align: center;
}
/* Ribbon effect */
.featured {
position: relative;
overflow: hidden;
}
.featured::before {
content: "New";
position: absolute;
top: 10px;
right: -30px;
background-color: #f59e0b;
color: white;
padding: 5px 40px;
transform: rotate(45deg);
font-size: 0.875rem;
font-weight: bold;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
/* Loading skeleton */
.skeleton {
position: relative;
overflow: hidden;
background-color: #e5e7eb;
}
.skeleton::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.5),
transparent
);
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
Accessibility Considerations
Use pseudo-classes and pseudo-elements while maintaining accessibility.
/* Always show focus for keyboard navigation */
*:focus-visible {
outline: 3px solid #3b82f6;
outline-offset: 2px;
}
/* Remove focus for mouse users */
*:focus:not(:focus-visible) {
outline: none;
}
/* Ensure decorative content is hidden from screen readers */
.icon::before {
content: "";
/* Never put meaningful content in pseudo-elements */
/* Use aria-label on parent instead */
}
/* Visible focus indicators */
a:focus-visible{
button:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
/* High contrast mode support */
@media(prefers-contrast: high) {
.button:focus-visible {
outline: 3px solid;
outline-offset: 3px;
}
}
/* Reduced motion support */
@media(prefers-reduced-motion: reduce) {
*::before{
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Practice Exercises
- Interactive Button: Create a button with hover, focus, and active states using appropriate pseudo-classes.
- Styled List: Build a list where every third item has a different background using nth-child.
- Form Validation: Style a form input that shows validation state using :valid, :invalid, and pseudo-elements for icons.
- Animated Underline: Create a navigation link with an animated underline effect using ::after.
- Card with Badge: Design a card component with a ribbon badge using ::before and appropriate positioning.
- Pseudo-classes select based on state (:hover, :focus) or structure (:nth-child)
- Pseudo-elements create virtual elements (::before, ::after)
- Use :focus-visible for keyboard-only focus indicators
- ::before and ::after require content property, even if empty
- Text pseudo-elements (::first-letter, ::first-line) style text portions
- Modern selectors like :has() and :is() simplify complex selection
What's Next?
Explore Colors & Typography to enhance your designs with color theory and typography principles, or check out Transforms & Effects for dynamic visual effects.
Forms & Input Styling
Create beautiful, accessible, and user-friendly form interfaces
Forms are critical user interaction points. Well-styled forms with clear visual feedback, proper spacing, and accessible markup significantly improve user experience. Learn to style inputs, selects, checkboxes, radios, and create complete form systems with validation states.
Text Input Styling
Create consistent, accessible text inputs with proper focus states and sizing.
/* Base input styles */
.form-control {
width: 100%;
padding: 0.75rem 1rem;
font-size: 1rem;
line-height: 1.5;
color: #1f2937;
background-color: #ffffff;
border: 1px solid #d1d5db;
border-radius: 8px;
transition: border-color 0.2s, box-shadow 0.2s;
}
.form-control:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.form-control:disabled {
background-color: #f3f4f6;
color: #9ca3af;
cursor: not-allowed;
opacity: 0.6;
}
.form-control::placeholder {
color: #9ca3af;
opacity: 1;
}
/* Input sizes */
.form-control-sm {
padding: 0.5rem 0.75rem;
font-size: 0.875rem;
}
.form-control-lg {
padding: 1rem 1.25rem;
font-size: 1.125rem;
}
/* Read-only state */
.form-control:read-only {
background-color: #f9fafb;
border-color: #e5e7eb;
}
<div class="form-group">
<label for="email" class="form-label">Email</label>
<input type="email" id="email" class="form-control" placeholder="you@example.com">
</div>
Label and Form Group
Structure forms with proper label associations and grouping.
/* Form group spacing */
.form-group {
margin-bottom: 1.5rem;
}
.form-group:last-child {
margin-bottom: 0;
}
/* Label styles */
.form-label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
font-size: 0.875rem;
color: #374151;
}
.form-label.required::after {
content: " *";
color: #ef4444;
}
/* Help text */
.form-text {
display: block;
margin-top: 0.5rem;
font-size: 0.875rem;
color: #6b7280;
}
/* Error message */
.form-error {
display: block;
margin-top: 0.5rem;
font-size: 0.875rem;
color: #ef4444;
}
/* Floating labels */
.form-floating {
position: relative;
}
.form-floating .form-control {
padding: 1.625rem 1rem 0.625rem;
}
.form-floating label {
position: absolute;
top: 0;
left: 0;
padding: 1rem;
pointer-events: none;
transform-origin: 0 0;
transition: opacity 0.2s, transform 0.2s;
color: #9ca3af;
}
.form-floating .form-control:focus ~ label{
.form-floating .form-control:not(:placeholder-shown) ~ label {
opacity: 0.65;
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
}
Validation States
Provide clear visual feedback for form validation.
/* Valid state */
.form-control.is-valid {
border-color: #22c55e;
padding-right: calc(1.5em + 0.75rem);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2322c55e' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right calc(0.375em + 0.1875rem) center;
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.form-control.is-valid:focus {
border-color: #22c55e;
box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.1);
}
.valid-feedback {
display: none;
margin-top: 0.5rem;
font-size: 0.875rem;
color: #22c55e;
}
.form-control.is-valid ~ .valid-feedback {
display: block;
}
/* Invalid state */
.form-control.is-invalid {
border-color: #ef4444;
padding-right: calc(1.5em + 0.75rem);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ef4444'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ef4444' stroke='none'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right calc(0.375em + 0.1875rem) center;
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.form-control.is-invalid:focus {
border-color: #ef4444;
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
}
.invalid-feedback {
display: none;
margin-top: 0.5rem;
font-size: 0.875rem;
color: #ef4444;
}
.form-control.is-invalid ~ .invalid-feedback {
display: block;
}
/* Warning state */
.form-control.is-warning {
border-color: #f59e0b;
}
.form-control.is-warning:focus {
border-color: #f59e0b;
box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1);
}
Select Dropdowns
Style select elements with custom arrows and states.
/* Custom select */
.form-select {
width: 100%;
padding: 0.75rem 2.5rem 0.75rem 1rem;
font-size: 1rem;
line-height: 1.5;
color: #1f2937;
background-color: #ffffff;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23374151' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right 0.75rem center;
background-size: 16px 12px;
border: 1px solid #d1d5db;
border-radius: 8px;
appearance: none;
transition: border-color 0.2s, box-shadow 0.2s;
}
.form-select:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.form-select:disabled {
background-color: #f3f4f6;
color: #9ca3af;
cursor: not-allowed;
}
/* Multiple select */
.form-select[multiple] {
padding: 0.5rem;
background-image: none;
height: auto;
}
.form-select[multiple] option {
padding: 0.5rem;
border-radius: 4px;
}
.form-select[multiple] option:checked {
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
color: white;
}
Checkboxes and Radio Buttons
Create custom, accessible checkbox and radio button styles.
/* Custom checkbox */
.form-check {
display: flex;
align-items: center;
margin-bottom: 0.75rem;
}
.form-check-input {
width: 1.25rem;
height: 1.25rem;
margin-right: 0.5rem;
border: 2px solid #d1d5db;
border-radius: 4px;
background-color: #ffffff;
appearance: none;
cursor: pointer;
transition: all 0.2s;
flex-shrink: 0;
}
.form-check-input:checked {
background-color: #3b82f6;
border-color: #3b82f6;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: center;
background-size: 100% 100%;
}
.form-check-input:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.form-check-input:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.form-check-label {
cursor: pointer;
user-select: none;
}
/* Radio button */
.form-check-input[type="radio"] {
border-radius: 50%;
}
.form-check-input[type="radio"]:checked {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e");
}
/* Switch/Toggle */
.form-switch {
display: flex;
align-items: center;
}
.form-switch .form-check-input {
width: 2.5rem;
height: 1.25rem;
border-radius: 9999px;
background-color: #d1d5db;
position: relative;
transition: background-color 0.2s;
}
.form-switch .form-check-input::after {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 1rem;
height: 1rem;
background: white;
border-radius: 50%;
transition: transform 0.2s;
}
.form-switch .form-check-input:checked {
background-color: #3b82f6;
background-image: none;
}
.form-switch .form-check-input:checked::after {
transform: translateX(1.25rem);
}
Textarea Styling
Style text areas with proper sizing and resize controls.
/* Textarea base styles */
.form-textarea {
width: 100%;
min-height: 100px;
padding: 0.75rem 1rem;
font-size: 1rem;
font-family: inherit;
line-height: 1.5;
color: #1f2937;
background-color: #ffffff;
border: 1px solid #d1d5db;
border-radius: 8px;
resize: vertical;
transition: border-color 0.2s, box-shadow 0.2s;
}
.form-textarea:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
/* Fixed size textarea */
.form-textarea-fixed {
resize: none;
}
/* Auto-growing textarea */
.form-textarea-auto {
min-height: 60px;
max-height: 300px;
overflow-y: auto;
}
/* Character counter */
.textarea-wrapper {
position: relative;
}
.character-count {
position: absolute;
bottom: 0.5rem;
right: 0.75rem;
font-size: 0.75rem;
color: #9ca3af;
pointer-events: none;
}
File Input Styling
Create custom file upload interfaces.
/* Hide default file input */
.form-file {
position: relative;
}
.form-file-input {
position: absolute;
opacity: 0;
width: 0.1px;
height: 0.1px;
z-index: -1;
}
/* Custom file input label */
.form-file-label {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
font-size: 1rem;
font-weight: 500;
color: #3b82f6;
background-color: white;
border: 2px solid #3b82f6;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
}
.form-file-label:hover {
background-color: #3b82f6;
color: white;
}
.form-file-input:focus + .form-file-label {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* Drag and drop area */
.file-drop-zone {
border: 2px dashed #d1d5db;
border-radius: 12px;
padding: 3rem 2rem;
text-align: center;
transition: all 0.2s;
cursor: pointer;
}
.file-drop-zone:hover{
.file-drop-zone.drag-over {
border-color: #3b82f6;
background-color: rgba(59, 130, 246, 0.05);
}
.file-drop-zone-icon {
font-size: 3rem;
color: #9ca3af;
margin-bottom: 1rem;
}
.file-drop-zone-text {
color: #6b7280;
}
Search Input
Style search inputs with icons and clear buttons.
/* Search input wrapper */
.search-wrapper {
position: relative;
}
.search-input {
width: 100%;
padding: 0.75rem 3rem 0.75rem 2.5rem;
border: 1px solid #d1d5db;
border-radius: 9999px;
font-size: 1rem;
transition: all 0.2s;
}
.search-input:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
/* Search icon */
.search-icon {
position: absolute;
left: 1rem;
top: 50%;
transform: translateY(-50%);
color: #9ca3af;
pointer-events: none;
}
/* Clear button */
.search-clear {
position: absolute;
right: 0.75rem;
top: 50%;
transform: translateY(-50%);
width: 1.5rem;
height: 1.5rem;
padding: 0;
border: none;
background: transparent;
color: #9ca3af;
border-radius: 50%;
cursor: pointer;
display: none;
transition: all 0.2s;
}
.search-input:not(:placeholder-shown) ~ .search-clear {
display: flex;
align-items: center;
justify-content: center;
}
.search-clear:hover {
background-color: #f3f4f6;
color: #374151;
}
Input Groups
Combine inputs with buttons, icons, or text addons.
/* Input group */
.input-group {
display: flex;
width: 100%;
}
.input-group .form-control {
flex: 1;
border-radius: 0;
}
.input-group .form-control:first-child {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.input-group .form-control:last-child {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
/* Input group addon */
.input-group-text {
display: flex;
align-items: center;
padding: 0.75rem 1rem;
font-size: 1rem;
color: #6b7280;
background-color: #f9fafb;
border: 1px solid #d1d5db;
white-space: nowrap;
}
.input-group > *:not(:first-child) {
border-left: 0;
}
/* Input group button */
.input-group .btn {
border-radius: 0;
}
.input-group .btn:first-child {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.input-group .btn:last-child {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
Form Layout Patterns
Common form layout structures and patterns.
/* Inline form */
.form-inline {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 1rem;
}
.form-inline .form-group {
margin-bottom: 0;
}
/* Grid form layout */
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
}
/* Two-column form */
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
@media(max-width: 768px) {
.form-row {
grid-template-columns: 1fr;
}
}
/* Form sections */
.form-section {
margin-bottom: 2rem;
padding: 1.5rem;
background: #f9fafb;
border-radius: 12px;
}
.form-section-title {
margin-bottom: 1rem;
font-size: 1.125rem;
font-weight: 600;
color: #1f2937;
}
/* Form actions */
.form-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid #e5e7eb;
}
Practice Exercises
- Contact Form: Create a complete contact form with name, email, subject, message, and validation states.
- Custom Checkboxes: Design custom checkbox and radio button styles with smooth animations.
- File Upload: Build a drag-and-drop file upload interface with preview and progress indication.
- Search Bar: Implement a search input with autocomplete dropdown and keyboard navigation.
- Multi-step Form: Create a multi-step form with progress indicator and validation at each step.
- Always associate labels with inputs using for and id attributes
- Provide clear focus indicators for keyboard navigation
- Show validation feedback after user interaction, not on page load
- Use appropriate input types (email, tel, url) for better mobile UX
- Maintain consistent spacing and sizing across all form elements
- Hide native styling with appearance: none when customizing
What's Next?
Continue to Accessibility for comprehensive form accessibility guidelines, or explore Pseudo-classes for advanced input state styling.
CSS Transitions & Animations
Create smooth, engaging motion effects with CSS
CSS transitions and animations bring your designs to life. Transitions smoothly change property values over time, while animations provide more complex, keyframe-based motion. Both are GPU-accelerated and performant when used correctly.
CSS Transitions
Transitions animate changes between CSS property values. They're perfect for hover effects, focus states, and simple animations.
.button {
background-color: #3b82f6;
color: white;
padding: 12px 24px;
border: none;
border-radius: 8px;
/* Transition all properties over 0.3s */
transition: all 0.3s ease;
}
.button:hover {
background-color: #2563eb;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
}
Transition Properties
/* Shorthand: property duration timing-function delay */
.element {
transition: background-color 0.3s ease 0s;
}
/* Individual properties */
.element {
transition-property: background-color, transform;
transition-duration: 0.3s;
transition-timing-function: ease-in-out;
transition-delay: 0.1s;
}
/* Multiple transitions */
.card {
transition:
transform 0.3s ease,
box-shadow 0.3s ease,
background-color 0.2s ease;
}
.card:hover {
transform: scale(1.05);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
background-color: #f9fafb;
}
Timing Functions
Timing functions control the acceleration curve of transitions and animations.
/* Linear - constant speed */
.linear { transition: all 0.3s linear; }
/* Ease (default) - slow start, fast middle, slow end */
.ease { transition: all 0.3s ease; }
/* Ease-in - slow start, then accelerate */
.ease-in { transition: all 0.3s ease-in; }
/* Ease-out - fast start, then decelerate */
.ease-out { transition: all 0.3s ease-out; }
/* Ease-in-out - slow start and end */
.ease-in-out { transition: all 0.3s ease-in-out; }
/* Custom cubic-bezier */
.custom {
transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
/* Steps (for frame-by-frame animation) */
.steps {
transition: all 1s steps(4, end);
}
CSS Animations with @keyframes
Animations provide more control than transitions, allowing you to define multiple intermediate states.
/* Define keyframes */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Apply animation */
.fade-in {
animation: fadeIn 0.6s ease-out;
}
/* Multiple steps */
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
}
.bouncing {
animation: bounce 1s ease-in-out infinite;
}
Animation Properties
/* Shorthand: name duration timing-function delay iteration-count direction fill-mode */
.element {
animation: slideIn 0.5s ease-out 0.2s 1 normal forwards;
}
/* Individual properties */
.detailed {
animation-name: pulse;
animation-duration: 2s;
animation-timing-function: ease-in-out;
animation-delay: 0.5s;
animation-iteration-count: infinite; /* or number */
animation-direction: alternate; /* normal, reverse, alternate, alternate-reverse */
animation-fill-mode: both; /* none, forwards, backwards, both */
animation-play-state: running; /* running or paused */
}
/* Pause animation on hover */
.pausable {
animation: spin 2s linear infinite;
}
.pausable:hover {
animation-play-state: paused;
}
Common Animation Patterns
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes slideInRight {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.slide-in {
animation: slideInRight 0.6s ease-out;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.05);
opacity: 0.8;
}
}
.pulse {
animation: pulse 2s ease-in-out infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: spin 1s linear infinite;
}
/* Loading spinner */
.loading {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3b82f6;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }
20%, 40%, 60%, 80% { transform: translateX(10px); }
}
.error-shake {
animation: shake 0.5s ease-in-out;
}
Performance Best Practices
/* Only animate these properties for best performance: */
/* Transform (GPU-accelerated) */
.optimized {
transition: transform 0.3s ease;
}
.optimized:hover {
transform: translateY(-5px) scale(1.02);
}
/* Opacity (GPU-accelerated) */
.fade {
transition: opacity 0.3s ease;
}
/* AVOID animating these (causes reflow/repaint): */
.slow {
/* ❌ Don't animate: width, height, top, left, margin, padding */
transition: width 0.3s; /* Causes layout recalculation */
}
/* Use transform instead */
.fast {
/* ✅ Do this instead: */
transition: transform 0.3s;
}
.fast:hover {
transform: scale(1.2); /* Same visual effect, better performance */
}
Respecting User Preferences
/* Respect prefers-reduced-motion */
@media(prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Or selectively disable specific animations */
.animated {
animation: bounce 1s infinite;
}
@media(prefers-reduced-motion: reduce) {
.animated {
animation: none;
}
}
Advanced Animation Techniques
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.list-item {
animation: fadeInUp 0.6s ease-out backwards;
}
/* Stagger with delay */
.list-item:nth-child(1) { animation-delay: 0.1s; }
.list-item:nth-child(2) { animation-delay: 0.2s; }
.list-item:nth-child(3) { animation-delay: 0.3s; }
.list-item:nth-child(4) { animation-delay: 0.4s; }
.list-item:nth-child(5) { animation-delay: 0.5s; }
Practice Task
- Create a button with hover transition that changes background, lifts up, and adds shadow
- Build a loading spinner using @keyframes rotation
- Implement a fade-in animation for content that appears on page load
- Create a card hover effect with multiple property transitions at different speeds
- Build a navigation menu where items slide in sequentially with staggered delays
Key Takeaways
- Transitions: Simple property changes between states (hover, focus)
- Animations: Complex, multi-step motion with @keyframes
- Performance: Only animate transform and opacity for smoothness
- Timing functions: Control acceleration with ease, linear, or cubic-bezier
- Accessibility: Respect prefers-reduced-motion for users sensitive to motion
- GPU acceleration: Transform and opacity use hardware acceleration
- fill-mode: Use forwards to maintain final state after animation
What's Next?
Explore CSS Transforms for more advanced transformations, learn about Pseudo-classes for animation triggers, or check out Performance for optimization techniques.
CSS Transforms & Effects
Create stunning visual transformations and animations with CSS transform properties
CSS transforms allow you to manipulate elements in 2D and 3D space without affecting the document flow. Transforms are GPU-accelerated, making them ideal for animations and interactive effects. Master these properties to create smooth, performant visual experiences.
Transform Functions Overview
CSS provides several transform functions that can be combined to create complex effects. These functions modify the coordinate space of the CSS visual formatting model.
/* Translation - Move elements */
.translate {
transform: translate(50px, 100px);
transform: translateX(50px);
transform: translateY(100px);
}
/* Rotation - Rotate elements */
.rotate {
transform: rotate(45deg);
transform: rotateX(45deg);
transform: rotateY(45deg);
transform: rotateZ(45deg);
}
/* Scale - Resize elements */
.scale {
transform: scale(1.5);
transform: scale(1.2, 0.8);
transform: scaleX(1.5);
transform: scaleY(0.8);
}
/* Skew - Distort elements */
.skew {
transform: skew(10deg, 5deg);
transform: skewX(10deg);
transform: skewY(5deg);
}
Combining Multiple Transforms
Multiple transform functions can be chained together. The order matters - transforms are applied from right to left in the declaration.
.card {
transition: transform 300ms ease-out;
}
.card:hover {
/* Applied right to left: scale → rotate → translate */
transform: translateY(-10px) rotate(2deg) scale(1.05);
}
/* Interactive button effect */
.button {
transform: perspective(1000px) rotateY(0deg);
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1);
}
.button:hover {
transform: perspective(1000px) rotateY(-5deg) scale(1.02);
}
.button:active {
transform: perspective(1000px) rotateY(-5deg) scale(0.98);
}
Transform Origin
The transform-origin property sets the point around which transformations occur. By default, it's the center (50% 50%).
/* Rotate from top-left corner */
.rotate-topleft {
transform-origin: top left;
transform: rotate(15deg);
}
/* Scale from bottom center */
.scale-bottom {
transform-origin: bottom center;
transform: scale(1.5);
}
/* Door swing effect */
.door {
transform-origin: left center;
transition: transform 400ms ease;
}
.door:hover {
transform: perspective(1200px) rotateY(-45deg);
}
/* Custom origin with coordinates */
.custom-origin {
transform-origin: 80px 40px;
transform: rotate(30deg);
}
3D Transforms
3D transforms add depth to your designs. Use perspective to define the distance between the viewer and the z-plane.
/* Perspective container */
.scene {
perspective: 1000px;
perspective-origin: center center;
}
/* 3D card flip */
.card-container {
width: 300px;
height: 200px;
position: relative;
transform-style: preserve-3d;
transition: transform 600ms;
}
.card-container:hover {
transform: rotateY(180deg);
}
.card-front{
.card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
}
.card-back {
transform: rotateY(180deg);
}
/* 3D cube rotation */
.cube {
transform-style: preserve-3d;
animation: rotateCube 6s infinite linear;
}
@keyframes rotateCube {
0% { transform: rotateX(0deg) rotateY(0deg); }
50% { transform: rotateX(180deg) rotateY(180deg); }
100% { transform: rotateX(360deg) rotateY(360deg); }
}
Perspective and Depth
Perspective creates the illusion of depth by making elements appear closer or farther away.
/* As a property on parent */
.perspective-container {
perspective: 800px;
perspective-origin: 50% 50%;
}
/* As a transform function */
.element {
transform: perspective(800px) rotateX(15deg);
}
/* Layered depth effect */
.layer-1 {
transform: translateZ(100px);
}
.layer-2 {
transform: translateZ(50px);
}
.layer-3 {
transform: translateZ(0px);
}
/* Parallax hover effect */
.parallax-card {
transform-style: preserve-3d;
transition: transform 200ms ease-out;
}
.parallax-card:hover {
transform: rotateX(5deg) rotateY(10deg);
}
.parallax-card .content {
transform: translateZ(50px);
}
.parallax-card .background {
transform: translateZ(-50px) scale(1.1);
}
Backface Visibility
Control whether the back face of an element is visible when rotated away from the viewer.
/* Hide backface (useful for card flips) */
.flippable {
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
/* Complete flip card example */
.flip-container {
perspective: 1000px;
}
.flipper {
position: relative;
transform-style: preserve-3d;
transition: transform 0.6s;
}
.flip-container:hover .flipper {
transform: rotateY(180deg);
}
.front{
.back {
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
.back {
transform: rotateY(180deg);
}
Transform Performance Tips
Optimize transforms for smooth animations by leveraging GPU acceleration and avoiding layout triggers.
/* Force GPU acceleration */
.accelerated {
transform: translateZ(0);
will-change: transform;
}
/* Smooth animation with proper easing */
.smooth-animation {
transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* Use transform instead of top/left for positioning */
.efficient-move {
/* Bad - triggers layout */
/* position: relative; top: 10px; left: 10px; */
/* Good - GPU accelerated */
transform: translate(10px, 10px);
}
/* Remove will-change after animation */
.animated {
will-change: transform;
transition: transform 400ms;
}
.animated.complete {
will-change: auto;
}
Practical Transform Examples
Real-world examples demonstrating common transform use cases.
/* Hover card effect */
.product-card {
transition: transform 250ms ease, box-shadow 250ms ease;
}
.product-card:hover {
transform: translateY(-8px) scale(1.02);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
}
/* Loading spinner */
.spinner {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* Pulse effect */
.pulse {
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%{ transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
/* Shake animation */
@keyframes shake {
0%{ 100% { transform: translateX(0); }
10%{ 30%{ 50%{ 70%{ 90% { transform: translateX(-10px); }
20%{ 40%{ 60%{ 80% { transform: translateX(10px); }
}
.error-shake {
animation: shake 0.5s;
}
Practice Exercises
- Card Flip: Create a business card that flips on hover to reveal contact information on the back.
- 3D Cube: Build a rotating 3D cube with different content on each face.
- Parallax Effect: Implement a multi-layer parallax effect using translateZ and perspective.
- Loading Animation: Design a creative loading spinner using transform and animations.
- Interactive Gallery: Create an image gallery where thumbnails scale and rotate on hover with smooth transitions.
- Transforms are GPU-accelerated and don't trigger layout reflows
- Use transform-origin to control the transformation pivot point
- 3D transforms require perspective and preserve-3d
- Combine multiple transforms for complex effects
- Use will-change sparingly to hint GPU acceleration
- Backface-visibility is essential for flip animations
What's Next?
Continue to CSS Variables & Custom Properties to learn how to create dynamic, theme-able designs, or explore CSS Functions for advanced responsive calculations.
CSS Variables & Custom Properties
Create dynamic, maintainable stylesheets with CSS custom properties
CSS Custom Properties (CSS Variables) allow you to store values that can be reused throughout your stylesheet. They cascade and inherit like regular CSS properties, making them perfect for theming, responsive design, and maintaining consistency across large projects.
Basic Syntax and Usage
Custom properties are declared with a double-dash prefix (--) and accessed using the var() function.
/* Declare variables in :root for global scope */
:root {
--primary-color: #3b82f6;
--secondary-color: #8b5cf6;
--text-color: #1f2937;
--spacing-unit: 8px;
--border-radius: 8px;
}
/* Use variables with var() function */
.button {
background-color: var(--primary-color);
color: white;
padding: calc(var(--spacing-unit) * 2);
border-radius: var(--border-radius);
}
.card {
border: 2px solid var(--primary-color);
padding: calc(var(--spacing-unit) * 3);
border-radius: calc(var(--border-radius) * 2);
}
Fallback Values
The var() function accepts a second parameter as a fallback value if the custom property is not defined.
.element {
/* Fallback to blue if --theme-color is not defined */
color: var(--theme-color, #3b82f6);
/* Multiple fallbacks */
font-family: var(--custom-font, var(--system-font, sans-serif));
/* Fallback with calculation */
padding: var(--custom-padding, calc(1rem + 2px));
}
/* Nested fallbacks for progressive enhancement */
.progressive {
background: var(--gradient,
var(--primary-color,
var(--fallback-color, #6366f1)
)
);
}
Scope and Inheritance
Custom properties inherit from parent elements and can be scoped to specific selectors.
/* Global variables */
:root {
--base-color: #3b82f6;
--spacing: 16px;
}
/* Component-scoped variables */
.sidebar {
--base-color: #8b5cf6; /* Override for this component */
--spacing: 12px;
background: var(--base-color);
padding: var(--spacing);
}
.sidebar .nested-element {
/* Inherits --base-color: #8b5cf6 from .sidebar */
border-left: 3px solid var(--base-color);
}
/* Media query scoping */
@media(min-width: 768px) {
:root {
--spacing: 24px;
--font-size-base: 18px;
}
}
Theming with Custom Properties
Create complete theme systems that can be switched dynamically without reloading styles.
/* Default (light) theme */
:root {
--bg-primary: #ffffff;
--bg-secondary: #f9fafb;
--text-primary: #111827;
--text-secondary: #6b7280;
--border-color: #e5e7eb;
--shadow: rgba(0, 0, 0, 0.1);
}
/* Dark theme */
[data-theme="dark"] {
--bg-primary: #1f2937;
--bg-secondary: #111827;
--text-primary: #f9fafb;
--text-secondary: #9ca3af;
--border-color: #374151;
--shadow: rgba(0, 0, 0, 0.5);
}
/* High contrast theme */
[data-theme="high-contrast"] {
--bg-primary: #000000;
--bg-secondary: #1a1a1a;
--text-primary: #ffffff;
--text-secondary: #cccccc;
--border-color: #ffffff;
--shadow: rgba(255, 255, 255, 0.3);
}
/* Apply theme variables */
body {
background-color: var(--bg-primary);
color: var(--text-primary);
}
.card {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
box-shadow: 0 4px 6px var(--shadow);
}
Mathematical Operations
Combine custom properties with calc() for dynamic calculations.
:root {
--base-size: 16px;
--scale-ratio: 1.25;
--spacing-unit: 8px;
}
/* Type scale using calculations */
.h1 {
font-size: calc(var(--base-size) * var(--scale-ratio) * var(--scale-ratio) * var(--scale-ratio));
}
.h2 {
font-size: calc(var(--base-size) * var(--scale-ratio) * var(--scale-ratio));
}
/* Spacing scale */
.mb-1 { margin-bottom: calc(var(--spacing-unit) * 1); }
.mb-2 { margin-bottom: calc(var(--spacing-unit) * 2); }
.mb-3 { margin-bottom: calc(var(--spacing-unit) * 3); }
.mb-4 { margin-bottom: calc(var(--spacing-unit) * 4); }
/* Responsive sizing */
.container {
--max-width: 1200px;
--padding: 20px;
max-width: var(--max-width);
padding: 0 var(--padding);
width: calc(100% - var(--padding) * 2);
}
Color Systems
Build comprehensive color systems with variations and opacity controls.
:root {
/* Base colors as RGB values (for alpha manipulation) */
--color-primary-rgb: 59, 130, 246;
--color-success-rgb: 34, 197, 94;
--color-warning-rgb: 251, 146, 60;
--color-danger-rgb: 239, 68, 68;
/* Solid colors */
--color-primary: rgb(var(--color-primary-rgb));
--color-success: rgb(var(--color-success-rgb));
--color-warning: rgb(var(--color-warning-rgb));
--color-danger: rgb(var(--color-danger-rgb));
/* Alpha variations */
--color-primary-alpha-10: rgba(var(--color-primary-rgb), 0.1);
--color-primary-alpha-20: rgba(var(--color-primary-rgb), 0.2);
--color-primary-alpha-50: rgba(var(--color-primary-rgb), 0.5);
}
/* Usage */
.badge-primary {
background: var(--color-primary-alpha-10);
color: var(--color-primary);
border: 1px solid var(--color-primary-alpha-20);
}
.button-primary {
background: var(--color-primary);
box-shadow: 0 4px 12px var(--color-primary-alpha-20);
}
.button-primary:hover {
box-shadow: 0 6px 20px var(--color-primary-alpha-50);
}
Responsive Design Patterns
Use custom properties to create responsive designs that adapt to different screen sizes.
:root {
--container-width: 90%;
--font-size-base: 16px;
--spacing: 12px;
--columns: 1;
}
@media(min-width: 640px) {
:root {
--container-width: 85%;
--spacing: 16px;
--columns: 2;
}
}
@media(min-width: 1024px) {
:root {
--container-width: 1200px;
--font-size-base: 18px;
--spacing: 24px;
--columns: 3;
}
}
.container {
width: var(--container-width);
padding: var(--spacing);
}
.grid {
display: grid;
grid-template-columns: repeat(var(--columns), 1fr);
gap: var(--spacing);
}
Dynamic Updates with JavaScript
Custom properties can be updated dynamically with JavaScript for interactive experiences.
/* CSS */
.interactive-element {
--mouse-x: 50%;
--mouse-y: 50%;
--hue: 200;
background: linear-gradient(
calc(var(--mouse-x) * 1deg),
hsl(var(--hue), 70%, 50%),
hsl(calc(var(--hue) + 60), 70%, 50%)
);
transform: perspective(1000px)
rotateX(calc((var(--mouse-y) - 50) * 0.2deg))
rotateY(calc((var(--mouse-x) - 50) * 0.2deg));
}
Browser Support and Fallbacks
Custom properties are widely supported, but always provide fallbacks for older browsers.
/* Feature detection */
@supports(--css: variables) {
.modern {
--spacing: 20px;
padding: var(--spacing);
}
}
@supports not (--css: variables) {
.modern {
padding: 20px; /* Fallback */
}
}
/* Inline fallbacks */
.element {
background: #3b82f6; /* Fallback */
background: var(--primary-color, #3b82f6);
font-size: 16px; /* Fallback */
font-size: var(--font-size-base, 16px);
}
Practice Exercises
- Theme Switcher: Create a complete light/dark/high-contrast theme system with a toggle button.
- Color Palette: Build a color system with primary, secondary, and accent colors, each with 10 shades using HSL and custom properties.
- Responsive Typography: Implement a type scale that adjusts based on screen size using CSS variables and media queries.
- Interactive Card: Create a card that responds to mouse movement, updating shadow and rotation using CSS variables controlled by JavaScript.
- Component Library: Design a button component system with multiple variants (primary, secondary, danger) using scoped custom properties.
- Custom properties cascade and inherit like regular CSS properties
- Use :root for global variables, component selectors for local scope
- Always provide fallback values for critical properties
- Combine with calc() for dynamic calculations
- Perfect for theming and runtime style updates with JavaScript
- Store RGB values separately to create alpha variations
What's Next?
Explore CSS Functions (calc, clamp, min, max) to enhance your custom properties with advanced calculations, or check out Performance & Architecture for organizing large-scale CSS projects.
CSS Math Functions: calc(), min(), max(), clamp()
Master responsive calculations without JavaScript using CSS mathematical functions
CSS math functions enable dynamic calculations directly in your stylesheets. These powerful tools eliminate the need for multiple media queries and create truly fluid, responsive designs that adapt seamlessly to any viewport size.
The calc() Function
calc() performs basic arithmetic operations with different units. It's essential for creating flexible layouts.
/* Mixing units */
.sidebar {
width: calc(100% - 250px);
height: calc(100vh - 60px);
}
/* Multiple operations */
.container {
width: calc((100% - 40px) / 3);
padding: calc(1rem + 2px);
}
/* With CSS variables */
:root {
--header-height: 64px;
--sidebar-width: 280px;
--gap: 20px;
}
.main-content {
width: calc(100% - var(--sidebar-width) - var(--gap));
height: calc(100vh - var(--header-height));
margin-left: calc(var(--sidebar-width) + var(--gap));
}
/* Negative values */
.offset {
margin-left: calc(-1 * var(--container-padding));
width: calc(100% + var(--container-padding) * 2);
}
/* Complex calculations */
.grid-item {
width: calc((100% - (var(--columns) - 1) * var(--gap)) / var(--columns));
}
The min() Function
min() returns the smallest value from a comma-separated list. Perfect for setting maximum constraints.
/* Responsive container width */
.container {
/* Never wider than 1200px, but 90% on small screens */
width: min(1200px, 90%);
margin: 0 auto;
}
/* Responsive font size with maximum */
h1 {
/* Scales with viewport but never exceeds 48px */
font-size: min(48px, 8vw);
}
/* Sidebar with max width */
.sidebar {
width: min(320px, 100%);
}
/* Image constraints */
img {
width: 100%;
max-height: min(500px, 80vh);
object-fit: cover;
}
/* Multiple values */
.flexible {
padding: min(5vw, 2rem, 40px);
gap: min(3%, 24px);
}
/* With calc() */
.complex {
width: min(calc(100% - 40px), 1200px);
margin-inline: auto;
}
The max() Function
max() returns the largest value from a comma-separated list. Ideal for setting minimum constraints.
/* Ensure minimum size */
.button {
/* At least 44px for touch targets */
min-height: max(44px, 2.5em);
padding: max(12px, 1em) max(24px, 2em);
}
/* Responsive font with minimum */
body {
/* Never smaller than 16px */
font-size: max(16px, 1vw);
}
/* Minimum spacing */
.section {
margin-block: max(2rem, 5vh);
padding-inline: max(20px, 3%);
}
/* Grid columns with minimum width */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(max(250px, 30%), 1fr));
gap: max(1rem, 2%);
}
/* Ensure readability */
.text-content {
line-height: max(1.5, calc(1em + 0.5rem));
letter-spacing: max(0.01em, 0.5px);
}
The clamp() Function
clamp() constrains a value between minimum and maximum bounds. It's the most powerful function for fluid design.
/* Syntax: clamp(min, preferred, max) */
/* Fluid typography */
h1 {
font-size: clamp(2rem, 5vw, 4rem);
}
h2 {
font-size: clamp(1.5rem, 3vw + 1rem, 3rem);
}
p {
font-size: clamp(1rem, 0.875rem + 0.5vw, 1.25rem);
line-height: clamp(1.5, 1.2 + 0.5vw, 1.8);
}
/* Fluid spacing */
.section {
padding-block: clamp(2rem, 5vw, 6rem);
padding-inline: clamp(1rem, 4%, 3rem);
}
.stack > * + * {
margin-top: clamp(0.5rem, 2vw, 2rem);
}
/* Fluid container */
.container {
width: clamp(320px, 90%, 1200px);
margin-inline: auto;
}
/* Fluid gap */
.grid {
gap: clamp(1rem, 3vw, 3rem);
}
Fluid Typography Systems
Create a complete type scale that adapts smoothly across all screen sizes.
:root {
/* Base size scales from 16px to 20px */
--font-size-base: clamp(1rem, 0.875rem + 0.5vw, 1.25rem);
/* Type scale using relative calculations */
--font-size-sm: clamp(0.875rem, 0.8rem + 0.35vw, 1.125rem);
--font-size-lg: clamp(1.125rem, 1rem + 0.625vw, 1.5rem);
--font-size-xl: clamp(1.25rem, 1.125rem + 0.75vw, 1.875rem);
--font-size-2xl: clamp(1.5rem, 1.25rem + 1.25vw, 2.5rem);
--font-size-3xl: clamp(2rem, 1.5rem + 2.5vw, 3.5rem);
--font-size-4xl: clamp(2.5rem, 1.75rem + 3.75vw, 4.5rem);
}
body {
font-size: var(--font-size-base);
}
.text-sm { font-size: var(--font-size-sm); }
.text-lg { font-size: var(--font-size-lg); }
h6{ .h6 { font-size: var(--font-size-xl); }
h5{ .h5 { font-size: var(--font-size-2xl); }
h4{ .h4 { font-size: var(--font-size-2xl); }
h3{ .h3 { font-size: var(--font-size-3xl); }
h2{ .h2 { font-size: var(--font-size-3xl); }
h1{ .h1 { font-size: var(--font-size-4xl); }
Fluid Spacing Systems
Build spacing scales that adapt proportionally to viewport size.
:root {
/* Spacing scale from mobile to desktop */
--space-3xs: clamp(0.25rem, 0.2rem + 0.25vw, 0.5rem);
--space-2xs: clamp(0.5rem, 0.4rem + 0.5vw, 0.75rem);
--space-xs: clamp(0.75rem, 0.65rem + 0.5vw, 1rem);
--space-sm: clamp(1rem, 0.875rem + 0.625vw, 1.5rem);
--space-md: clamp(1.5rem, 1.25rem + 1.25vw, 2.5rem);
--space-lg: clamp(2rem, 1.5rem + 2.5vw, 4rem);
--space-xl: clamp(3rem, 2rem + 5vw, 6rem);
--space-2xl: clamp(4rem, 2.5rem + 7.5vw, 8rem);
}
/* Usage */
.section {
padding-block: var(--space-lg);
}
.card {
padding: var(--space-md);
gap: var(--space-sm);
}
.stack > * + * {
margin-top: var(--space-sm);
}
.grid {
gap: var(--space-md);
}
Viewport-Based Calculations
Leverage viewport units for truly responsive designs that scale with screen size.
/* Full viewport layouts */
.hero {
min-height: calc(100vh - var(--header-height));
padding: clamp(2rem, 10vh, 6rem) clamp(1rem, 5vw, 3rem);
}
/* Viewport-aware containers */
.container {
width: min(100% - 2rem, 1200px);
margin-inline: auto;
}
/* Responsive aspect ratios */
.video-container {
width: 100%;
aspect-ratio: 16 / 9;
max-height: calc(100vh - 100px);
}
/* Fluid grid sizing */
.grid {
grid-template-columns: repeat(
auto-fit,
minmax(clamp(250px, 40vw, 400px), 1fr)
);
}
/* Sidebar layout */
.layout {
display: grid;
grid-template-columns: minmax(250px, 20vw) 1fr;
gap: clamp(1rem, 3vw, 3rem);
}
Combining Functions
Nest and combine functions for complex, responsive calculations.
/* Nested functions */
.advanced {
/* Clamp with calc */
width: clamp(300px, calc(50% - 2rem), 600px);
/* Min with calc */
padding: min(5vw, calc(2rem + 10px));
/* Max with multiple calc */
margin: max(calc(2rem - 10px), calc(3vw + 5px));
}
/* Complex grid system */
.responsive-grid {
--min-column-width: 280px;
--max-columns: 4;
--gap: clamp(1rem, 2vw, 2rem);
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(
max(var(--min-column-width), calc((100% - (var(--max-columns) - 1) * var(--gap)) / var(--max-columns))),
1fr
)
);
gap: var(--gap);
}
/* Fluid container with constraints */
.fluid-container {
width: min(
calc(100% - clamp(2rem, 5vw, 4rem)),
max(600px, 60vw)
);
padding: clamp(1rem, 3vw, 3rem);
}
Performance Considerations
Math functions are performant, but follow best practices for optimal results.
/* Good: Use CSS variables for repeated calculations */
:root {
--spacing-unit: clamp(1rem, 2vw, 2rem);
}
.element-1 { padding: var(--spacing-unit); }
.element-2 { margin: var(--spacing-unit); }
/* Avoid: Repeating complex calculations */
/* .element-1 { padding: clamp(1rem, 2vw, 2rem); } */
/* .element-2 { margin: clamp(1rem, 2vw, 2rem); } */
/* Good: Simplify when possible */
.simple {
width: calc(100% - 40px);
}
/* Avoid: Unnecessary complexity */
/* .complex { width: calc(calc(100% - 20px) - 20px); } */
/* Use logical properties with calculations */
.modern {
margin-inline: clamp(1rem, 5%, 3rem);
padding-block: max(2rem, 5vh);
}
Practice Exercises
- Fluid Typography: Create a complete type scale using clamp() that scales smoothly from mobile (375px) to desktop (1920px).
- Responsive Grid: Build a product grid that maintains item width between 250px and 400px while filling available space.
- Split Layout: Design a two-column layout where the sidebar is 20% of viewport width but never less than 250px or more than 350px.
- Hero Section: Create a hero section with fluid padding and font sizes that look good on all devices.
- Spacing System: Implement a complete spacing scale using clamp() with consistent ratios across breakpoints.
- calc() mixes units and performs arithmetic operations
- min() sets maximum constraints, max() sets minimum constraints
- clamp() combines min and max for fluid, bounded values
- Functions can be nested for complex calculations
- Store repeated calculations in CSS variables for performance
- Use viewport units (vw, vh) for truly responsive designs
What's Next?
Continue to Pseudo-classes & Pseudo-elements to learn about interactive states and decorative elements, or explore CSS Variables to combine with these functions.
Shadows, Gradients & Depth
Create depth and dimension with shadows and gradient techniques
Shadows and gradients are essential tools for creating visual depth and hierarchy in modern web design. Master box-shadow, text-shadow, drop-shadow filters, and various gradient types to build interfaces that feel tactile and three-dimensional.
Box Shadow Fundamentals
Box-shadow adds depth by simulating light and shadow around elements.
/* Syntax: offset-x offset-y blur-radius spread-radius color */
/* Basic shadow */
.shadow-sm {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.shadow {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.shadow-md {
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.shadow-lg {
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}
.shadow-xl {
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.25);
}
/* Inset shadow */
.shadow-inset {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Colored shadows */
.shadow-colored {
box-shadow: 0 8px 16px rgba(59, 130, 246, 0.3);
}
/* No shadow */
.shadow-none {
box-shadow: none;
}
Layered Shadows
Combine multiple shadows for more realistic depth effects.
/* Material Design elevation */
.elevation-1 {
box-shadow:
0 1px 3px rgba(0, 0, 0, 0.12),
0 1px 2px rgba(0, 0, 0, 0.24);
}
.elevation-2 {
box-shadow:
0 3px 6px rgba(0, 0, 0, 0.15),
0 2px 4px rgba(0, 0, 0, 0.12);
}
.elevation-3 {
box-shadow:
0 10px 20px rgba(0, 0, 0, 0.15),
0 3px 6px rgba(0, 0, 0, 0.10);
}
.elevation-4 {
box-shadow:
0 15px 25px rgba(0, 0, 0, 0.15),
0 5px 10px rgba(0, 0, 0, 0.05);
}
/* Realistic card shadow */
.card-realistic {
box-shadow:
0 2.8px 2.2px rgba(0, 0, 0, 0.02),
0 6.7px 5.3px rgba(0, 0, 0, 0.028),
0 12.5px 10px rgba(0, 0, 0, 0.035),
0 22.3px 17.9px rgba(0, 0, 0, 0.042),
0 41.8px 33.4px rgba(0, 0, 0, 0.05),
0 100px 80px rgba(0, 0, 0, 0.07);
}
/* Soft glow effect */
.glow {
box-shadow:
0 0 10px rgba(59, 130, 246, 0.3),
0 0 20px rgba(59, 130, 246, 0.2),
0 0 30px rgba(59, 130, 246, 0.1);
}
Directional Shadows
Create shadows that suggest specific light sources and directions.
/* Top light source */
.light-top {
box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.1);
}
/* Bottom light source */
.light-bottom {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
/* Left light source */
.light-left {
box-shadow: -4px 0 8px rgba(0, 0, 0, 0.1);
}
/* Right light source */
.light-right {
box-shadow: 4px 0 8px rgba(0, 0, 0, 0.1);
}
/* Corner light */
.light-corner {
box-shadow: -8px -8px 16px rgba(0, 0, 0, 0.1);
}
/* Ambient light (all sides) */
.light-ambient {
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
}
Text Shadow
Add depth and legibility to text with text-shadow.
/* Subtle text shadow */
.text-shadow-sm {
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
/* Medium text shadow */
.text-shadow {
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
/* Strong text shadow */
.text-shadow-lg {
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
/* Outline effect */
.text-outline {
text-shadow:
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
color: white;
}
/* Glow effect */
.text-glow {
text-shadow:
0 0 10px rgba(59, 130, 246, 0.8),
0 0 20px rgba(59, 130, 246, 0.6),
0 0 30px rgba(59, 130, 246, 0.4);
color: #3b82f6;
}
/* 3D text effect */
.text-3d {
text-shadow:
1px 1px 0 #2563eb,
2px 2px 0 #2563eb,
3px 3px 0 #1e40af,
4px 4px 0 #1e40af,
5px 5px 0 #1e3a8a,
6px 6px 10px rgba(0, 0, 0, 0.4);
color: #3b82f6;
}
/* Inset text */
.text-inset {
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4);
color: #6b7280;
}
/* Neon text */
.text-neon {
text-shadow:
0 0 7px #fff,
0 0 10px #fff,
0 0 21px #fff,
0 0 42px #f0f,
0 0 82px #f0f,
0 0 92px #f0f,
0 0 102px #f0f,
0 0 151px #f0f;
color: #fff;
}
Drop Shadow Filter
Use drop-shadow filter for shadows that follow element shapes, including transparency.
/* Box shadow - follows box model */
.box-shadow {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
/* Drop shadow - follows element shape (SVG, PNG) */
.drop-shadow {
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.2));
}
/* Multiple drop shadows */
.drop-shadow-multiple {
filter:
drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1))
drop-shadow(0 4px 8px rgba(0, 0, 0, 0.15));
}
/* Colored drop shadow */
.drop-shadow-colored {
filter: drop-shadow(0 4px 12px rgba(59, 130, 246, 0.5));
}
/* Icon with drop shadow */
.icon-shadow {
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
}
/* Image with shadow */
img.shadowed {
filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.25));
}
Linear Gradients
Create smooth color transitions along a straight line.
/* Basic linear gradient */
.gradient-basic {
background: linear-gradient(to right, #3b82f6, #8b5cf6);
}
/* Diagonal gradient */
.gradient-diagonal {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
/* Multi-color gradient */
.gradient-rainbow {
background: linear-gradient(
to right,
#ff6b6b,
#feca57,
#48dbfb,
#ff6b6b
);
}
/* Gradient with transparency */
.gradient-fade {
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
}
/* Hard stop gradient */
.gradient-hard {
background: linear-gradient(
to right,
#3b82f6 0%,
#3b82f6 50%,
#8b5cf6 50%,
#8b5cf6 100%
);
}
/* Stripe pattern */
.gradient-stripes {
background: repeating-linear-gradient(
45deg,
#3b82f6,
#3b82f6 10px,
#60a5fa 10px,
#60a5fa 20px
);
}
Radial Gradients
Create circular or elliptical color transitions.
/* Circular gradient */
.gradient-radial {
background: radial-gradient(circle, #3b82f6, #1e40af);
}
/* Elliptical gradient */
.gradient-ellipse {
background: radial-gradient(ellipse, #667eea, #764ba2);
}
/* Positioned gradient */
.gradient-positioned {
background: radial-gradient(
circle at top left,
#3b82f6,
#8b5cf6
);
}
/* Spotlight effect */
.spotlight {
background: radial-gradient(
circle at center,
rgba(255, 255, 255, 0.2) 0%,
transparent 70%
);
}
/* Vignette effect */
.vignette {
background: radial-gradient(
ellipse at center,
transparent 50%,
rgba(0, 0, 0, 0.7) 100%
);
}
/* Repeating radial */
.gradient-radial-repeating {
background: repeating-radial-gradient(
circle,
#3b82f6,
#3b82f6 10px,
#60a5fa 10px,
#60a5fa 20px
);
}
Conic Gradients
Create gradients that rotate around a center point.
/* Basic conic gradient */
.gradient-conic {
background: conic-gradient(
from 0deg,
#3b82f6,
#8b5cf6,
#ec4899,
#3b82f6
);
border-radius: 50%;
}
/* Pie chart */
.pie-chart {
background: conic-gradient(
#3b82f6 0deg 120deg,
#8b5cf6 120deg 240deg,
#ec4899 240deg 360deg
);
border-radius: 50%;
width: 200px;
height: 200px;
}
/* Color wheel */
.color-wheel {
background: conic-gradient(
from 0deg,
red,
yellow,
lime,
cyan,
blue,
magenta,
red
);
border-radius: 50%;
}
/* Repeating conic */
.gradient-conic-repeating {
background: repeating-conic-gradient(
from 0deg,
#3b82f6 0deg 15deg,
#60a5fa 15deg 30deg
);
border-radius: 50%;
}
/* Loading spinner */
.spinner {
background: conic-gradient(
transparent 0deg 270deg,
#3b82f6 270deg 360deg
);
border-radius: 50%;
animation: rotate 1s linear infinite;
}
@keyframes rotate {
to { transform: rotate(360deg); }
}
Interactive Shadow Effects
Create dynamic shadows that respond to user interaction.
/* Button elevation on hover */
.button-elevated {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
.button-elevated:hover {
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
transform: translateY(-2px);
}
.button-elevated:active {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transform: translateY(0);
}
/* Card hover effect */
.card-hover {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: box-shadow 300ms ease;
}
.card-hover:hover {
box-shadow:
0 20px 25px rgba(0, 0, 0, 0.15),
0 10px 10px rgba(0, 0, 0, 0.1);
}
/* Focus shadow */
input:focus {
box-shadow:
0 0 0 3px rgba(59, 130, 246, 0.2),
0 2px 4px rgba(0, 0, 0, 0.1);
outline: none;
}
/* Animated glow */
@keyframes glow {
0%{ 100% {
box-shadow: 0 0 20px rgba(59, 130, 246, 0.5);
}
50% {
box-shadow: 0 0 40px rgba(59, 130, 246, 0.8);
}
}
.glowing {
animation: glow 2s ease-in-out infinite;
}
Advanced Depth Techniques
Combine shadows and gradients for sophisticated depth effects.
/* Neumorphism */
.neumorphic {
background: #e0e5ec;
border-radius: 20px;
box-shadow:
9px 9px 16px rgba(163, 177, 198, 0.6),
-9px -9px 16px rgba(255, 255, 255, 0.5);
}
.neumorphic-inset {
background: #e0e5ec;
border-radius: 20px;
box-shadow:
inset 6px 6px 12px rgba(163, 177, 198, 0.4),
inset -6px -6px 12px rgba(255, 255, 255, 0.6);
}
/* Glassmorphism */
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
/* Layered card */
.layered-card {
position: relative;
background: white;
border-radius: 16px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.layered-card::before {
content: '';
position: absolute;
inset: -4px;
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: inherit;
z-index: -1;
opacity: 0.5;
filter: blur(20px);
}
/* Floating effect */
@keyframes float {
0%{ 100% {
transform: translateY(0);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
50% {
transform: translateY(-10px);
box-shadow: 0 25px 35px rgba(0, 0, 0, 0.2);
}
}
.floating {
animation: float 3s ease-in-out infinite;
}
Practice Exercises
- Elevation System: Create a 5-level elevation system for cards with increasingly prominent shadows.
- Button States: Design a button with distinct shadow effects for default, hover, active, and focus states.
- Gradient Background: Build a hero section with a multi-color gradient and overlay text with appropriate shadows for legibility.
- Neumorphic UI: Create a neumorphic calculator interface with raised and pressed button states.
- Animated Loader: Design a loading spinner using conic-gradient and rotation animation.
- Layer multiple box-shadows for realistic depth effects
- Use drop-shadow filter for shadows on transparent PNGs and SVGs
- Text-shadow improves legibility and adds visual interest
- Combine shadows with transforms for interactive effects
- Linear, radial, and conic gradients each serve different purposes
- Subtle shadows (low opacity, blur) look more natural
What's Next?
Explore Backgrounds & Borders to complement your depth effects, or check out Transforms & Effects for dynamic animations.
Accessibility & Inclusive Design
Create interfaces that work for everyone, regardless of ability
Accessibility (a11y) ensures your web content is usable by everyone, including people with disabilities. CSS plays a crucial role in creating accessible interfaces through proper color contrast, focus indicators, responsive text, and motion preferences. Learn WCAG guidelines and implement inclusive design patterns.
Color Contrast Requirements
WCAG 2.1 defines minimum contrast ratios between text and background colors.
/* WCAG AA Requirements:
* - Normal text (< 24px): 4.5:1 contrast ratio
* - Large text (≥ 24px or 19px bold): 3:1 contrast ratio
* - UI components and graphics: 3:1 contrast ratio
*
* WCAG AAA Requirements:
* - Normal text: 7:1 contrast ratio
* - Large text: 4.5:1 contrast ratio
*/
/* GOOD - AA Compliant */
.text-good {
color: #1f2937; /* Gray-800 */
background-color: #ffffff; /* White */
/* Contrast ratio: 16.1:1 ✓ */
}
.text-muted-good {
color: #4b5563; /* Gray-600 */
background-color: #ffffff;
/* Contrast ratio: 7.5:1 ✓ */
}
/* BAD - Fails AA */
.text-bad {
color: #9ca3af; /* Gray-400 */
background-color: #ffffff;
/* Contrast ratio: 2.8:1 ✗ */
}
/* Dark mode - Maintain contrast */
[data-theme="dark"] {
--text-primary: #f9fafb; /* Gray-50 */
--bg-primary: #111827; /* Gray-900 */
/* Contrast ratio: 16.9:1 ✓ */
--text-secondary: #d1d5db; /* Gray-300 */
/* Contrast ratio: 8.5:1 ✓ */
}
/* Link contrast */
a {
color: #2563eb; /* Blue-600 */
/* Contrast ratio: 5.7:1 with white ✓ */
}
/* Button contrast */
.btn-primary {
background-color: #3b82f6; /* Blue-500 */
color: #ffffff;
/* Contrast ratio: 4.5:1 ✓ */
}
Focus Indicators
Visible focus indicators are essential for keyboard navigation accessibility.
/* Global focus styles */
*:focus {
outline: 2px solid transparent;
outline-offset: 2px;
}
/* Visible focus for keyboard navigation only */
*:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* Remove focus for mouse clicks */
*:focus:not(:focus-visible) {
outline: none;
}
/* Interactive element focus */
a:focus-visible{
button:focus-visible{
input:focus-visible{
select:focus-visible{
textarea:focus-visible {
outline: 3px solid #3b82f6;
outline-offset: 2px;
}
/* High contrast mode - visible focus */
@media(prefers-contrast: high) {
*:focus-visible {
outline: 3px solid currentColor;
outline-offset: 3px;
}
}
/* Custom focus ring */
.custom-focus:focus-visible {
outline: none;
box-shadow:
0 0 0 3px #ffffff,
0 0 0 5px #3b82f6;
}
/* Skip to content link */
.skip-to-content {
position: absolute;
top: -100px;
left: 20px;
z-index: 1000;
padding: 0.75rem 1.5rem;
background: #3b82f6;
color: white;
text-decoration: none;
border-radius: 8px;
}
.skip-to-content:focus {
top: 20px;
}
Responsive and Resizable Text
Text must remain readable when users resize it or zoom the page.
/* Use relative units (rem, em) not pixels */
body {
font-size: 1rem; /* 16px base - GOOD */
line-height: 1.5; /* Unitless line-height */
}
/* BAD - Fixed pixel sizes */
.bad-text {
font-size: 14px; /* Hard to scale */
line-height: 20px; /* Fixed height */
}
/* GOOD - Relative sizes */
.good-text {
font-size: 0.875rem; /* Scales with user preferences */
line-height: 1.5; /* Proportional */
}
/* Respect user font size preferences */
html {
font-size: 100%; /* Don't override user default */
}
/* Fluid typography with limits */
h1 {
font-size: clamp(2rem, 5vw, 4rem);
}
/* Minimum line height for readability */
p {
line-height: 1.5; /* WCAG recommends 1.5 minimum */
}
/* Proper text spacing */
.readable-text {
line-height: 1.6;
letter-spacing: 0.01em;
word-spacing: 0.05em;
}
/* Maximum line length */
.content {
max-width: 65ch; /* 45-75 characters optimal */
margin-inline: auto;
}
Touch Target Sizes
Interactive elements must be large enough to activate accurately.
/* WCAG 2.1 AA: Minimum 44x44px touch targets */
button{
a{
input{
select {
min-height: 44px;
min-width: 44px;
}
/* Icon-only buttons */
.icon-button {
width: 44px;
height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
}
/* Increase target size with padding */
.nav-link {
padding: 0.75rem 1rem; /* Total height > 44px */
}
/* Mobile - larger targets */
@media(max-width: 768px) {
button{
a.btn {
min-height: 48px;
min-width: 48px;
padding: 0.875rem 1.25rem;
}
}
/* Spacing between targets */
.button-group {
display: flex;
gap: 0.5rem; /* Minimum 8px between targets */
}
Screen Reader Only Content
Hide content visually while keeping it accessible to screen readers.
/* Screen reader only class */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Focusable screen reader only */
.sr-only-focusable:focus {
position: static;
width: auto;
height: auto;
padding: inherit;
margin: inherit;
overflow: visible;
clip: auto;
white-space: normal;
}
/* Hide aria-hidden elements from everyone */
[aria-hidden="true"] {
display: none;
}
/* Usage examples */
.icon-button {
/* Icon button needs text for screen readers */
}
.icon-button .icon {
/* Visual icon */
}
.icon-button .sr-only {
/* "Settings" - Screen reader text */
}
<button class="icon-button">
<svg aria-hidden="true">...</svg>
<span class="sr-only">Close menu</span>
</button>
Motion and Animation Preferences
Respect user preferences for reduced motion.
/* Default animations */
.animated {
transition: transform 300ms ease, opacity 300ms ease;
}
.fade-in {
animation: fadeIn 500ms ease-in;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* Reduce motion for users who prefer it */
@media(prefers-reduced-motion: reduce) {
*{
*::before{
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
/* Keep essential transitions */
.animated {
transition: opacity 0.01ms;
}
}
/* Safe animations - position changes only */
@media(prefers-reduced-motion: no-preference) {
.smooth-scroll {
scroll-behavior: smooth;
}
}
/* Loading indicators - always animate */
.spinner {
animation: spin 1s linear infinite;
}
@media(prefers-reduced-motion: reduce) {
.spinner {
/* Replace with pulsing opacity instead */
animation: pulse 1s ease-in-out infinite;
}
}
Color Scheme Preferences
Support user color scheme preferences including dark mode.
/* Light mode (default) */
:root {
--bg-primary: #ffffff;
--text-primary: #1f2937;
--border-color: #e5e7eb;
}
/* Dark mode preference */
@media(prefers-color-scheme: dark) {
:root {
--bg-primary: #111827;
--text-primary: #f9fafb;
--border-color: #374151;
}
}
/* High contrast preference */
@media(prefers-contrast: high) {
:root {
--border-width: 2px;
}
button{
a {
outline: var(--border-width) solid currentColor;
}
}
/* Low contrast preference (for light sensitivity) */
@media(prefers-contrast: low) {
* {
text-shadow: none;
box-shadow: none;
}
}
/* Forced colors mode (Windows High Contrast) */
@media(forced-colors: active) {
.custom-checkbox {
forced-color-adjust: auto;
}
}
Semantic HTML and ARIA
Use proper HTML elements and ARIA attributes for semantic meaning.
/* Style semantic HTML */
main {
/* Main content area */
}
nav {
/* Navigation */
}
article {
/* Self-contained content */
}
aside {
/* Complementary content */
}
/* ARIA live regions */
[aria-live="polite"]{
[aria-live="assertive"] {
/* Status messages, alerts */
}
/* Hidden content */
[aria-hidden="true"] {
display: none;
}
/* Disabled states */
[aria-disabled="true"]{
:disabled {
opacity: 0.6;
cursor: not-allowed;
pointer-events: none;
}
/* Expanded/collapsed states */
[aria-expanded="false"] .icon {
transform: rotate(0deg);
}
[aria-expanded="true"] .icon {
transform: rotate(180deg);
}
/* Selected state */
[aria-selected="true"] {
background-color: #dbeafe;
font-weight: 600;
}
/* Invalid state */
[aria-invalid="true"] {
border-color: #ef4444;
}
Logical Properties for Internationalization
Use logical properties for better RTL (right-to-left) language support.
/* Physical properties (avoid for i18n) */
.old-way {
margin-left: 1rem;
padding-right: 1rem;
border-left: 2px solid #3b82f6;
text-align: left;
}
/* Logical properties (better for i18n) */
.new-way {
margin-inline-start: 1rem;
padding-inline-end: 1rem;
border-inline-start: 2px solid #3b82f6;
text-align: start;
}
/* Block and inline directions */
.container {
padding-block: 2rem; /* Top & bottom */
padding-inline: 1rem; /* Left & right (or right & left in RTL) */
}
/* Logical border radius */
.card {
border-start-start-radius: 12px; /* Top-left in LTR */
border-start-end-radius: 12px; /* Top-right in LTR */
}
/* RTL support */
[dir="rtl"] {
/* Logical properties automatically reverse */
}
/* Directional icons */
.icon-arrow {
transform: scaleX(1);
}
[dir="rtl"] .icon-arrow {
transform: scaleX(-1);
}
Print Accessibility
Ensure content is accessible when printed.
@media print {
/* Remove unnecessary elements */
nav{
.sidebar{
.advertisement{
.no-print {
display: none !important;
}
/* Optimize for print */
body {
font-size: 12pt;
line-height: 1.5;
color: #000;
background: #fff;
}
/* Show link URLs */
a[href]::after {
content: " (" attr(href) ")";
font-size: 90%;
color: #666;
}
/* Page breaks */
h1{ h2{ h3 {
page-break-after: avoid;
page-break-inside: avoid;
}
img {
page-break-inside: avoid;
max-width: 100%;
}
}
Practice Exercises
- Contrast Audit: Review a website and fix all color contrast issues to meet WCAG AA standards.
- Keyboard Navigation: Build a dropdown menu that works entirely with keyboard (Tab, Enter, Escape, Arrow keys).
- Focus Management: Create a modal dialog with proper focus trapping and return focus management.
- Screen Reader Test: Use a screen reader to test a form and fix any accessibility issues found.
- Reduced Motion: Implement an animated page with proper reduced motion alternatives.
- Maintain 4.5:1 contrast ratio for normal text, 3:1 for large text
- Never remove focus indicators without providing visible alternatives
- Support prefers-reduced-motion for users with vestibular disorders
- Use relative units (rem, em) for font sizes, not pixels
- Minimum 44x44px touch targets for interactive elements
- Test with keyboard, screen readers, and zoom levels up to 200%
What's Next?
Continue to Forms & Input Styling for accessible form patterns, or explore Best Practices for comprehensive development guidelines.
Performance & Architecture
Optimize CSS delivery and structure for fast, maintainable websites
CSS performance impacts loading speed, runtime efficiency, and long-term maintainability. Learn critical CSS loading strategies, CSS methodologies (BEM, OOCSS, SMACSS), code organization, and optimization techniques to build scalable, performant stylesheets.
Loading Strategies
Optimize how CSS is loaded and parsed by the browser.
<!-- 1. Critical CSS inline (fastest FCP) -->
<head>
<style>
/* Critical above-the-fold styles */
body { margin: 0; font-family: system-ui; }
.header { /* Critical header styles */ }
</style>
<!-- 2. Preload key CSS files -->
<link rel="preload" href="/css/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/main.css"></noscript>
<!-- 3. Async load non-critical CSS -->
<link rel="preload" href="/css/non-critical.css" as="style" onload="this.rel='stylesheet'">
</head>
/* Keep critical CSS minimal */
/* Inline only above-the-fold styles */
/* Target < 14KB for first render */
/* Critical CSS example */
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
color: #1f2937;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.header {
height: 64px;
display: flex;
align-items: center;
}
File Size Optimization
Reduce CSS file size through minification, compression, and purging.
/* Before optimization */
.button {
padding-top: 12px;
padding-right: 24px;
padding-bottom: 12px;
padding-left: 24px;
background-color: #3b82f6;
border-radius: 8px;
font-weight: 600;
}
/* After optimization (minified, shorthand) */
.button{padding:12px 24px;background:#3b82f6;border-radius:8px;font-weight:600}
/* Use CSS shorthand properties */
.optimized {
/* Instead of margin-top, margin-right, etc. */
margin: 1rem 2rem 1rem 2rem;
/* Instead of individual padding */
padding: 0.75rem 1.5rem;
/* Instead of separate background properties */
background: #3b82f6 url('/img.png') no-repeat center/cover;
/* Instead of border-width, border-style, border-color */
border: 2px solid #e5e7eb;
}
/* Remove unused CSS */
/* Use tools like PurgeCSS, UnCSS */
/* Avoid deep nesting (increases file size) */
/* BAD */
.nav .menu .item .link .icon {
color: blue;
}
/* GOOD */
.nav-icon {
color: blue;
}
CSS Architecture: BEM Methodology
Block Element Modifier (BEM) naming convention for maintainable CSS.
/* BEM Syntax: block__element--modifier */
/* Block - standalone component */
.card {
background: white;
border-radius: 8px;
padding: 1.5rem;
}
/* Element - child of block */
.card__header {
margin-bottom: 1rem;
border-bottom: 1px solid #e5e7eb;
}
.card__title {
font-size: 1.25rem;
font-weight: 600;
}
.card__body {
color: #6b7280;
}
.card__footer {
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid #e5e7eb;
}
/* Modifier - variant of block or element */
.card--featured {
border: 2px solid #3b82f6;
box-shadow: 0 10px 25px rgba(59, 130, 246, 0.1);
}
.card--compact {
padding: 1rem;
}
.card__title--large {
font-size: 1.5rem;
}
/* Combining modifiers */
.button {
padding: 0.75rem 1.5rem;
border-radius: 8px;
font-weight: 500;
}
.button--primary {
background: #3b82f6;
color: white;
}
.button--secondary {
background: #6b7280;
color: white;
}
.button--large {
padding: 1rem 2rem;
font-size: 1.125rem;
}
.button--small {
padding: 0.5rem 1rem;
font-size: 0.875rem;
}
OOCSS (Object-Oriented CSS)
Separate structure from skin and container from content.
/* Principle 1: Separate structure from skin */
/* Structure (layout, positioning) */
.box {
display: flex;
padding: 1rem;
margin-bottom: 1rem;
}
/* Skin (visual appearance) */
.skin-primary {
background: #3b82f6;
color: white;
}
.skin-secondary {
background: #6b7280;
color: white;
}
/* Principle 2: Separate container from content */
/* BAD - Content depends on container */
.sidebar h3 {
font-size: 1.25rem;
}
/* GOOD - Content independent */
.heading-md {
font-size: 1.25rem;
}
/* Utility objects */
.media {
display: flex;
gap: 1rem;
}
.media__image {
flex-shrink: 0;
}
.media__body {
flex: 1;
}
/* Reusable spacing objects */
.mt-1 { margin-top: 0.25rem; }
.mt-2 { margin-top: 0.5rem; }
.mt-3 { margin-top: 1rem; }
.mt-4 { margin-top: 1.5rem; }
SMACSS (Scalable and Modular Architecture)
Organize CSS into five categories: Base, Layout, Module, State, and Theme.
/* 1. Base Rules - Defaults and resets */
*{
*::before{
*::after {
box-sizing: border-box;
}
body {
margin: 0;
font-family: system-ui, sans-serif;
line-height: 1.5;
}
/* 2. Layout Rules - Major sections (prefix: l-) */
.l-header {
position: sticky;
top: 0;
}
.l-sidebar {
width: 250px;
}
.l-main {
flex: 1;
}
.l-footer {
padding: 2rem 0;
}
/* 3. Module Rules - Reusable components */
.card {
background: white;
border-radius: 8px;
padding: 1.5rem;
}
.button {
padding: 0.75rem 1.5rem;
border-radius: 8px;
}
/* 4. State Rules - State changes (prefix: is-, has-) */
.is-active {
font-weight: bold;
color: #3b82f6;
}
.is-hidden {
display: none;
}
.is-loading {
opacity: 0.5;
pointer-events: none;
}
.has-error {
border-color: #ef4444;
}
/* 5. Theme Rules - Color schemes */
.theme-dark {
--bg: #111827;
--text: #f9fafb;
}
.theme-light {
--bg: #ffffff;
--text: #1f2937;
}
Runtime Performance
Optimize for browser rendering and reflow performance.
/* Avoid expensive properties */
/* BAD - Triggers layout */
.slow {
width: 100px;
height: 100px;
top: 10px;
left: 10px;
}
/* GOOD - GPU accelerated */
.fast {
transform: translate(10px, 10px);
will-change: transform;
}
/* Use transform and opacity for animations */
.animated {
/* Triggers paint and layout */
/* transition: width 300ms, height 300ms, background 300ms; */
/* Only triggers composite */
transition: transform 300ms, opacity 300ms;
}
/* Contain layout reflow */
.card {
contain: layout style paint;
}
/* Optimize selector specificity */
/* BAD - Complex selector */
nav ul li a.active {
color: blue;
}
/* GOOD - Simple class */
.nav-link--active {
color: blue;
}
/* Avoid universal selectors */
/* BAD */
* {
transition: all 300ms;
}
/* GOOD - Specific classes */
.transition-transform {
transition: transform 300ms;
}
/* Use content-visibility for off-screen content */
.lazy-section {
content-visibility: auto;
contain-intrinsic-size: 0 500px;
}
/* Limit box-shadow layers */
/* BAD - Multiple shadows */
.heavy-shadow {
box-shadow:
0 1px 1px rgba(0,0,0,0.1),
0 2px 2px rgba(0,0,0,0.1),
0 4px 4px rgba(0,0,0,0.1),
0 8px 8px rgba(0,0,0,0.1),
0 16px 16px rgba(0,0,0,0.1);
}
/* GOOD - Single shadow */
.light-shadow {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
File Organization
Structure CSS files for maintainability and scalability.
styles/
├── base/
│ ├── _reset.css
│ ├── _typography.css
│ └── _variables.css
├── components/
│ ├── _button.css
│ ├── _card.css
│ ├── _form.css
│ └── _modal.css
├── layout/
│ ├── _header.css
│ ├── _footer.css
│ ├── _sidebar.css
│ └── _grid.css
├── utilities/
│ ├── _spacing.css
│ ├── _colors.css
│ └── _text.css
├── pages/
│ ├── _home.css
│ └── _about.css
└── main.css (imports all)
/* main.css - Import order matters */
/* 1. Base/Config */
@import 'base/variables';
@import 'base/reset';
@import 'base/typography';
/* 2. Layout */
@import 'layout/grid';
@import 'layout/header';
@import 'layout/footer';
@import 'layout/sidebar';
/* 3. Components */
@import 'components/button';
@import 'components/card';
@import 'components/form';
@import 'components/modal';
/* 4. Pages */
@import 'pages/home';
@import 'pages/about';
/* 5. Utilities (last for highest specificity) */
@import 'utilities/spacing';
@import 'utilities/colors';
@import 'utilities/text';
CSS-in-JS vs Traditional CSS
Understand trade-offs between different CSS approaches.
/* Traditional CSS */
/* Pros: Cacheable, parallel download, familiar
* Cons: Global scope, no dead code elimination
*/
.button {
padding: 0.75rem 1.5rem;
background: #3b82f6;
border-radius: 8px;
}
/* CSS Modules */
/* Pros: Scoped styles, tree-shakeable
* Cons: Requires build step
*/
.button {
/* Compiled to: .Button_button__2Rx3j */
padding: 0.75rem 1.5rem;
background: #3b82f6;
}
/* Utility-First (Tailwind) */
/* Pros: Fast development, small production size
* Cons: Learning curve, verbose HTML
*/
/* class="px-6 py-3 bg-blue-500 rounded-lg" */
/* CSS-in-JS (styled-components) */
/* Pros: Component-scoped, dynamic styles
* Cons: Runtime cost, no caching
*/
/* const Button = styled.button`
padding: 0.75rem 1.5rem;
background: #3b82f6;
`; */
/* Recommendation: Choose based on project needs
* - Traditional CSS: Static sites, content-heavy
* - CSS Modules: React/Vue apps needing scoping
* - Utility-First: Rapid prototyping, design systems
* - CSS-in-JS: Complex dynamic styling needs
*/
Performance Monitoring
Measure and track CSS performance metrics.
/* Performance budgets */
/* Target metrics:
* - CSS file size: < 50KB (minified + gzipped)
* - Critical CSS: < 14KB (inline)
* - Selector complexity: < 3 levels deep
* - Animation: 60fps (16.67ms per frame)
* - First paint: < 1s
* - Interactive: < 3s
*/
/* Use CSS containment */
.independent-component {
contain: layout style paint;
}
/* Lazy load non-critical CSS */
/* */
Practice Exercises
- Critical CSS: Extract and inline critical CSS for a webpage's above-the-fold content.
- BEM Refactor: Refactor an existing component to use BEM naming methodology.
- Performance Audit: Run Lighthouse, identify CSS performance issues, and optimize them.
- CSS Architecture: Structure a multi-page website using SMACSS methodology.
- Bundle Optimization: Set up PurgeCSS to remove unused styles from a project.
- Inline critical CSS for fastest First Contentful Paint
- Use BEM, OOCSS, or SMACSS for maintainable architecture
- Animate transform and opacity only for 60fps performance
- Minify and compress CSS files in production
- Keep selectors simple and avoid deep nesting
- Organize code into base, components, layout, and utilities
What's Next?
Continue to Validation & Tools for debugging and testing strategies, or check Best Practices for comprehensive guidelines.
Best Practices
Professional CSS development guidelines for maintainable, scalable code
Master professional CSS development with industry best practices covering naming conventions, code organization, mobile-first design, accessibility, performance, and team collaboration. Build maintainable, scalable stylesheets that stand the test of time.
Naming Conventions
Use consistent, meaningful class names following established methodologies.
/* BEM: Block__Element--Modifier */
/* GOOD - Clear, descriptive BEM names */
.card {
/* Block: standalone component */
}
.card__header {
/* Element: child of .card */
}
.card__title {
/* Element: nested child */
}
.card--featured {
/* Modifier: variant of .card */
}
.card__title--large {
/* Modifier: variant of .card__title */
}
/* BAD - Unclear, inconsistent names */
.cd { /* Too abbreviated */ }
.cardHeader { /* Wrong case */ }
.card_title { /* Wrong separator */ }
.card-featured { /* Should be card--featured */ }
/* Naming rules:
* - Use lowercase with hyphens (kebab-case)
* - Be descriptive, not cryptic
* - Avoid abbreviations unless universal (btn is OK)
* - Prefix utility classes (u-, is-, has-)
* - Prefix JavaScript hooks (js-)
*/
/* Utility classes */
.u-text-center { text-align: center; }
.u-mb-2 { margin-bottom: 1rem; }
/* State classes */
.is-active { font-weight: bold; }
.is-hidden { display: none; }
.has-error { border-color: #ef4444; }
/* JavaScript hooks (no styles) */
.js-toggle-menu { /* No CSS here */ }
.js-modal-trigger { /* Reserved for JS */ }
Code Organization
Structure CSS files logically for maintainability and scalability.
styles/
├── 01-settings/
│ ├── _variables.css /* Design tokens */
│ └── _functions.css /* Custom functions */
├── 02-tools/
│ └── _mixins.css /* Reusable mixins */
├── 03-generic/
│ ├── _reset.css /* Normalize/reset */
│ └── _box-sizing.css /* Global resets */
├── 04-elements/
│ ├── _typography.css /* Base typography */
│ ├── _links.css /* Base link styles */
│ └── _forms.css /* Base form styles */
├── 05-objects/
│ ├── _container.css /* Layout objects */
│ ├── _grid.css /* Grid system */
│ └── _media.css /* Media object */
├── 06-components/
│ ├── _button.css /* Button component */
│ ├── _card.css /* Card component */
│ ├── _nav.css /* Navigation */
│ └── _modal.css /* Modal dialogs */
├── 07-utilities/
│ ├── _spacing.css /* Margin/padding utils */
│ ├── _text.css /* Text utilities */
│ └── _display.css /* Display utilities */
└── main.css /* Imports all files */
/* main.css - Import order */
/* 1. Settings - No output, just variables */
@import '01-settings/variables';
@import '01-settings/functions';
/* 2. Tools - Mixins and functions */
@import '02-tools/mixins';
/* 3. Generic - Ground zero styles */
@import '03-generic/reset';
@import '03-generic/box-sizing';
/* 4. Elements - Unclassed HTML elements */
@import '04-elements/typography';
@import '04-elements/links';
@import '04-elements/forms';
/* 5. Objects - Layout patterns */
@import '05-objects/container';
@import '05-objects/grid';
@import '05-objects/media';
/* 6. Components - UI components */
@import '06-components/button';
@import '06-components/card';
@import '06-components/nav';
@import '06-components/modal';
/* 7. Utilities - Overrides and helpers (highest specificity) */
@import '07-utilities/spacing';
@import '07-utilities/text';
@import '07-utilities/display';
DRY Principle (Don't Repeat Yourself)
Reduce repetition with variables, mixins, and reusable classes.
/* BAD - Repetitive code */
.button-primary {
padding: 0.75rem 1.5rem;
border-radius: 8px;
font-weight: 600;
background: #3b82f6;
color: white;
}
.button-secondary {
padding: 0.75rem 1.5rem;
border-radius: 8px;
font-weight: 600;
background: #6b7280;
color: white;
}
.button-danger {
padding: 0.75rem 1.5rem;
border-radius: 8px;
font-weight: 600;
background: #ef4444;
color: white;
}
/* GOOD - DRY with base class + modifiers */
.button {
/* Common styles */
padding: 0.75rem 1.5rem;
border-radius: 8px;
font-weight: 600;
color: white;
}
.button--primary { background: #3b82f6; }
.button--secondary { background: #6b7280; }
.button--danger { background: #ef4444; }
/* EVEN BETTER - CSS custom properties */
:root {
--button-padding: 0.75rem 1.5rem;
--button-radius: 8px;
--color-primary: #3b82f6;
--color-secondary: #6b7280;
--color-danger: #ef4444;
}
.button {
padding: var(--button-padding);
border-radius: var(--button-radius);
font-weight: 600;
color: white;
}
.button--primary { background: var(--color-primary); }
.button--secondary { background: var(--color-secondary); }
.button--danger { background: var(--color-danger); }
Mobile-First Approach
Design for mobile devices first, then progressively enhance for larger screens.
/* BAD - Desktop-first (max-width) */
.container {
width: 1200px; /* Desktop default */
}
@media(max-width: 992px) {
.container { width: 960px; }
}
@media(max-width: 768px) {
.container { width: 720px; }
}
@media(max-width: 576px) {
.container { width: 100%; }
}
/* GOOD - Mobile-first (min-width) */
.container {
width: 100%; /* Mobile default */
padding: 0 1rem;
}
@media(min-width: 576px) {
.container { max-width: 540px; }
}
@media(min-width: 768px) {
.container { max-width: 720px; }
}
@media(min-width: 992px) {
.container { max-width: 960px; }
}
@media(min-width: 1200px) {
.container { max-width: 1140px; }
}
/* Mobile-first navigation */
.nav {
/* Mobile: vertical stack */
flex-direction: column;
gap: 0.5rem;
}
@media(min-width: 768px) {
.nav {
/* Tablet+: horizontal row */
flex-direction: row;
gap: 2rem;
}
}
Avoid !important
Use proper specificity instead of relying on !important.
/* BAD - Overuse of !important */
.text-red {
color: red !important;
}
.button {
background: blue !important;
}
/* This creates specificity wars and is hard to override */
/* GOOD - Proper specificity management */
/* Specificity: 0,1,0 */
.text-red {
color: red;
}
/* Specificity: 0,1,0 */
.button {
background: blue;
}
/* If you need to override, increase specificity properly */
/* Specificity: 0,2,0 */
.nav .button {
background: green;
}
/* Or use utility classes with higher specificity */
/* Specificity: 0,1,0 but loaded last */
.u-bg-green {
background: green;
}
/* ACCEPTABLE uses of !important:
* 1. Utility classes meant to always win
* 2. Overriding inline styles you can't control
* 3. Print stylesheets
*/
/* Utility class - OK to use !important */
.u-hidden {
display: none !important;
}
/* Print styles - OK to use !important */
@media print {
.no-print {
display: none !important;
}
}
Selector Best Practices
Write efficient, maintainable selectors.
/* BAD - Overly specific selectors */
div#main article.post h2.title {
/* Specificity: 0,2,1,3 - Too high! */
}
/* BAD - Descendant selector hell */
.header .nav .menu .item .link {
/* 5 levels deep, hard to override */
}
/* BAD - Universal selector performance */
* {
/* Applies to every element */
transition: all 0.3s;
}
/* BAD - Tag selectors for components */
div.card { /* Unnecessarily specific */ }
/* GOOD - Simple class selectors */
.post-title {
/* Specificity: 0,1,0 - Perfect! */
}
.nav__link {
/* BEM keeps specificity flat */
}
/* GOOD - Limit nesting to 3 levels max */
.card { }
.card__header { }
.card__title { }
/* GOOD - Direct child combinator when needed */
.menu > .menu-item {
/* Only direct children, not nested ones */
}
/* GOOD - Use attribute selectors wisely */
[data-theme="dark"] { }
[aria-expanded="true"] { }
/* Selector performance tips:
* 1. Avoid universal selector (*)
* 2. Keep specificity low
* 3. Don't qualify class selectors (div.card)
* 4. Limit nesting depth
* 5. Use classes over tags for components
*/
Design Tokens
Centralize design decisions with CSS custom properties.
/* Design tokens - Single source of truth */
:root {
/* Colors */
--color-primary: #3b82f6;
--color-secondary: #6b7280;
--color-success: #10b981;
--color-danger: #ef4444;
--color-warning: #f59e0b;
/* Grays */
--gray-50: #f9fafb;
--gray-100: #f3f4f6;
--gray-900: #111827;
/* Spacing scale */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
/* Typography */
--font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-mono: 'Fira Code', 'Courier New', monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
/* Radii */
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-full: 9999px;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
/* Transitions */
--transition-fast: 150ms;
--transition-base: 250ms;
--transition-slow: 350ms;
}
/* Using tokens */
.button {
padding: var(--space-3) var(--space-6);
background: var(--color-primary);
border-radius: var(--radius-md);
font-size: var(--text-base);
box-shadow: var(--shadow-sm);
transition: all var(--transition-base);
}
/* Dark theme override */
[data-theme="dark"] {
--gray-50: #111827;
--gray-900: #f9fafb;
}
Documentation
Document complex CSS for team collaboration.
/* ============================================
BUTTON COMPONENT
============================================
Usage:
Variants:
- button--primary (blue)
- button--secondary (gray)
- button--danger (red)
Sizes:
- button--sm (small)
- button--lg (large)
States:
- :hover
- :focus
- :disabled
- .is-loading
Accessibility:
- Meets WCAG AA contrast ratios
- Focus visible indicator
- Disabled state clearly visible
============================================ */
.button {
/* Base button styles */
padding: var(--space-3) var(--space-6);
border: none;
border-radius: var(--radius-md);
font-weight: 600;
cursor: pointer;
transition: all var(--transition-base);
/* Accessibility: Focus indicator */
&:focus {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
}
/* TODO: Add button--outline variant */
/* FIXME: Focus indicator not visible on dark backgrounds */
/* HACK: Using margin-top instead of proper grid gap for IE11 */
/* NOTE: This component requires Font Awesome icons */
Version Control
Best practices for CSS in Git workflows.
# .gitignore for CSS projects
node_modules/
dist/
build/
*.css.map
.sass-cache/
.cache/
# Commit message format
# type(scope): description
# Examples:
# feat(button): add outline variant
# fix(nav): correct mobile menu alignment
# style(card): improve spacing consistency
# refactor(forms): migrate to BEM naming
# perf(critical): reduce inline CSS size
# docs(readme): add CSS architecture guide
# Code review checklist:
# ✓ Follows naming convention (BEM)
# ✓ No !important (unless justified)
# ✓ Mobile-first media queries
# ✓ Proper indentation (2 spaces)
# ✓ Color contrast meets WCAG AA
# ✓ Focus states for interactive elements
# ✓ No browser-specific hacks without comments
# ✓ CSS validated (no errors)
# ✓ Performance considered (no expensive properties)
# ✓ Documentation for complex code
Practice Exercises
- Refactor Project: Take an existing project and refactor it to use BEM naming consistently.
- Design Tokens: Create a comprehensive design token system with colors, spacing, and typography.
- Mobile-First: Convert desktop-first CSS to mobile-first approach with min-width media queries.
- Reduce Specificity: Audit CSS for high-specificity selectors and simplify them.
- Documentation: Document a complex component with usage examples and accessibility notes.
- Use BEM or similar naming convention for consistency
- Organize CSS files logically with clear folder structure
- Apply DRY principle with variables and base classes
- Design mobile-first with min-width media queries
- Avoid !important; manage specificity properly
- Keep selectors simple and limit nesting depth
- Use design tokens for centralized design decisions
- Document complex code for team collaboration
What's Next?
You've completed the CSS Learning Path! Review Performance & Architecture and Validation & Tools to reinforce your knowledge, or explore advanced CSS topics.
Validation & Tools
Debug, validate, and maintain CSS with powerful development tools
Modern CSS development requires robust tooling for validation, debugging, and optimization. Learn to use W3C validators, browser DevTools, linters, PostCSS, Autoprefixer, and debugging techniques to write error-free, cross-browser compatible CSS.
W3C CSS Validator
Validate CSS syntax and compliance with W3C specifications.
/* Valid CSS */
.valid-example {
display: flex;
gap: 1rem;
color: #3b82f6;
margin: 10px 20px;
}
/* Common validation errors */
/* ERROR: Missing semicolon */
.error1 {
color: red
font-size: 16px;
}
/* ERROR: Invalid property value */
.error2 {
display: flexbox; /* Should be "flex" */
}
/* ERROR: Typo in property name */
.error3 {
colr: blue; /* Should be "color" */
}
/* ERROR: Invalid color format */
.error4 {
background: #gg0000; /* Invalid hex */
}
/* WARNING: Vendor prefix without standard */
.warning1 {
-webkit-box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/* Missing standard box-shadow */
}
/* CORRECTED */
.corrected {
-webkit-box-shadow: 0 2px 4px rgba(0,0,0,0.1);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Use W3C Validator at: https://jigsaw.w3.org/css-validator/ */
/* Methods:
* 1. By URI - Validate live website
* 2. By file upload - Validate local CSS file
* 3. By direct input - Paste CSS code
*/
Browser DevTools
Leverage built-in browser debugging tools for CSS inspection.
/* Inspect Element (F12 or Right-click → Inspect) */
/* 1. Elements Panel - Live CSS editing */
.element {
/* Hover over values to see color swatches */
color: #3b82f6;
/* Click checkbox to toggle properties */
display: flex;
/* Edit values inline and see changes instantly */
padding: 1rem;
}
/* 2. Computed Panel - See final computed values */
/* Shows which styles won specificity battle */
/* Displays inherited values */
/* Box model visualization */
/* 3. Coverage Tool (Chrome DevTools → More Tools → Coverage) */
/* Identifies unused CSS rules */
/* Shows percentage of used vs unused code */
/* 4. Rendering Panel - Performance debugging */
/* Paint flashing - Shows repainted areas */
/* Layout shift regions - CLS debugging */
/* Frame rendering stats - FPS monitoring */
/* 5. Performance Panel - Profile CSS performance */
/* Record page interactions */
/* Identify style recalculation bottlenecks */
/* Measure layout and paint times */
/* 6. Animations Panel */
/* Visualize CSS animations and transitions */
/* Adjust timing functions visually */
/* Replay animations at different speeds */
CSS Linters
Catch errors and enforce code quality standards automatically.
// .stylelintrc.json
{
"extends": "stylelint-config-standard",
"rules": {
"indentation": 2,
"color-hex-case": "lower",
"color-hex-length": "short",
"selector-class-pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$",
"declaration-block-no-duplicate-properties": true,
"no-descending-specificity": true,
"max-nesting-depth": 3,
"declaration-no-important": true,
"unit-allowed-list": ["px", "rem", "em", "%", "vh", "vw", "deg", "s", "ms"]
}
}
/* Stylelint will catch these issues: */
/* ERROR: Invalid hex case */
.error1 {
color: #3B82F6; /* Should be lowercase */
}
/* ERROR: Long hex when short available */
.error2 {
color: #ffffff; /* Should be #fff */
}
/* ERROR: Duplicate property */
.error3 {
display: block;
display: flex; /* Duplicate property */
}
/* ERROR: !important usage */
.error4 {
color: red !important; /* Avoid !important */
}
/* ERROR: Too much nesting */
.error5 .child .grandchild .great-grandchild {
/* Exceeds max-nesting-depth: 3 */
}
/* FIXED VERSION */
.fixed1 {
color: #3b82f6;
}
.fixed2 {
color: #fff;
}
.fixed3 {
display: flex; /* Only one declaration */
}
.fixed4 {
color: red; /* No !important */
}
.fixed5__child {
/* Use BEM instead of deep nesting */
}
PostCSS & Autoprefixer
Transform and enhance CSS with JavaScript-based tools.
/* Input CSS (modern syntax) */
.example {
display: flex;
user-select: none;
backdrop-filter: blur(10px);
&:hover {
opacity: 0.8;
}
}
/* Output CSS (autoprefixed + transpiled) */
.example {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
}
.example:hover {
opacity: 0.8;
}
/* PostCSS Plugins Benefits:
* - Autoprefixer: Automatic vendor prefixes
* - cssnano: Minification and optimization
* - postcss-preset-env: Use future CSS today
* - postcss-import: @import resolution
* - postcss-nested: Sass-like nesting
*/
Common Debugging Techniques
Strategies for identifying and fixing CSS issues.
/* Technique 1: Outline everything */
* {
outline: 1px solid red !important;
}
/* Quickly visualize layout and spacing issues */
/* Technique 2: Simplify selectors */
/* Complex selector causing issues? */
.nav .menu > li:nth-child(2) .dropdown .link {
color: blue;
}
/* Simplify to test */
.test {
color: blue;
}
/* Technique 3: Binary search - Comment out half */
.component {
display: flex;
/* flex-direction: column; */
/* gap: 1rem; */
/* padding: 2rem; */
background: white;
/* border-radius: 8px; */
}
/* Uncomment half at a time to isolate issue */
/* Technique 4: Check specificity */
/* Use browser DevTools Computed panel */
/* See which rule is winning */
/* Lower specificity: */
.button { color: blue; } /* Specificity: 0,1,0 */
/* Higher specificity: */
.nav .button { color: red; } /* Specificity: 0,2,0 */
/* Technique 5: Validate color contrast */
/* Use DevTools color picker */
.text {
color: #6b7280; /* Check contrast ratio */
background: #ffffff;
/* DevTools shows ratio like 4.54:1 */
}
/* Technique 6: Test responsive breakpoints */
@media(max-width: 768px) {
.responsive {
/* Add background to verify media query works */
background: red;
}
}
/* Technique 7: Console.log computed styles */
/* See JavaScript example below */
CSS Coverage Analysis
Identify and remove unused CSS to reduce file size.
/* Chrome DevTools Coverage (Cmd+Shift+P → Coverage) */
/* Shows:
* - Total CSS bytes
* - Unused bytes (red)
* - Used bytes (green)
* - Percentage utilization
*/
/* PurgeCSS configuration */
Version Control & Code Review
Best practices for managing CSS in teams.
# .gitignore for CSS projects
node_modules/
dist/
*.css.map
.sass-cache/
# Git pre-commit hooks
# Run linter before commit
npx stylelint "**/*.css"
# Review checklist:
# ✓ No !important (unless necessary)
# ✓ No inline styles in HTML
# ✓ Proper BEM naming
# ✓ Mobile-first media queries
# ✓ Accessibility (focus states, contrast)
# ✓ Performance (avoid expensive properties)
# ✓ Browser support (use Autoprefixer)
# ✓ No duplicate selectors
# ✓ Consistent spacing/indentation
Practice Exercises
- W3C Validation: Validate a CSS file using W3C Validator and fix all errors/warnings.
- DevTools Mastery: Use Coverage tool to identify and remove unused CSS from a project.
- Linter Setup: Configure Stylelint with custom rules and fix all linting errors.
- PostCSS Pipeline: Set up PostCSS with Autoprefixer and cssnano, verify output.
- Debug Challenge: Given a broken layout, use DevTools to identify and fix CSS issues.
- Use W3C CSS Validator to catch syntax errors early
- Master browser DevTools for live CSS debugging and inspection
- Implement Stylelint to enforce code quality standards
- Use PostCSS and Autoprefixer for cross-browser compatibility
- Analyze CSS coverage to remove unused styles
- Test across multiple browsers with @supports and fallbacks
What's Next?
Complete your CSS journey with Best Practices for comprehensive development guidelines, or revisit Performance & Architecture.
Last updated: February 2026