GAZAR

Principal Engineer | Mentor

Elevate Your Frontend Skills with the Latest Techniques and Features in CSS, July 2023

Elevate Your Frontend Skills with the Latest Techniques and Features in CSS, July 2023

Are you looking to take your front-end development abilities to the next level? Are you eager to stay ahead of the curve and create visually stunning, highly interactive websites? If so, it’s time to explore the world of advanced CSS and embrace this versatile language's latest techniques and features. With the rapid evolution of web technologies, mastering the art of CSS is essential for creating exceptional user experiences and ensuring your websites stand out in today’s competitive digital landscape.

1. Container Queries

To use container queries, you would start by defining a container query on an element. This could be a class or an attribute that you use to group the elements you want to apply the query to.

/* Example container query */
@container (min-width: 300px) {
  /* CSS rules for the element when its container is at least 300px wide */
}

Next, you would apply the container query to the elements you want to style based on their container size.

<!-- Applying the container query to an element -->
<div class="container-element">
  <!-- Content here -->
</div>

Inside the container query block, you can write CSS rules that apply to the element when its container matches the specified condition.

/* Example container query */
@container (min-width: 300px) {
  .container-element {
    /* CSS rules for the element when its container is at least 300px wide */
  }
}

2. Style Queries

In simpler terms, you can use style queries to query a container based on its style rather than just its size. Here’s how it works:

@container style(color: purple) {
      /* styles to apply when the card container has a color of purple */
  .card {
    /* To change the background to green: */
    background: green;
  }
}

The above code will change the background of a card or section to green if the parent section has the color purple.

2. :has selector

The general syntax of the :has selector is as follows:

