For years, front-end developers have longed for native functions / mixins in CSS—something like what Sass, Less, or Stylus provide, but built-in. Recently, a new draft proposal for CSS custom functions has gained traction. Una Kravets highlighted several early uses (negation, opacity, fluid typography), including a “layout sidebar” pattern. The idea is to wrap responsive logic (e.g. media queries) inside the function so that when you call --layout-sidebar()
, it returns different layout values depending on viewport size.
In other words, instead of manually writing media queries for your grid template columns every time, you can “abstract” that into a CSS function. The approach is still experimental (only Chrome currently supports it), but it offers a glimpse of where CSS might go. In this tutorial, I’ll walk you through how --layout-sidebar()
works, how to adapt it, and a live example you can try.
How --layout-sidebar()
Works
The idea behind --layout-sidebar()
is simple: provide a two-column layout where on small viewports, both sidebar and main content collapse to one column (i.e. sidebar takes full width), but when the viewport is wider, the sidebar gets a fixed width (or custom width), and the main content takes the remaining space.
@function --layout-sidebar(--sidebar-width: 20ch) {
result: 1fr;
@media (width > 640px) {
result: var(--sidebar-width) auto;
}
}
.layout {
display: grid;
grid-template-columns: --layout-sidebar();
}
Let me explain it line by line:
@function --layout-sidebar(--sidebar-width: 20ch) { … }
defines a custom CSS function named--layout-sidebar
, taking one optional parameter--sidebar-width
with default20ch
.- Inside, the first line
result: 1fr;
sets the default return if no media query overrides it. This ensures on narrow viewports, the grid template will be1fr
(i.e. one flexible column). - Then the
@media (width > 640px)
block overrides the function’sresult
tovar(--sidebar-width) auto
. That means: for viewports wider than 640px, the layout will use two columns — the first is the sidebar width (from the parameter or default), and the second isauto
, which stretches to fill the rest (i.e. main content). - Finally,
.layout { display: grid; grid-template-columns: --layout-sidebar(); }
uses the function call. On small viewports, it becomesgrid-template-columns: 1fr;
(i.e. single column). On large ones,grid-template-columns: 20ch auto;
(or the provided width).
This decouples responsive logic into a single reusable function. If in future you want two breakpoints or more complex branching, you could nest additional media queries inside the function.
One caveat: because CSS functions and mixins (as proposed) are still under development, browser support is extremely limited. Also note that while custom properties (CSS variables) are broadly supported, you still cannot use var()
inside media query conditions (you can use it inside values, but not in @media
itself). The new custom function syntax sidesteps that limitation by allowing conditional branching inside the function.
Extending & Adapting the Pattern
Here are some ways you might adapt or extend --layout-sidebar()
for real-world use:
- Change the breakpoint: Instead of
640px
, pick something likemin-width: 768px
or use@media (min-width: ...)
so it reads more conventionally. - Support multiple breakpoints: You might inside the function do something like:
@media (width > 640px) { result: var(--sidebar-width) auto; } @media (width > 1024px) { result: var(--sidebar-width) 2fr 1fr; /* or some 3-column layout */ }
- Use different units: Instead of
ch
, you might userem
,%
,px
or even a CSS variable you define globally (e.g.--sidebar-desired-width
). - Fallback for unsupported browsers: Provide a more traditional CSS fallback (e.g. explicit
@media
rules) before or after the function call, so browsers that don’t understand@function
still work. - Combine with
grid-template-areas
or explicit named items to place sidebar and main region. - Animate or transition: Because grid template columns are animatable, you could animate the shift from single to two-column layout (though watch complexity).
Live Example
Here’s a minimal HTML + CSS you can play with in CodePen. It uses the --layout-sidebar()
approach with fallback.
See the Pen How –layout-sidebar() Works by Alex Ivanovs (@stackdiary) on CodePen.
In browsers that do not support the new @function
, the fallback media-query–based definitions ensure the layout still works.
In browsers that do support @function
, the --layout-sidebar()
call takes effect, overriding the fallback.
The --layout-sidebar()
pattern shows an elegant future direction: bundling responsive layout logic into CSS-native reusable functions. You write one call instead of repeating media queries across components. However, this is still in experimental territory:
- Browser support is extremely limited (primarily Chrome for now).
- You must provide fallbacks if you expect broad compatibility.
- Complex branching or nested layouts may bloat the function, so balance clarity vs flexibility.