DEV Community

jabo Landry
jabo Landry

Posted on

You’re probably writing complex CSS for no reason

These past days I’ve noticed that many of us haven’t been checking out on what’s new with CSS features and I think if you haven’t checked for these new features, you’re probably complicating your CSS snippets and writing complicated JavaScript snippets that can done using CSS.

In Today’s guide I will be talking about some of the new features of CSS that you probably haven’t heard of or may have heard of them but haven’t practiced them, no worries I will be guiding you on how they work and giving an example of their use-cases.

Features we will cover

has pseudo-class

The has pseudo-class unlocks a lot of possibility with CSS, now with has pseudo-class you can style the parent element based on its descendant's behavior, styling and even their attributes.

If I we were to have a button that toggles a text on/off, in this case we would use JavaScript classList method on the element to trigger its visibility by adding and removing the class to hide/show the element that we want to toggle, we would have something that looks like this:

With has we don’t need to write any JavaScript at all, But here we take a different approach instead of using a button in our markup as we normally do we use an input box of a checkbox and style it to look more like a button and then we use the parent to check if there’s a checked element in its descendants elements if so we target the p element and set its display behavior to none, take a look at this video too:

  • snippet

    <style>
          body:has(input:checked) p {
            display: none;
          }
          input[type="checkbox"] {
            appearance: none;
            cursor: pointer;
          }
    
          input[type="checkbox"]::before {
            content: "Hide";
            background-color: green;
            color: white;
            padding: 0.4rem 1.4rem;
            border-radius: 0.4rem;
          }
    
          input[type="checkbox"]:checked::before {
            content: "show";
          }
          input[type="checkbox"]:active:before {
            background-color: limegreen;
          }
        </style>
      </head>
    
      <body>
        <input type="checkbox" />
    
        <p>
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatum
          temporibus molestiae itaque harum ut consectetur odit, sit cumque quae
          fugiat error inventore, perspiciatis tempore, voluptatibus magni
          laudantium quas aliquid. Nulla voluptate ex ut molestiae exercitationem
          autem doloribus modi? Voluptatem, repudiandae.
        </p>
      </body>
    

These are the snippet that make up this function, we’ve wrapped all the contents inside the body element which acts as a parent, now we use the has pseudo-class to find a checked input under the body element we then target the p element to hide it when the checkbox is checked and unhide it when we uncheck the checkbox.

When combined with pseudo-elements like ::before and ::after you can make it more interactive as I did in the example, and of course, you can do more than just toggling things on and off.

CSS nesting

Before if we were to style a specific descendant element of a given parent, we would have to prefix the parent or wrapping element before the element we want to style, let’s take an example of our previous example we want to style the p element we would have written a CSS that looks like this:

body{
  box-sizing: border-box;
  margin: .9rem;
}

body p {
  font-family: sans-serif;
  font-size: 1em;
}
Enter fullscreen mode Exit fullscreen mode

But do you know that we can do the same thing by nesting the p element inside the body declaration like so:

body {
  box-sizing: border-box;
  margin: 0.9rem;
  p {
    font-family: sans-serif;
    font-size: 1em;
  }
}
Enter fullscreen mode Exit fullscreen mode

nesting for pseudo-elements and pseudo-classes

And we if we wanted to nest any pseudo-element or pseudo-class, we use the & for example we can simplify this input declaration:


      body:has(input:checked) p {
        display: none;
      }
      input[type="checkbox"] {
        appearance: none;
        cursor: pointer;
      }

      input[type="checkbox"]::before {
        content: "Hide";
        background-color: green;
        color: white;
        padding: 0.4rem 1.4rem;
        border-radius: 0.4rem;
      }
Enter fullscreen mode Exit fullscreen mode

By nesting the ::before selection inside the input selector like this:

input[type="checkbox"] {
        appearance: none;
        cursor: pointer;
        &::before{
          content:"Hide"
           background-color: green;
            color: white;
            padding: 0.4rem 1.4rem;
            border-radius: 0.4rem;
        }
      }
Enter fullscreen mode Exit fullscreen mode

This is helpful when you have long list of pseudo-elements and classes you want to apply to a single element you can nest them as the example we have to avoid having many definitions of the same element declaration.

