CSS Functions: A Field Guide
CSS is a language of values, and functions are how many of those values get computed or transformed. They plug into properties wherever a value is expected, and some, like calc(), even accept other functions as arguments.
Unlike in a language like JavaScript, you can’t author your own functions in CSS — they’re all provided by the spec. And rather than invisibly affecting program logic, CSS functions produce visual results: they control layout, paint filters, and shape how elements animate. The palette of available functions is broad and continues to grow as new modules land.
Everyday Value Helpers
Several functions are ubiquitous enough that they feel like core syntax.
url() points to external resources like images, fonts, and other stylesheets. Keep in mind that each url() declaration is another HTTP request, so it pays to be deliberate about what you load this way.
.el {
background: url(/images/image.jpg);
}
attr() reaches into the HTML and pulls an attribute’s content into the CSS, most commonly into the content property. It appears frequently in print stylesheets to display link URLs after link text, and it can also be used to show an image’s alt text in place of a broken image.
calc() is the workhorse for combining values. It takes two arguments and an operator (+, -, *, /), and—unlike Sass-style math—it allows mixing units, such as subtracting 6rem from 100%. Because it’s evaluated live, those percentages recalculate automatically when their context changes. It can also accept CSS custom properties as arguments for dynamic flexibility.
.thing {
width: calc(100% - 6rem);
}
Custom Properties and Their Functions
CSS custom properties have only one dedicated function, but it’s the mechanism that makes them work. var() looks up a custom property declared earlier in the document and applies its value:
html {
--color: orange;
}
p {
color: var(--color);
}
Combine var() with calc() and you can build powerful, updatable systems. A property like --ratio: 1.618 declared on the root can drive a modular type scale via line-height: calc(var(--ratio) * 1rem); change the property once and everything downstream adjusts. JavaScript’s setProperty method can also update custom properties in real time, allowing for dynamic changes without heavy code.
Working With Color
Color is one of the most function-heavy areas of CSS. The classic functions rgb() and rgba() describe colors via red, green, blue, and alpha components. rgba(251, 16, 16, 1) is the same red as the hex #fb1010; the alpha value of 1 makes it fully opaque. Deciding between rgb() and rgba() is now mostly a matter of style — the space-and-slash syntax in the Color Module Level 4 spec lets either function take an alpha value. In fact, both the old comma syntax and the newer rgb(251 16 16 / 1) syntax are valid.
hsl() and hsla() describe colors by hue, saturation, and lightness instead. The hue/saturation/lightness model is popular for programmatic color work: each channel is a numeric argument that can be a custom property, making it easy to build systematic color palettes.
The future brings more modern color functions — lab(), lch(), oklab(), oklch(), and hwb() — which use the space-separated format with an optional alpha slash.
Structural and Selector Functions
Pseudo-class selector functions give you a grammar for targeting elements by pattern instead of by class or ID.
:not()selects everything except what you pass it. Scoping it tightly — say, to a component modifier class instead of the entire document — keeps it from becoming dangerously broad.:nth-child()targets elements by their index among siblings. While it’s commonly used for striping tables or alternating items, it can express much more complex patterns. Combined with clever formulas, it’s capable of surprising feats.:nth-last-child()counts backward from the last sibling.:nth-of-type()matches elements of a given type, likeimg:nth-of-type(5)selecting the fifth image on a page.:nth-last-of-type()does the same but counts from the last matching element.
These pseudo-classes often prove that a thoughtful selector can do work you might otherwise reach for a JavaScript library to handle.
Under the spec’s “Logical Combinations” heading, functions like :is() and :where() group selector lists. Both accept multiple selectors as arguments; the difference is specificity. :is() takes on the specificity of the most specific selector it contains, while :where() is always zero. That makes :where() handy for styles you want to be easily overridden, particularly in integrations where you have limited control over the stylesheet.
:has() takes relational selection one step further. As a relational pseudo-class, it targets an element that contains another matching element — for example, a:has(> img) selects any link that directly contains an image. The current proposal restricts its use to JavaScript so the browser only evaluates it when triggered by conditional logic, which keeps performance costs down.
Animation and Motion
Animation adds a temporal dimension to CSS, and the functions that control it manage change over time.
The cubic-bezier() function replaces keyword easings like ease or linear with your own curve, giving fine control over an animation’s acceleration and deceleration.
path() is paired with the offset-path property. It lets you define an SVG path for an element to follow, which is the foundation of CSS motion-path animation. It may eventually work with clip-path as well. Both Michelle Barker and Dan Wilson have written excellent deep dives on this technique.
steps() sets animation easing to discrete jumps rather than smooth interpolation, giving you jittery, frame-by-frame effects or stepped transitions.
Several transform functions apply sizing and distortion along axes. These functions are special in that they can only be used with the transform property:
- Scaling functions —
scale(),scaleX(),scaleY(),scaleZ(), andscale3d()— increase or decrease size on one or more axes. - Translate functions —
translate(),translateX(),translateY(),translateZ(), andtranslate3d()— reposition an element. perspective()adjusts how an object appears to project out from its background.- Rotate functions —
rotate(),rotateX(),rotateY(),rotateZ(), androtate3d()— spin an element about its axes. - Skew functions —
skew(),skewX(), andskewY()— apply a distortion that increases with distance and angle.
.double {
transform: scale(2);
}
Given the potential performance cost of complex animation, be mindful of your users’ hardware. The will-change property primes the browser for changes, and the update media feature lets you avoid animation on devices with slow refresh rates.
Filter Effects
The CSS filter property accepts its own special subset of functions, mimicking Photoshop-style effects. Filter functions let you do everything from subtle image tweaks to wild Instagram-like looks.
brightness()adjusts how brightly something displays. Low values wash it in shadow; high values blow it out like overexposure.blur()applies a Gaussian blur.contrast()adjusts the difference between a subject’s lightest and darkest parts.grayscale()strips color information. It isn’t all-or-nothing — applying partial grayscale can make an image look weathered. One clever use is lightly desaturating images in dark mode to reduce eye strain.invert()flips colors like a photo negative. Inside aninverted-colorsmedia query, it can undo unwanted inversion of images and video so they look correct regardless of user preference.opacity()sets how much background shows through an element. At 0%, it’s invisible but still part of the DOM — removing an element still calls for thehiddenattribute.saturate()increases or decreases color intensity.sepia()gives anything an old-timey, sepia-toned look.drop-shadow()applies a shadow to an element’s rendered shape — unlikebox-shadow, which is bound by the box model.hue-rotate()shifts the hue of every pixel by the angle you give it, creating a sometimes-psychedelic effect on colorful subjects.
filter() also imports SVG filters, which enable specialized distortions well beyond what single functions can do.
Responsive and Sizing Helpers
Comparison functions make it easier to encode fluid sizing logic directly in CSS.
clamp() accepts a minimum, a preferred, and a maximum value. The element uses the preferred value so long as it stays within the bounds. This enables so-called CSS locks — responsive type that scales with the viewport but never becomes unreadably small or absurdly large.
min() and max() round out the trio: they evaluate a list of values and return the smallest or largest.
Gradients, Grids, Shapes, and Beyond
Gradient functions describe smooth transitions between colors. linear-gradient() paints along a straight line — which you can angle — while radial-gradient() radiates from a center point; both have repeating- variants. More recently, conic-gradient() rotates the color stop around a circle, enabling things like donut charts, though support remains spotty.
CSS Grid introduced focused track functions:
repeat()loop through column or row patterns. It’s useful when the framework knows the track count in advance, or when you want the number to be dynamic.minmax()declares minimum and maximum track sizes.fit-content()lets a track grow up to a maximum size but clamp at the content’s preferred size.
Shape functions work exclusively with the clip-path property for masking content:
circle()creates a circular mask with configurable radius and position.ellipse()draws an oblong version of circle().polygon()accepts an arbitrary set of points. An optionalfill-ruleargument determines which part of the polygon is registered as “inside.”inset()masks out a rectangle within the element.
Less Common Utilities
Some functions serve narrower niches but are valuable once you need them.
counter() and counters() control the generated “numbers” that browsers place before list items. Using the ::marker pseudo-element selector with the content property lets you restyle ordered and nested lists.
element() is a bit like camera feedback: it accepts the ID of another element and creates an “image” out of its rendered appearance, to which you can apply further CSS like filters. It has real support caveats, but in browsers that handle it, it’s a powerful trick — for example, building a minimap of a long article.
image-set() takes a list of image paths, letting the browser pick the best candidate based on screen characteristics and connection quality — the background-image analog of srcset.
::slotted() is a pseudo-element for Web Components; everything placed into a slot inside an HTML template is targeted through this function.
Spec-Track and Experimental Functions
CSS also has functions that are still working their way through the spec process. Some exist behind flags in Firefox Nightly or Chrome Canary, while others are only known via W3C discussion.
annotation()enables Alternate Annotation Forms — special characters often outlined by circles or squares — but only for typefaces that include them.cross-fade()will blend two or more background images.dir()flips reading orientation, and only Firefox supports it so far; Chromium users can get the same effect with the attribute selector[dir="rtl"].env()exposes environment variables about the device. It became known for helping sites adapt to the iPhone X’s notch. If you use it, the intent is making layouts robust to hardware constraints — not user-agent sniffing.image()will choose a static image fromurl(), or even a dynamically drawn gradient orelement()result.- Trigonometry and advanced math functions —
sin(),cos(),tan(),acos(),asin(),atan(),atan2(),sqrt(),hypot(), andpow()— are on the way for calculations, with clear potential for animation work. :host()and:host-context()work with the Shadow DOM for component-based styling.:nth-col()and:nth-last-col()target columns in a grid, including implicit ones.symbols()lets you define custom list bullet characters, provided the glyphs are in your font.
Functions You Shouldn’t Use
Several older or more specialized CSS functions are marked for depreciation and should be avoided in new and ongoing projects alike.
matrix()andmatrix3d()were supplanted by the more intuitive scale, translate, rotate, and skew functions.rect()was a companion to the deprecatedclipproperty; modern projects useclip-pathinstead.target-counter(),target-counters(), andtarget-text()were aimed at styling fragment URLs for paged media.- Typography functions like
character-variant(),styleset(),stylistic(),ornaments(), andswash()activate advanced font features but should be avoided in favor of the more thoroughly supportedfont-feature-settingsproperty. Use a font inspection tool to find out whether a typeface actually contains these glyph variants before going down this road. format()can hint at a font’s format inside aurl(), which prevents the browser from downloading fonts it can’t decode.leader()would generate dot-leader patterns — the dots between a menu item and its price — but it never gained traction, although workarounds exist withcontent.local()points to a font installed on the device itself, but relying on manual font installation is risky, and it’s smart to always specify fallbacks.



