dev

Site Update: Modern CSS Styling pt. 1


Over the past year, CSS has gotten some massive updates and many browsers support these cool new features. When building this site I decided I wanted to try out some of these new features, even if all of them aren’t 100% required. For example, Astro scopes all css to the component or file the css is in, so there would be little reason to use @layer feature, but I wanted to try it out (which I’ll probably undo, but more on that later).

@container

Container is one feature I’ve actually really been enjoying. It allows responsive styles to be tired to the width of the element and not the viewport. This helps reduce those special times you’d have to create custom CSS for a card on in a layout that has different max-widths than the normal layout. In the past you’d have add more media queries for those edge cases, creating more work. Now you can use @container to tie the styles to the width of the element and not the viewport. I’ll show an example using my Cartridge component from the blog list page.

.c-cartridge__wrap {
  container-type: inline-size;
  container-name: cartridge;
}

Above I give my Cartridge component a matching name.

.c-cartridge {
  padding: var(--space-4xl) var(--space-md) var(--space-2xl);
  border-radius: var(--space-2xs);

  @container cartridge (min-width: 500px) {
    padding: var(--space-2xl) var(--space) var(--space-md);
    border-radius: 40% 40% 1rem 1rem;
  }
}

I am using the same component to create both the N64 styled cartridge and the Game Boy styled cartridge based on the width of the Cartridge component. There is a lot more css going on, but hopefully you get the idea. It’s real fun if you adjust your browser width and see the changes happen in real time, and when they are all the same style.

@layers

@layer allow you to scope css to specific layers to help prevent specificity issues that often are associated with CSS. Many projects already try to account for this by creating css file structures and imports the place the base and resets first, then applies the component styles and so on. Consider the following example:

@layer base {
  a.link {
    color: red;
  }
}

@layer component {
  .link {
    color: blue;
  }
}

@layer base, components;
<a href="#" class="link"> Click here </a>

If the layers weren’t defined, the color for the anchor would be red, however with the layers defined and explicitly ordered, the anchor tag will be red. This example is a bit contrived but think of a time at work where css specificity cause a bug with styling. Defining layers adds a “trump card” to the cascade order. It basically says, in reference to our example above, “The styles from the component layer are more important than the base layer.” Should be noted that !important still rules all and will override layers. Also if a style is defined outside of a layer, it will be placed in the global layer and be considered more important.

One issue with using @layers I’ve ran into with Astro is the order the styles are applied. It appears in the default set-up that the global layers are applied last in the current layout file structure, and the component layers are place first in the cascade. Basically meaning the order of how you would set up with layers is reversed. If I really wanted to commit to layers I would need restructure and use CSS imports, creating them for each component, which defeats the purpose of Astro’s scoped css. I’ll likely keep the base layer and removed the component layer.

It’s been run using these new CSS features and I can really see the benefit of them. I want to next try out has() and :is() selectors and @scope (which I don’t fully understand), but that’ll maybe be part 2.