But be careful using this type of nesting because it can lead to unreadable CSS it's better to use it for pseudo-classes, pseudo-elements or when you are constantly prefixing your parent element on its descendant's children you want to style.

@scope

Did you actually know that with CSS you can style elements based in a scope they are define in and you can limit the elements of the scope that gets affected, just as in normal programming when have scopes and we can limit the availability of the variable based on the scope the same with CSS.

Let’s take an example to see how this would work:

 <body>
    <section>

      <div class="profile">
        <img src="./assets/people.png" alt="article image" width="200" />
      </div>

      <div class="img-2">
        <img src="./assets/people.png" alt="article image" width="200" />
      </div>

    </section>
  </body>
Enter fullscreen mode Exit fullscreen mode

Let’s say we have this HTML structure; we have a section that has two divs one of them has the class called img-2 which has the same content as the first one they both have images take the first div.’s image and make it a rounded image much more like a profile, the snippet could look like this

.profile img {
  border: 4px solid green;
  border-radius: 50%;
}
Enter fullscreen mode Exit fullscreen mode

We can use @scope to limit the styles to only apply to the first image using the section we can write like:

@scope (section) to (.img-2) {
  img {
    border: 4px solid greenyellow;
    border-radius: 50%;
  }
}
Enter fullscreen mode Exit fullscreen mode

What we are essentially doing is we are taking section scope and target all the images elements within the section scope, to method is essential because it tells CSS to apply styles to every img in the scope except the images that are found inside an element with the class of .img-2 if you forgot to add it will add styles to all img elements in the scope

  • Rule of Thumb

    use to to limit you’re styles to a specific scope only by excluding a given markup or scope you define inside it’s curry braces ()

@container queries

Container queries are another type of making responsive design but in a more a customized way, before the responsive required you to target the whole screen’s viewport or width to start applying styles based on a certain viewport the screen reaches, which sometimes was hard to work when you only wanted to add responsive to a certain section of your page.

With @container queries, you can add responsive designs based on the size of the parent element or the wrapping element.

Consider this example

  <section class="blog">
      <figure>
        <div>
          <img src="./assets/people.png" alt="article image" />
          <figcaption>sample image</figcaption>
        </div>

        <p class="description">
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Vitae,
          asperiores dolorum. Aspernatur laboriosam quam, nulla ipsum cumque
          dolores pariatur recusandae nobis ea itaque commodi similique eos
          dolor! Quae dolore eaque numquam quidem voluptatem, asperiores ea!
          Esse ut ratione quam quisquam.
        </p>
      </figure>
    </section>
Enter fullscreen mode Exit fullscreen mode

We have a section with a class of blog and we want to make the content display flex when its size in width is less than 640px , using container queries we can do it using the below example

section {
  display: grid;
  container-type: inline-size;
}

@container (width < 640px) {
  figure {
    display: flex;
    align-items: center;
    background-color: green;
  }
}
Enter fullscreen mode Exit fullscreen mode

Unlike media queries to be able to use container queries you first need to have an element wrapping the elements you want to have container queries on, and then target the wrapper element in our case we have section as our wrapper element and then use the property of container-type to specify if you want your styles to be triggered while scaling the screen horizontally or scaling vertically,

Most of the time you will want the responsive the occur when scaling horizontally meaning when the screen is shrinking on the x-axis for this behavior you use the inline-size.

If you want to apply vertically meaning shrinking on the y-axis you can use the block-size

And also, there is another one both to track both sides.

Below there is a demo showing how container queries differ from me

As you can see in the demo, we have a black background color that is applying when our screen is below the width 640px and we have a green background that is later appearing when our container size with is below 640px.

You can see the difference even though it is small, but the green background lasts a little longer than the black one because our container width is still less than 640px even though our screen width is greater than 640px

Summary

We have covered the has pseudo-class which can be used style the parent element or style its descendants based on the descendant's behavior, style or attributes

We’ve covered @scope which we can use to only apply styles to a specific element in a scope of the markup structure and the @container queries that we use to add responsive design based on the parent or container element size.

Final Thoughts

This was few in more features that are being released in CSS and they can do more advanced things more than what I demoed in this guide, if you explore more you will find many use-cases for each feature and also the examples in this guide are also a good reference for more use-cases you may think of or challenge they can help solve with your CSS, Thanks for reading I hope you’ve enjoyed it.

Top comments (0)