🧮 Calc & Functions

Mathematical CSS Functions

CSS Mathematical Functions

Perform calculations and create dynamic values in CSS. These functions enable responsive designs and complex layouts without JavaScript.

💻 calc() Function

/* Basic calculations */
.element {
    width: calc(100% - 50px);
    height: calc(100vh - 80px);
    margin: calc(10px + 5px);
}

/* Operators: + - * / */
.box {
    width: calc(50% - 20px);        /* Subtraction */
    padding: calc(10px + 5px);      /* Addition */
    font-size: calc(16px * 1.5);    /* Multiplication */
    line-height: calc(24px / 16px); /* Division */
}

/* Mix units */
.mixed {
    width: calc(100% - 100px);
    padding: calc(2em + 10px);
    margin: calc(50% - 2rem);
}

/* Nested calc */
.nested {
    width: calc(100% - calc(20px * 2));
}

/* With CSS variables */
:root {
    --spacing: 20px;
    --multiplier: 2;
}

.dynamic {
    padding: calc(var(--spacing) * var(--multiplier));
    width: calc(100% - var(--spacing) * 2);
}

/* Examples */
/* Full width minus sidebar */
.content {
    width: calc(100% - 250px);
}

/* Viewport height minus header and footer */
.main {
    min-height: calc(100vh - 60px - 80px);
}

/* Center with calc */
.centered {
    position: absolute;
    left: calc(50% - 100px);  /* 100px = half of element width */
    top: calc(50% - 50px);
}

📏 min(), max(), clamp()

min() - Smallest Value

/* Use smallest value */
.element {
    width: min(100%, 600px);
    /* Width is 100% OR 600px, whichever is smaller */
}

/* Multiple values */
.box {
    width: min(100%, 600px, 50vw);
    /* Smallest of: 100%, 600px, or 50vw */
}

/* Responsive padding */
.container {
    padding: min(5%, 50px);
    /* 5% on large screens, max 50px */
}

/* Font size limit */
.text {
    font-size: min(5vw, 24px);
    /* Scales with viewport but never exceeds 24px */
}

max() - Largest Value

/* Use largest value */
.element {
    width: max(200px, 50%);
    /* Width is 200px OR 50%, whichever is larger */
}

/* Minimum width guarantee */
.card {
    width: max(300px, 25%);
    /* Never smaller than 300px */
}

/* Responsive minimum height */
.section {
    min-height: max(400px, 50vh);
}

/* Minimum font size */
.text {
    font-size: max(16px, 1vw);
    /* Never smaller than 16px for readability */
}

clamp() - Bounded Value

/* clamp(minimum, preferred, maximum) */
.element {
    width: clamp(200px, 50%, 800px);
    /* min: 200px, preferred: 50%, max: 800px */
}

/* Fluid typography */
.heading {
    font-size: clamp(1.5rem, 5vw, 3rem);
    /* min: 1.5rem, scales with viewport, max: 3rem */
}

body {
    font-size: clamp(1rem, 2.5vw, 1.25rem);
    /* Fluid text size between 16px and 20px */
}

/* Responsive padding */
.container {
    padding: clamp(1rem, 5vw, 3rem);
}

/* Responsive spacing */
.section {
    margin-bottom: clamp(2rem, 8vw, 6rem);
}

/* Line length control */
.text-content {
    max-width: clamp(45ch, 80%, 75ch);
    /* Optimal line length: 45-75 characters */
}

/* Gap in grid */
.grid {
    gap: clamp(1rem, 3vw, 2rem);
}

🎯 Comparison Functions

/* min() for responsive design */
.responsive-width {
    width: min(90%, 1200px);
    /* 90% of viewport but never more than 1200px */
}

/* max() for minimum sizes */
.card {
    width: max(300px, 33.333%);
    /* At least 300px wide, even on small screens */
}

/* clamp() for fluid scaling */
h1 {
    font-size: clamp(2rem, 5vw + 1rem, 4rem);
    /* Scales smoothly between 2rem and 4rem */
}

/* Combine with calc() */
.complex {
    width: clamp(
        200px,
        calc(50% - 20px),
        600px
    );
}

/* Container with constraints */
.container {
    width: min(100% - 40px, 1200px);
    margin: 0 auto;
}

🔢 Mathematical Functions

Trigonometric Functions

/* sin() - Sine */
.element {
    transform: rotate(sin(45deg));
}

