Tips for choosing a parent element using SCSS

Here is an example of HTML:

<ul id="navbar-main" class="navbar-nav mr-auto">
    <li class="nav-item active">
        <a href="https://travian.dev/materials" class="nav-link nav-materials">
            <span class="invisible">Materials</span>
        </a>
    </li>
</ul>

Additionally, here is some SCSS:

#navbar-main {
  li {
    &.nav-item {
      .nav-link {
        width: 50px;
        height: 50px;
        background: no-repeat center;
        background-size: contain;

        &.nav-materials {
          background-image: url('../images/buttons/menu-materials.png');

          .active { // this is used to select .nav-item.active .navlink.nav-materials
            background: red;
          }
        }
      }
    }
  }
}

While the code is functioning, there is a desire for increased maintainability and readability. The aim is to achieve a structure like the following:

#navbar-main {
  li {
    &.nav-item {
      .nav-link {
        width: 50px;
        height: 50px;
        background: no-repeat center;
        background-size: contain;

        &.nav-materials {
          background-image: url('../images/buttons/menu-materials.png');

          .active { // here something to actually select .nav-item.active .navlink.nav-materials
            background: red;
          }
        }
      }
    }
  }
}

Answer №1

It never crossed my mind that inserting part of a selector between the parent selector in Scss could be done in a way that is maintainable, but perhaps there's a way...

Prior to delving into it, I found some valuable resources: the Sass Ampersand article on CSS-Tricks which discusses using mixins beyond the standard cases where `&` can be utilized, and also `#{&}` for using `&` twice (something I learned after struggling with `&&` and `li&`, sigh).

The mixin provided as is wouldn't cater to your specific scenario, which led me to create my own approach:

A Scss mixin that accepts 3 parameters to construct various selectors and any rule set

➡️ Codepen demo

@mixin nav-bg($parent, $active, $sel) {
  @at-root #{$parent} {
    &#{$active $sel} {
      @content;
    }
  }
}


#navbar-main {
  li {
    &.nav-item {
      .nav-link {
        width: 50px;
        height: 50px;
        background: no-repeat center;
        background-size: contain;
      }

      @include nav-bg(&, '', '.nav-materials') {
        background-image: url('../images/buttons/menu-materials.png');
      }

      @include nav-bg(&, '.active', '.nav-materials') {
        background: red;
      }
    }
  }
}


// output
#navbar-main li.nav-item .nav-link {
  width: 50px;
  height: 50px;
  background: no-repeat center;
  background-size: contain;
}
#navbar-main li.nav-item .nav-materials {
  background-image: url("../images/buttons/menu-materials.png");
}
#navbar-main li.nav-item.active .nav-materials {
  background: red;
}


If your aim is to maximize maintainability, I highly recommend revamping your nesting techniques and reducing selector specificity.
Here's how I would rewrite your code block:

➡️ Simplified selectors (Codepen)

#navbar-main {
  .nav-link {
    width: 50px;
    height: 50px;
    background: no-repeat center;
    background-size: contain;
  }

  .nav-materials {
    background-image: url('../images/buttons/menu-materials.png');
  }

  .active {
    .nav-materials {
      background: red;
    }
  }
}

