CSS Nesting

by Andy Prevost

Thursday August 1 2024

Selectors have long been the domain of LESS and SASS pre-processors.

They are also native to CSS too – along with combinators, child and appended nested selectors.

To illustrate this, I will post the code to recent development for My CSS Framework (blade.css) – a checkbox toggle switch. You can find it at https://blog.aprevost.com/toggle_example.html.

The toggle switch example code is very basic and may not be the final version. I show five different sizes: Small, Medium, Large, X-Large, and Jumbo. All the CSS code is nested under the container.

The HTML for one of the toggle switches:

  <label class="check-toggle-container">
    <input type="checkbox" checked>
    <span class="check-slider"></span>
  </label>

By the way, if you click on the link above to view the example page, start your browser console. I have added some javascript code to the example so you can see the effect on the "checked" status of each input when you toggle.

Note that there is no code in the nested .medium css code. That is because the default is identical to the .medium tag. It's added there just for consistency (or clarity) in writing the HTML.

Here's the CSS code:

  <style>
  .check-toggle-container {
    –base-height: 22px;
    –base-width: calc((var(–base-height) * 2) - 2px);
    –base-border: 3px;
    display: inline-block;
    height: var(–base-height);
    outline-style: none;
    position: relative;
    width: var(–base-width);
    &.small {
      –base-border: 2px;
      –base-height: 18px;
    }
    /* medium is same as default */
    &.medium {
    }
    &.large {
      –base-border: 2.5px;
      –base-height: 28px;
    }
    &.x-large {
      –base-height: 36px;
    }
    &.jumbo {
      –base-height: 48px;
    }
    /* Hide the checkbox input */
    input[type="checkbox"] {
      display: none;
    }
    /* Slider look & position */
    .check-slider {
      background-color: #D3D3D3;
      border-radius: var(–base-height);
      bottom: 0;
      cursor: pointer;
      left: 0;
      position: absolute;
      right: 0;
      top: 0;
      transition: .4s;
      /* Slider circle look & position */
      &:before {
        background-color: #ffffff;
        border-radius: 50%;
        bottom: var(–base-border);
        color: #FF0000;
        content: "\2718";
        height: calc(var(–base-height) - calc(var(–base-border) *2));
        left: var(–base-border);
        line-height: calc(var(–base-height) - calc(var(–base-border) *2));
        position: absolute;
        width: calc(var(–base-height) - var(–base-border));
        text-align: center;
        transition: .4s;
      }
    }
    /* Change slider background color when selected */
    input[type="checkbox"]:checked+.check-slider {
      background-color: #008000;
      /* Slide white ball to right */
      &:before {
        color: #008000;
        content: "\2714";
        transform: translateX(calc(var(–base-height) - calc(var(–base-border) *2)));
      }
    }
  }
  </style>

This is 70 lines of code (well, 64 lines if you also remove the comments). Everything is nested under the container.

And, note, there is an error in the specification as documented on most websites. If you have an HTML fragment in a nested tag, the document says to use the & nested selector in front of the CSS code. That is wrong. It won't work (it will actually generate an error). You have to leave off the nested selector (that means do not use & .check-slider { use .check-slider {) see above, there are two examples.

Look closely at the HTML code in the example. One of the selectors has class="check-toggle-container small" ... that is consistent with the CSS code above where we use &.small ... that means that the "small" class is specified only when used with the "check-toggle-container" class. (that's what nested means).

Although not used in any of the example, there is one other nesting example well worth discussing. That is the "appended nested selector". Consider this HTML code:

<div class="container-u">
  <div class="content-u">
    ... content
  </div>
</div>

It's always been difficult to apply CSS to the "container" element that contains "content". That's what the appended nested selector does. Here's how that would look:

<style>
.content-u {
  ... content-u styles
  .container-u & {
    ... container-u styles
  }
}
</style>

Isn't that a lot simpler than any other way of doing this?

Enjoy!

◀ Previous Next ▶

Post a Comment