/* cos() - Cosine */
.element {
    transform: translateX(cos(60deg) * 100px);
}

/* tan() - Tangent */
.element {
    height: calc(100px * tan(45deg));
}

/* asin(), acos(), atan() - Inverse functions */
.angle {
    transform: rotate(asin(0.5));
    transform: rotate(acos(0.5));
    transform: rotate(atan(1));
}

/* atan2() - Two-argument arctangent */
.element {
    transform: rotate(atan2(1, 1));  /* 45deg */
}

Exponential Functions

/* pow() - Power */
.element {
    width: calc(pow(2, 3) * 10px);  /* 2^3 * 10px = 80px */
}

/* sqrt() - Square root */
.element {
    width: calc(sqrt(16) * 20px);  /* 4 * 20px = 80px */
}

/* hypot() - Hypotenuse */
.element {
    width: calc(hypot(3, 4) * 10px);  /* 5 * 10px = 50px */
}

/* log() - Logarithm */
.element {
    opacity: calc(log(10));
}

/* exp() - Exponential */
.element {
    transform: scale(exp(1));  /* e ≈ 2.718 */
}

Sign-Related Functions

/* abs() - Absolute value */
.element {
    margin: calc(abs(-20px));  /* 20px */
}

/* sign() - Sign of number */
.element {
    --value: -5;
    transform: translateX(calc(sign(var(--value)) * 100px));
    /* -1 * 100px = -100px */
}

/* Round functions */
/* round() - Round to nearest */
.element {
    width: calc(round(15.7px));  /* 16px */
}

/* mod() - Modulo */
.element {
    width: calc(mod(17px, 5px));  /* 2px */
}

/* rem() - Remainder */
.element {
    width: calc(rem(17px, 5px));  /* 2px */
}

🎨 Color Functions

/* rgb() and rgba() */
.color-rgb {
    background: rgb(255, 0, 0);
    background: rgba(255, 0, 0, 0.5);
}

/* hsl() and hsla() */
.color-hsl {
    background: hsl(240, 100%, 50%);  /* Blue */
    background: hsla(240, 100%, 50%, 0.5);
}

/* hwb() - Hue, Whiteness, Blackness */
.color-hwb {
    background: hwb(240 0% 0%);  /* Pure blue */
    background: hwb(240 20% 0%);  /* Lighter blue */
}

/* lab() - Lab color space */
.color-lab {
    background: lab(50% 0 0);  /* Mid gray */
}

/* lch() - Lightness, Chroma, Hue */
.color-lch {
    background: lch(50% 50 240);
}

/* color-mix() - Mix two colors */
.mixed {
    background: color-mix(in srgb, red 50%, blue);
    /* 50% red, 50% blue */
}

/* Relative colors (modern) */
.relative {
    --base-color: blue;
    background: rgb(from var(--base-color) r g b / 50%);
}

🎯 Practical Examples

/* Responsive container */
.container {
    width: min(100% - 40px, 1200px);
    margin: 0 auto;
    padding: clamp(1rem, 5vw, 3rem);
}

/* Fluid typography system */
:root {
    --font-size-sm: clamp(0.875rem, 1vw, 1rem);
    --font-size-base: clamp(1rem, 2vw, 1.125rem);
    --font-size-lg: clamp(1.125rem, 3vw, 1.5rem);
    --font-size-xl: clamp(1.5rem, 4vw, 2rem);
    --font-size-2xl: clamp(2rem, 5vw, 3rem);
    --font-size-3xl: clamp(2.5rem, 6vw, 4rem);
}

h1 { font-size: var(--font-size-3xl); }
h2 { font-size: var(--font-size-2xl); }
h3 { font-size: var(--font-size-xl); }

/* Responsive grid with minimum item width */
.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
    gap: clamp(1rem, 3vw, 2rem);
}

/* Full-height layout with fixed header */
.layout {
    display: grid;
    grid-template-rows: auto 1fr auto;
    min-height: 100vh;
}

.header {
    height: 60px;
}

.main {
    min-height: calc(100vh - 60px - 80px);
}

.footer {
    height: 80px;
}

/* Sidebar layout */
.page {
    display: grid;
    grid-template-columns: minmax(200px, 250px) 1fr;
    gap: clamp(1rem, 3vw, 2rem);
}

@media (max-width: 768px) {
    .page {
        grid-template-columns: 1fr;
    }
}

