4 min read

2023 State of CSS

Yesterday was Google I/O and the updates to the the web platform caught my attention, specifically those pertaining to CSS. This prompted me to write this article, reflecting on the changes over the years and how its advancements contrast with my experiences using TailwindCSS over the last few years.

I've been almost exclusively Tailwind for about 3 years now so I've been out of the loop with specific CSS updates.

Native nesting

This brings me back to my SASS days which I had been using since the beginning of my career 10 years ago. It's crazy that this is perfectly shippable CSS now in 2023 🤯 with any pre/post processing.

.card {
  position: relative;
  & h2 {
    font-weight: 500;
  & p {
    margin: .5em 0;

Colour mixing

This is awesome. You can now mix colours in CSS. This is great for creating a colour scheme for your app from a single brand colour. Super powerful. On past projects I've created SASS mixins to generate colour schemes. This is a much better solution.

:root {
  --my-brand: #ff0000;
  --my-brand-light: color-mix(in srgb, --my-brand, white);
  --my-brand-dark: color-mix(in srgb, --my-brand, black);

Logical operators in media queries

We can now use >, >=, < and <= in media queries. This is great for readability and clarity.

.card {
  /* same as min-width: 50em but it's clearer */
  @media(width >= 50em) {
    min-width: 16em;

Aspect ratio

We've had this one for a while now but it's still great. No more need to reach for the old padding hack and needing to wrap the inner content so it sits on top of the padding.

.card {
  aspect-ratio: 2 / 3;
/* replaces */
.card::before {
  content: "";
  padding-bottom: calc(3 / 2 * 100%);

Container queries

While media queries are great, they're not perfect. They're based on the viewport size and not the size of the element itself. This is where container queries come in. They're based on the size of the element itself. This is great for creating reusable components that can adapt to their container size.

.card {
  @container(width >= 50em) {
    padding: 2em;

New viewport units

We used to only have vh, vw, vmin and vmax. Now we have svh, lvh and dvh. The s stands for small, l for large and d for dynamic.

Large Viewport (LV): Think of this as the "full screen mode." It's what you see when the browser's extras (like toolbars) are hidden. Sizes are tagged with 'lv' like lvw, lvh, etc.

Small Viewport (SV): This is your screen space when the browser's extras are visible. Sizes get an 'sv' tag like svw, svh, etc.

Dynamic Viewport (DV): Now, this one's clever. It changes size based on whether the browser's extras are hidden or visible. So, when the toolbars are out, it's as small as the SV, and when they're hidden, it goes as big as the LV. Sizes use a 'dv' tag like dvw, dvh, and so on.

body {
  /* 100% of the viewport height when the browser's extras are hidden */
  height: 100svh;
  /* 100% of the viewport height when the browser's extras are visible */
  height: 100lvh;
  /* 100% of the viewport height when the browser's extras are hidden or visible */
  height: 100dvh;

Bringing it all together

Quick example of how we can use all of these new features together to create a card component.

In conclusion

I'm excited for the future of CSS. It's come a long way and I'm looking forward to seeing what the next 10 years brings.

In the meantime I'll probably continue to use TailwindCSS for the foreseeable future. It's a great tool and I'm very comfortable with it. I'm sure it will continue to evolve and adapt to the new features of CSS.




Eager for more?

How I Over-engineered a Swear Jar