parent-selector:has(descendant-selector) {
  /* Styles applied to the parent element when it contains the specified descendant *
}

Like:

<div class="parent">
  <p>Some content here.</p>
  <span>Some more content.</span>
</div>

/* Example: Applying styles to the parent div when it contains a <span> */
.parent:has(span) {
  background-color: lightblue;
}

In this example, the div element with the class "parent" would be styled with a light blue background only if it contains a span element.

4. nth-of microsyntax

The web platform now has a more advanced nth-child selection. The advanced nth-child syntax gives a new keyword (“of”), which lets you use the existing micro syntax of An+B, with a more specific subset within which to search.

:nth-child(2 of .highlight) { 
 // Select the 2nd child element that has the 
 // class .highlight applied to it */
 outline: 0.3rem dashed hotpink;
 outline-offset: 0.7rem;
}

5. text-wrap: balance

As a developer, you don’t know the final size, font size, or even language of a headline or paragraph. All the variables needed for an effective and aesthetic treatment of text wrapping, are in the browser. This is why we see headline wrapping as in the following image:

1_b7IQ1mrFEfnRwy1IJxIjPw.webp

And this syntax will give you balance lines.

.balanced {
  max-inline-size: 50ch;
  text-wrap: balance;
}

1_USmHJ_MzvjbnAnccjkmzcQ.webp

6. initial-letter

The initial-letter property automatically calculates both the font size and the number of lines needed to create our stylized drop cap!

/* Style that first letter! */
.subhead::first-letter {
  initial-letter: 2;
}

1_msY0Dheejf-ouM7Tn3ewnw.webp

7. Dynamic viewport units

We’ve got viewport units (e.g. vw, vh, vmin, vmax), and they are mostly pretty great. It’s cool to always have a unit available that is relative to the entire screen.

  • The “Large Viewport”: lvh / lvw / lvmin / lvmax
  • The “Small Viewport”: svh / svw / svmin / svmax
  • The “Dynamic Viewport”: dvh / dvw / dvmin / dvmax
1_w3OS4QKKYR2ilVV5Yr6z0g.webp

The Dynamic Viewport is the viewport sized with *dynamic consideration of any UA interfaces*. It will automatically adjust itself in response to UA interface elements being shown or not: the value will be anything within the limits of 100vh (maximum) and 100svh (minimum).

8. Wide-gamut color spaces

CSS Color Module Level 4 introduced syntax to use Display-P3 color space on the web:

color: color(display-p3 1 0.5 0)
1_UklWLFMdu5_ja7WKfD8YYw.webp

The white line shows the edge of sRGB. Everything on its top right is Display-P3 colors not available in sRGB. Note how greens is greatly expanded while blues aren’t nearly as much.

9. color-mix()

The CSS color-mix() function is an experimental feature that is currently a part of the Color Module 5. True to its name, the function will accept any two colors, mix them together and return a little colour Frankenstein.

color-mix(in srgb, #34c9eb 20%, white);

10. Nesting

Before nesting, every selector needed to be explicitly declared, separately from one another. This leads to repetition, stylesheet bulk and a scattered authoring experience.

.nesting {
  color: hotpink;
}
.nesting > .is {
  color: rebeccapurple;
}
.nesting > .is > .awesome {
  color: deeppink;
}

After nesting, selectors can be continued and related style rules to it can be grouped within.

.nesting {
  color: hotpink;
  > .is {
    color: rebeccapurple;
    > .awesome {
      color: deeppink;
    }
  }
}

11. Cascade layers

Cascade layers give CSS authors more direct control over the cascade so we can build more intentionally cascading systems without relying as much on heuristic assumptions that are tied to selection.

@layer framework {
  .overly#powerful .framework.widget {
    color: maroon;
  }
}
@layer site {
  .my-single_class {
    color: rebeccapurple;
  }
}

12. Scoped styles

Scoped styles allow you to contain a set of styles within a single component on the page. You can use a .title selector that only works within a Card component, and a separate .title selector that only works in an Accordion.

@scope (.card) {
  /* Scope the following styles to inside `.card` */
  :scope {
    padding: 1rem;
    background-color: white;
  }
  .title {
    font-size: 1.2rem;
    font-family: Georgia, serif;
  }
}

13. Trigonometric functions

Calculate the sine, cosine, tangent, and more in CSS.

:root {
  --radius: 20vmin;
}
.dot {
  --angle: 30deg;
  translate: /* Translation on X-axis */
             calc(cos(var(--angle)) * var(--radius))
             /* Translation on Y-axis */
             calc(sin(var(--angle)) * var(--radius) * -1)
  ;
}

14. Individual transform properties

The properties are scale, rotate, and translate, which you can use to individually define those parts of a transformation.

.target {
  translate: 50% 0;
  rotate: 30deg;
  scale: 1.2;
}

15. popover

The :popover-open CSS pseudo-class represents a popover element (i.e. one with a popover attribute) that is in the showing state. You can use this to apply style to popover elements only when they are shown.

By default, popovers appear in the middle of the viewport. The default styling is achieved like this in the UA stylesheet:

[popover] {
  position: fixed;
  inset: 0;
  width: fit-content;
  height: fit-content;
  margin: auto;
  border: solid;
  padding: 0.25em;
  overflow: auto;
  color: CanvasText;
  background-color: Canvas;
}

To override the default styles and get the popover to appear somewhere else on your viewport, you could need to override the above styles with something like this:

:popover-open {
  width: 200px;
  height: 100px;
  position: absolute;
  inset: unset;
  bottom: 5px;
  right: 5px;
  margin: 0;
}

16. anchor positioning

You can try out the CSS anchor positioning API in Chrome Canary behind the “Experimental Web Platform Features” flag. To enable that flag, open Chrome Canary and visit chrome://flags. Then enable the "Experimental web platform features" flag.

@supports(anchor-name: --foo) {
  /* Styles... */
}

First, you need to choose how to define the anchor. You can do this within your CSS by setting the anchor-name property on the anchor element. It accepts a dashed-ident value.

.anchor {
  anchor-name: --my-anchor;
}

Alternatively, you will be able to define an anchor in your HTML with the anchor attribute. The attribute value is the ID of the anchor element. This creates an implicit anchor.

<a id="my-anchor" class="anchor"></a>
<div anchor="my-anchor" class="boat">I’m a boat!</div>

17. selectmenu

The proposed <selectmenu> will have powerful styling options and full control over the different parts. In other words, there would be not one, but two levels of customisation. In this post, we'll look at what they are and when they are useful.

<style>
  .my-select-menu::part(button) {
    color: white;
    background-color: #f00;
    padding: 5px;
    border-radius: 5px;
  }
  .my-select-menu::part(listbox) {
    padding: 10px;
    margin-top: 5px;
    border: 1px solid red;
    border-radius: 5px;
  }
</style>

<selectmenu class="my-select-menu">
  <option>Option 1</option>
  <option>Option 2</option>
  <option>Option 3</option>
</selectmenu>

18. Scroll-driven animations

The CSS scroll-driven animations module provides functionality that builds on top of the CSS animations module and Web Animations API. It allows you to animate property values based on a progression along a scroll-based timeline instead of the default time-based document timeline.

<body>
  <div id="progress"></div>
  …
</body>

@keyframes grow-progress {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

#progress {
  position: fixed;
  left: 0; top: 0;
  width: 100%; height: 1em;
  background: red;
  transform-origin: 0 50%;
  animation: grow-progress auto linear;
  animation-timeline: scroll();
}

19. accent-color

The accent-color CSS property sets the accent color for user-interface controls generated by some elements. (Here)

input {
  accent-color: auto;
  display: block;
  width: 30px;
  height: 30px;
}

input.custom {
  accent-color: rebeccapurple;
}

20. Scroll snap

The scroll-snap-type CSS property sets how strictly snap points are enforced on the scroll container in case there is one.

<div class="container">
  <section class="child"></section>
  <section class="child"></section>
  <section class="child"></section>
  <p>...</p>
</div>

.container {
  scroll-snap-type: y mandatory;
}
.child {
  scroll-snap-align: start;
}

21. @when and @else

The proposed @when rule generalizes conditionals, so instead of using a specific conditional rule for a specific task, such as a feature query with @support, you can generalize your rule block to use two or more kinds of queries.

@when media(max-width: 769px) and supports(display: grid) and supports(display: flex) {
    .grid {
        grid-template-columns: 1fr;
    }
    .flex {
        flex-direction: row;
    }
}

// OR
@when media(min-width: 768px) and supports(display: grid) {
    div {
        display: grid;
        grid-template-columns: 1fr;
    }
  } @else supports(clip-path: circle(1px)) and supports(transform: skewY(1deg)) {
        div {
            display: block;
         }
    }
  } @else {
    /* Fallback. In case all of the above conditions evaluates to false */
      div {
        display: block;
      }
}

22. Inset

The inset CSS property is a shorthand that corresponds to the top, right, bottom, and/or left properties. It has the same multi-value syntax of the margin shorthand.

<div>
  <span class="exampleText">Example text</span>
</div>
div {
  background-color: yellow;
  width: 150px;
  height: 120px;
  position: relative;
}

.exampleText {
  writing-mode: sideways-rl;
  position: absolute;
  inset: 20px 40px 30px 10px;
  background-color: #c8c800;
}

CSS is just getting cooler and more amazing!