/* Card grid with constraints */
.cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(clamp(250px, 30%, 350px), 1fr));
    gap: clamp(1rem, 2vw, 2rem);
}

/* Responsive spacing scale */
:root {
    --space-xs: clamp(0.25rem, 1vw, 0.5rem);
    --space-sm: clamp(0.5rem, 2vw, 1rem);
    --space-md: clamp(1rem, 3vw, 1.5rem);
    --space-lg: clamp(1.5rem, 4vw, 2rem);
    --space-xl: clamp(2rem, 5vw, 3rem);
    --space-2xl: clamp(3rem, 6vw, 4rem);
}

.section {
    padding: var(--space-xl) var(--space-md);
    margin-bottom: var(--space-2xl);
}

/* Aspect ratio with calc */
.aspect-16-9 {
    height: 0;
    padding-bottom: calc(9 / 16 * 100%);
    position: relative;
}

.aspect-16-9 > * {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

/* Dynamic columns based on container width */
.dynamic-columns {
    column-count: max(1, min(4, calc((100% - 300px) / 300px)));
    column-gap: clamp(1rem, 3vw, 2rem);
}

/* Button with responsive padding */
.button {
    padding: clamp(0.5rem, 2vw, 1rem) clamp(1rem, 4vw, 2rem);
    font-size: clamp(0.875rem, 2vw, 1rem);
}

/* Responsive border radius */
.card {
    border-radius: clamp(8px, 1vw, 16px);
}

/* Optimal line length */
.text-content {
    max-width: min(65ch, 100%);
    margin: 0 auto;
}

/* Navigation with flexible spacing */
nav {
    display: flex;
    gap: clamp(1rem, 3vw, 2rem);
    padding: clamp(0.5rem, 2vw, 1rem);
}

/* Hero section height */
.hero {
    min-height: clamp(400px, 60vh, 800px);
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Responsive icon size */
.icon {
    width: clamp(20px, 5vw, 40px);
    height: clamp(20px, 5vw, 40px);
}

/* Form field spacing */
.form-field {
    margin-bottom: clamp(1rem, 3vw, 1.5rem);
}

.form-field input {
    padding: clamp(0.5rem, 2vw, 0.75rem);
    font-size: clamp(0.875rem, 2vw, 1rem);
}

/* Modal width constraints */
.modal {
    width: clamp(300px, 90vw, 600px);
    padding: clamp(1rem, 4vw, 2rem);
}

/* Gallery item size */
.gallery-item {
    width: clamp(150px, calc(33.333% - 20px), 300px);
    height: clamp(150px, 25vw, 300px);
}

/* Footer with minimum height */
.footer {
    min-height: max(100px, 10vh);
    padding: clamp(1rem, 3vw, 2rem);
}

💡 Best Practices

/* 1. Use clamp() for fluid typography */
/* Good - scales smoothly */
h1 {
    font-size: clamp(2rem, 5vw, 4rem);
}

/* Bad - abrupt changes */
h1 {
    font-size: 2rem;
}
@media (min-width: 768px) {
    h1 { font-size: 4rem; }
}

/* 2. Prefer min() for responsive containers */
.container {
    width: min(100% - 2rem, 1200px);
    margin: 0 auto;
}

/* 3. Use max() for minimum sizes */
.button {
    min-width: max(120px, 20%);
}

/* 4. Always provide fallbacks for older browsers */
.element {
    width: 50%;  /* Fallback */
    width: clamp(200px, 50%, 800px);
}

/* 5. Use calc() with CSS variables */
:root {
    --header-height: 60px;
    --footer-height: 80px;
}

.content {
    min-height: calc(100vh - var(--header-height) - var(--footer-height));
}

/* 6. Be mindful of performance */
/* Expensive (recalculates on every change) */
.expensive {
    width: calc(100vw - 100%);
}

/* Better (static calculation) */
.better {
    width: calc(100% - 100px);
}

/* 7. Use appropriate units */
/* Good - mixing compatible units */
.element {
    width: calc(100% - 50px);
}

/* Bad - incompatible for some calculations */
.element {
    width: calc(100% * 50px);  /* Doesn't work */
}

/* 8. Add spacing in calc() */
/* Good - readable */
.element {
    width: calc(100% - 50px);
}

/* Bad - hard to read */
.element {
    width: calc(100%-50px);
}

🎯 Key Takeaways