Custom properties have been introduced as “variables” in the CSS Variables Module in 2012. Later, “variables” were renamed “custom properties“ which according to the CSS Spec will support “other things” than variable substitution.
These “other things” don’t seem to have happened until now. The module is still a candidate recommendation since 2015, though major browsers support it.
Custom properties can be used like usual CSS properties. They are defined by two leading dashes followed by an identifier of your choice and can be defined inside any CSS block:
.some-selector { --my-var: value; }
The value can be any expression that would be valid for a CSS property.
Custom properties take part in the cascade, i.e. they are inherited and can be used inside media query blocks. To use --my-var
as a variable you simply reference it in a value of another property:
.other-selector { background-color: var(--my-var); }
For a more exhaustive description of the “variable” usage look here: https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables
When you define your new custom property in CSS and don’t use it in a var()
expression, nobody is going to listen. So no custom layout or behavior will arise from it. Of course, it is possible to retrieve the value of a custom property for a given element from JavaScript:
window.getComputedStyle(element).getPropertyValue("--my-var");
This is great but does not necessarily make sense. In JavaScript, you can program a custom behavior for elements directly, instead of defining a custom property for the given selector in CSS and then reading this property using the above code and programming the custom behavior based in the read value.
You could use media queries to create responsive behavior. The value read by getPropertyValue
would then depend on the current metrics of the browser. This can also be achieved in JavaScript directly, by querying the browser metrics directly in your code or by using matchMedia
to see what media queries currently apply.
When you are writing your own code, custom CSS properties are not much help. This is however very different if you understand them as an API to a framework that provides custom behavior. Here, the programmer of the behavior (framework) and the user are different people. So, the user wouldn’t necessarily want to dig into the code to modify the behavior.
Many frameworks today are controlled by CSS classes (e.g. Bootstrap or Bulma) or HTML attributes (Angular, Vue). Custom CSS properties are a 3rd way for specifying parameters and may prove to be a very efficient way to define responsive behavior.
In the next chapter, the possibilities of custom CSS properties are explained in the layJS framework example.
LayerJS is a framework to create animated layered user interfaces with simple HTML markup. It provides a universal concept where common UI pattern (menus, sliders, accordions, parallax, zooming) can simply be defined as dynamic, overlapping layers.
Its behavior can be controlled by HTML attributes or alternatively by the custom CSS properties described above. In the following chapter, we use this to create a menu which moves in from the side on desktops while fading in as fullscreen on mobile.
In layerJS everything happens in a “stage”. A stage is a viewport which defines the area where a thing should happen. In our case we want everything to happen right in the browser window, so we define the body as a stage.
We want the menu to appear on top of the main content, so we define two layers inside the stage, one for the menu and one for the content.
Within the menu layer we create a “frame” which contains the actual content of the menu and within the content layer we create a frame with our page content.
We don‘t want to show the menu initially we set the default frame of the menu layer to “!none”:
<body lj-type="stage"> <div id="lcontent" lj-type="layer"> <div id="home" lj-type="frame"> ... content ... </div> ... optional: more content frames </div> <div id="lmenu" lj-type="layer" lj-default-frame="!none"> <div id="menu" lj-type="frame"> ... menu items </div> </div> </div>
Now we define the behavior of our UI. The behavior is basically how the frames are fit/positioned into the stage and how this is animated. We chose to show the menu on the left side at full browser height with a fixed width. This is done by setting lj-fit-to
to responsive-height
. The transition is defined by lj-transition
:
#menu { --lj-fit-to: responsive-height; --lj-transition: left; width: 200px; }
To make this behavior responsive we simply define CSS clauses for mobile screens with different parameters — the menu should fill the whole screen and it should fade in:
@media (max-width: 600px) { #menu { --lj-fit-to: responsive; --lj-transition: fade; } }
You can find a live example here on JSBin. Click on “Menu” to open and close it. Make sure to resize the output part to see the responsive behavior.
This example shows how custom CSS properties can serve as a convenient method to control framework behavior in a responsive way. The biggest advantage is that the framework does not have to make any assumption about how responsiveness should work in a particular situation. The user will most likely work with a grid system or at least a set of breakpoints and the framework will seamlessly integrate into that concept.
layerJS in particular benefits from custom CSS properties. It provides a concept to build arbitrary user interfaces out of nested layers. It doesn’t directly implement responsive features but leaves the decision to the user on how the content of the layers should look on different devices.
With custom CSS properties the user can not only define the layout but also the behavior in a responsive way. For an explanation of the layerJS concept have a look at the animation on the project homepage. An easy introduction on how to build UIs with layerJS can be found here.
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowToast notifications are messages that appear on the screen to provide feedback to users. When users interact with the user […]
Deno’s features and built-in TypeScript support make it appealing for developers seeking a secure and streamlined development experience.
It can be difficult to choose between types and interfaces in TypeScript, but in this post, you’ll learn which to use in specific use cases.
This tutorial demonstrates how to build, integrate, and customize a bottom navigation bar in a Flutter app.