CSS DAY — day 1

On Thursday the 9th of June our front-end team attended CSS Day in Amsterdam. To hold on to the inspiring talks and techniques we wrote down our notes and some takeaways from this great first day:

.css-day {
    speakers: 7;
    date: "June 9";
    venue: Zuiderkerk; // Amsterdam, NL
    day: 1 of 2;

In And Out Of Style

— By Jeremy Keith

Jeremy Keith started off the day with an inspiring talk about the history of the World Wide Web, to better understand where we are today.

Technologies have changed a lot and humans are said to be resistant to change. This is where path dependence came into play: existing methods where used to maintain understanding and create a shared context. This is why standards matter: their real value is agreement.

How styling evolved

Keith mentioned the way how the methods of styling elements have changed over the years. Where we started with HTML styling elements (like <font>, <big>, <center>), separation of concerns quickly came into play. The first stylesheets don’t look the way they do now.

He talked about Rob Raisch, Pei Wei (who introduced nesting). And about how Håkon Wium Lie later joined forces with Bert Bos to create the CSS fundamentals as we know them today.

From a hacky past to a materially honest present

According to Keith CSS is simple, but not easy. In the past, to create the layouts we wanted, we started hacking: using images for gradients, border radiuses. Nowadays we have decent methods to create layout, like linear-gradient, border-radius, flexbox and grid. Dark mode media queries, accent-color etc. Tools, such as Sass and jQuery, pushed things forward, and these new standards ended up making tools like these obsolete.

“And kids, that's where CSS comes from” Jeremy Keith

The future

CSS is an ever evolving language where new features are being added all the time. Possible game changers:

@layer MDN

:scope MDN

What’s missing?

It’s still hard to style certain controls, like open state selects, datepickers or color pickers. To close the gap of things we still can’t do (well), have a look at this project: open-ui.org. The purpose of this project is to style and extend built-in controls (like datepickers, selects, color pickers etc). Web standards in the browser are the foundation to build upon.

Interop 2022

— By Rachel Andrew


Rachel Andrew talked about a cross browser effort called Interop 2022. Interoperable, in this context, means that CSS works the same way in different browsers. Cross browser styling used to be a hassle. However, today most things work pretty consistently. CSS is complicated, and CSS still has to allow that websites from 20 years ago still work.

The gap

New browser versions are being released very quickly, and so are new CSS features. However, there is a gap between landing the feature in the first browser and the other browsers that have to catch up.

Nowadays in some areas it’s still hard to create a decent cross browser styling. Different research results show that interoperably is still a big frustration.

The Interop Project

In 2021 Google started working on interoperability with other vendors to fix the top 5 browser compatibility issues. The project makes progress visible by showing how 15 key areas score per browser. The scores are calculated by Web Platform Tests. These tests are simple to write and a lot of them are currently missing. A way to contribute to the project is write these missing tests.

Feature support that is being realized because of Interop 2022

aspect-ratio Width and height ratio proportions.

.box {
    aspect-ratio: 16/9;

flexbox Added gap property.

.box {
    display: flex;
    gap: 1em;
    align-items: self-start;

self-start self-end: rtl ltr directions for a flow-relative alignment.

position: sticky Wasn’t behaving very well: sticky table headers weren’t working. Rewrite of the rendering engine in Chromium was needed, but now they are working.

New features

Cascade Layers

Feature to make working with the cascade easier. More on this in the talk from Bramus Van Damme.

Color Spaces and Functions

More available colors to use, later more on this in the talk of Chris Lilley. Color functions have been available within Sass for a while. Now they can be used in CSS as well. Functions like:

color: color-mix(in lch, red, blue);
color: color-contrast(wheat vs tan, sienna, #d2691e);
// Select list of of colors the color with the highest contrast to a specified single color


Contain styles so it will not be recalculated, this will optimize performance.

.item {
    contain: layout;


Creates a dialog/modal, including backdrop styles and a JS API to open/close the dialog.



accent-color The accent-color property in CSS is capable of re-tinting the accented color of form controls provided by the browser’s default styles with a custom color value.


overscroll-behavior and scroll-snap. More on this in one of tomorrow’s talks.


Yes, the long awaited subgrid. This will unlock a lot of layout possibilities. For example: We can have a full width area, but then we get nested items that we can align with other elements in the grid that is not its direct parent.

Viewport Units

Mobile devices do weird things with viewport units. Meet the following new units to be more flexible:

  • dvh: dynamic viewport height
  • lvh: largest viewport height
  • svh: smalled viewport height

If you want to influence what Interop 2023 will focus on, you can add issues on GitHub

Dynamic CSS Secrets

— By Lea Verou

Lea Verou took the audience on a wild journey on CSS variables. Lea noticed that in the State of the Web report a lot of people are still using custom properties in a very basic way. Most custom properties where set on the root. These were mostly used as constants.

Lea took us an impressive ride to show how how to take advantage of the reactivity.

As this was a such an interesting and fast paced talk, we think it’s best to have a look at her slides yourself.

The CSS Cascade, a deep dive

— By Bramus Van Damme

Bramus took a deep dive in how the cascade works. The CSS cascade is the algorithm that determines the winner from a set of competing declarations. There are multiple factors that determine the priority of a certain style.

It can be hard to figure out the specificity of certain style declarations. Especially when you use pseudo-classes such as :is(), :has(), :where() or :not(); These selectors select the same elements as traditional selectors, but the specificity is calculated differently.

A helpful tool to determine this is the Polypane CSS specifity calculateor. To figure out specifity in your codebase Bramus offers a NPM package.

introducing Cascade Layers

So, overriding styles can be hard. Especially when dealing with a reset.css that already has some very specific styles. Overriding can make things more complex, because where does it end? This is where Cascade Layers come into play.

@layer reset {
    ul[class] {
        margin: 0;
        padding: 0

@layer components {
    .nav {
        margin: 0 40px;

The first declared layer has lowest priority, in this example the styling of the component layer will be applied.

Cascade layers in-depth

  • Layer name resuse: you can reuse layer names, you’re not redeclaring, but appending.
  • Anonymous layers: layers do not need to have a name, and multiple anonymous layers will not append but redeclare.
  • @layer statement allows to predefine a certain layer order. You can declare this at the very top of your stylesheet:
@layer reset, base, components, utilities`;
  • External CSS files: you can assign layers when importing external CSS files:
@import url(reset.css) layer(reset); @import url(carousel.css)

Also when using the element, but make sure to use this value in the media attribute for improved browser support

  • Unlayered styles: regular styles outside of layers have the ultimate priority.
  • Layered nesting: yes, you can nest layers:
@layer theme {
    @layer light {
    @layer dark {

@layer theme.dark {
    :root {
        --contrast-color: red;
  • Old browsers: the support isn’t great yet.
    Edit: Whoops, Bramus luckily corrected us on this one: “Layers are supported in all modern browsers (thank you, #Interop2022) but older versions that dont understand layers will discard them. For those you’ll need the polyfill.”

Practical setup

In short, a pratical setup with layers could look like this:

@layer reset, thirdparty;

@import url(reset.css) layer(reset);
@import url(carousel.css) layer(thirdparty);

main {

Collaborating without Borders

— By Ana Ferreira

Collaborating without Borders: how to make remote work work.

Ana is working at Doist, the company that created Todoist and Twist. Doist works fully remote. Ana shares the challenges they face as a remote company.

Challenge 1: Trust

Trust is essential. Companies should create an environment of trust and create guidelines, such as:
don’t micromanage, let people choose their own work hours. Evaluate the work, and not the amount of hours. The amount of hours worked is not relevant if the work is done.

Challenge 2: Communication

Research of Wall Street Journal shows that professionals now spend more than 21.5 hours per week in meetings, an increase of 7.3 hours since the pandemic. Ana’s advice on this is: revert to asynchronous communication (if there is a SOS situation they will reach out through Telegram).

Most office workers never get an hour of uninterrupted work in a typical day (says research from Book Stolen Focus). If you are in focus mode, and interrupted, it will take 23 minutes on average to get back in the same state of focus.

Challenge 3: Empower

Employees don’t always have enough power to make decisions and move forward. At Doist they work in small disciplinary groups, squads that have the power to make decisions.

Challenge 4: Documentation

Documentation is key. Remember the decisions and the discussions leading up to these decisions, for future reference. For people who weren’t part of the project or to look back on. This information can also be of value to the marketing team, who might want to use the information in a press release. In short, when in doubt: add documentation.

Challenge 5: Humans first

Respect peoples time and well being. Being burned out or overworked is sometimes looked at as a badge of honor. We need to get rid of this toxic view, and work on trust, and bonding together (Doist is fond of retreats, work trips, and personal presentations). At Doist they like the employees to organize their work around their lives, instead of the other way around.

Escaping the sRGB Prison

— By Chris Lilley

Chris Lilley took the stage to give a very in-depth talk about color theory and the developments it went through. Basically, he states that on the web we are stuck within a prison of limited colors. Current possibilities are not enough to offer a wide range of colors.

The prison of sRGB

There are lots of color formats. And many type notations, such as hex, rgba(), hsl() etc. The problem is: all of these are inside the limited sRGB spectrum.

Off the web is the place where things were happening, film came up with projector 3 (P3) standard. This range is bigger than in sRGB. The web is falling behind.

using diplay-p3 in CSS color 4

There are new color functions to take advantage of a wider range of colors:


Inside the sRGB Gamut

color(display-p3 0.21. 0.56 0.74)
color(display-p3 0.21. 0.56 0.74 / 0.6)

Outside the sRGB gamut:

color(display-p3 0 1 0)
color(display-p3 )

Defensive CSS

Of course you have to be mindful of browser support and there are ways to take this into account:

@media (color-gamut: p3) {
    // is this a wide-gamut screen?
    color: color(display3 0.21 0.56 0.74);

@supports (background: color(display-p3 1 1 1)) {
    // is this syntax supported?
    color: color(display3 0.21 0.56 0.74);

Mixing colors

Mixing colors can be fun to create great gradients or pretty patterns.

color-mix(in oklab, teal 65%, olive)
color-mix(in oklab, teal 65%, olive 35%)

Colors to be mixed can be in any color space. However, Gamma encoded sRGB is a poor space for mixing, like all gradients we currently see on the web. So use the right color space when mixing colors. Oklab offers a nice progression, and is well suited for linear gradients.

Contrasting colors

A very useful color function is the color-contrast() function. You enter a base color and a list of possible color values and the browser will determine what color combination gives the best contrast.

--myAccent: $b22222;

color: color-contrast(wheat vs tan, sienna, var(--myAccent), #d2691e)
color: color-contrast(wheat vs tan, sienna, var(--myAccent), #d2691e to AA)
// WCAG2.1 contrast guidelines are used, to meet the specified target

Browser support

Full support is not there yet, but we’re looking forward to experiment with these nice new tools. This section is only a short summary of this amazing talk, definitely checkout the slides.

I pressed ⌘B - You wouldn’t believe what happened next

— By Marcin Wichary

Marcin Wichary from Figma concluded the day with a very fun talk about the struggles and challenges when working on the Figma app. For instance: there are so many font weight variants, and their names are sometimes vague or different names could mean the same thing. There are many font weights: light, thin, book, semibold / demibold. Also, what to do with all the different font origins (are they installed on the user’s computer or maybe included within Figma, or maybe both? What font should Figma prioritize?)

We can say quite a lot about this very fun talk, but we would highly recommend to watch this talk when it lands on Vimeo. You will literally be blown away once you find out what ⌘B does.

These were our notes for day 1 of CSS Day. See you tomorrow!

We welcome your feedback

We enjoy compliments, but you can totally shout at us for doing it wrong on our Twitter account 👋