Sass references: [@content](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#mixin-content), [@at-root](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#at-root)

I would also suggest substituting the id with a class, even for components that are presumed to be unique on a page. I resisted this change for quite some time, but it proved to be beneficial in avoiding unnecessary complications...

Keeping CSS selectors concise by CSSWizardry is a good starting point (explore archives from 2012 to 2016 for more insights) CSS methodologies for scalable styles:

Answer №2

In my opinion, it's difficult to find ways to enhance the original SCSS you provided. The Sass parent selector (&) chooses the entire chain of parents.

One alternative, albeit a bit awkward, is to utilize @at-root to go back to the root of your style sheet, and then modify a section of your selector like this:

/// Modify `$search` with `$replace` within `$string`
/// @author Hugo Giraudel
/// @param {String} $string - Initial string
/// @param {String} $search - Substring to update
/// @param {String} $replace ('') - New value
/// @return {String} - Revised string
@function str-replace($string, $search, $replace: '') {
  $index: str-index($string, $search);
  
  @if $index {
    @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
  }
  
  @return $string;
}

#navbar-main {
  li {
    &.nav-item {
      .nav-link {
        width: 50px;
        height: 50px;
        background: no-repeat center;
        background-size: contain;

        &.nav-materials {
          background-image: url('../images/buttons/menu-materials.png');

          @at-root #{str-replace(#{&}, ".nav-item", ".nav-item.active")} {
            background: red;
          }
        }
      }
    }
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Toggle switch unable to reset upon reloading the page

Issue with Toggle Switch Not Resetting on Page Reload I am encountering a problem with a toggle switch I implemented from the W3schools example (link here). Unlike in the W3schools editor where it resets its state upon reload, my toggle switch remains in ...

Facing compatibility problems with JavaScript and Cascading Style Sheets in Google Chrome?

Welcome to the site . Let's address a couple of issues with JavaScript and CSS: Firstly, the JS code seems to be malfunctioning only in Chrome, throwing an error that reads: 'Uncaught TypeError: Object [object Object] has no method 'on prij ...

Troubleshooting spacing and padding problems in Bootstrap 5.2.3's Scrollspy feature

Hello, I'm currently working on developing a new portfolio template that features a list on the left side to guide users through different sections of the page. Utilizing Scrollspy in Bootstrap 5.2.3 has been helpful so far, but I've noticed that ...

Causing an element to extend beyond its parent element's boundaries

I have implemented Material Design Lite for creating cards on my website. I encountered an issue where the menu I added to the card only displays within the bounds of the card. I would like it to overflow similar to this example () Here is a link to my fi ...

Struggling to decide on the perfect CSS selector for my puppeteer script

I am trying to use puppeteer page.type with a CSS selector. <div class="preloader"> <div class="cssload-speeding-wheel"></div> </div> <section id="wrapper" class="login-register"> <div class="login-box"> <d ...

Having trouble showcasing two unordered lists side by side on a single line

In my Magento Go store, I am showcasing products using CSS only. Currently, the loop is set to display 5 products in a row and then close the <ul> tag. However, if there are more products, a new <ul> element is created. My fixed width only allo ...

Menu sliding in causes horizontal scroll bar to appear

Encountering a problem with a slide-in menu. Here's an example: http://jsfiddle.net/flobar/Z62t2/ The issue arises when the menu is hidden, causing a horizontal scroll bar to appear. How can this be prevented? HTML: <div id="slideIn"> < ...

The image appears distorted when viewed in the Safari browser

I have an image within an li tag. The image appears correctly in Firefox and Chrome as shown below: https://i.sstatic.net/cuKzS.png However, in the Safari browser on iOS and macOS, the image is distorted: https://i.sstatic.net/RhIVU.jpg This is the cod ...

What is preventing Firefox and IE from displaying images fully in a list item?

I am trying to create a slideshow with two separate sliders using li elements for that purpose. It works perfectly in Chrome and Safari, but I am encountering issues in Firefox and IE. In Firefox, the slideshow works fine in quirks mode but not in standar ...

During DragAndDropToObject in Selenium IDE, the initial element in the list is overlooked

I have a webpage that is split into two datagrids. The left datagrid is structured like this: <ul class="left_dg"> <li> <ul></ul> </li> <li> <ul></ul> </li> <li&g ...

How can I add a % symbol to user input in a text input field?

When utilizing a number spinner, I'm looking to include the % symbol in the input box by default. I attempted using a span, however, it places the symbol outside the box. ...

Preserve the location of a moveable div using jQuery

I have implemented draggable divs in my JSP page, allowing users to move them around freely. After dragging the divs, I would like to save their positions either in a cookie or database for future reference. Could you please advise on the best way to ach ...

Customizing Material UI Stepper styles using CSS API

I am trying to customize the text color (represented by an SVG Icon) in Material UI StepIcon for active and completed steps only. Currently, I have successfully changed the icon color for those steps. This is how my custom MuiTheme appears: export default ...

How come I am able to reference a component in styled-components while others cannot?

When using styled-components, you can reference another React component using the syntax ${Label}. However, I have noticed that it only works with certain components and not others. Despite reading the documentation at , I encountered an issue when trying ...

Tips for displaying a button when hovering over it on large screens and larger sizes

I am trying to achieve a specific behavior where the button with class .bookmark-btn is only visible on md size screens and smaller at all times. However, on lg size screens and bigger, it should only appear when hovered over. How can I accomplish this? Cu ...

The Parcel build was unsuccessful due to an error from @parcel/resolver-default: The file '../../../../../css/main.css' could not be loaded within the './src' directory

I utilize [email protected]. Whenever I attempt to load an external css or javascript file in my index.html, Parcel consistently fails to build with the following error: Build failed. @parcel/core: Failed to resolve './css/main.css' from & ...

What could be causing the bootstrap card alignment issue when trying to display them side by side

I am currently developing a Flask project where I'm showcasing user information retrieved from the database within bootstrap cards. Utilizing jinja2 to iterate through an object statuses {% extends "base.html" %} {% block content %} {% if ...

Blurry text can be a common occurrence when applying the transform(-50%,-50%) function to center

I have found a way to center a section using the following code: <div class="clock-section"> <h5 id="clock-title">We will be arriving soon</h5> <hr class="hr" id="cdhr"> </div> Here is ...

Display updated text on hover over button panel

Is it possible to achieve the following using only CSS without any JavaScript? The desired outcome is a div containing two font awesome icons aligned to the right side. Specifically, I am looking for: - Icon of a pen that reacts on mouse hover - Icon o ...

Replace Css styling with custom styling in external stylesheet

Here is the code from the custom.css file, an external CSS within an HTML page: button { cursor: pointer; appearance: none; -moz-appearance: none; -webkit-appearance: none; border: none; padding: 0; margin: 0; background: none; -webkit-user-select: no ...