Is it possible to achieve complete separation of concerns when it comes to HTML, CSS, and JS?

What is the best way to achieve separation of concerns between HTML, CSS, and JS using this HTML structure?

<nav role="navigation" class="site-nav js-site-nav">
  <ul class="site-nav__list">
    <li class="site-nav__item"><a href="#" class="site-nav__link">Menu Item 1</a></li>
    <li class="site-nav__item"><a href="#" class="site-nav__link is-active">Menu Item 2</a></li>
  </ul>
</nav>

Check out the demo: http://codepen.io/achisholm/pen/wGVGxj

Upon closer inspection, it appears that this example lacks a true separation of concerns. The class naming system does not facilitate easy separation. Even when targeting the links, the .site-nav__link selector would still be required in the JS.

One possible solution could be to add a JS hook class to each link. Would adding .js-site-nav__link class to each link enhance the decoupling?

<nav role="navigation" class="site-nav">
  <ul class="site-nav__list">
    <li class="site-nav__item js-site-nav__item"><a href="#" class="site-nav__link">Menu Item 1</a></li>
    <li class="site-nav__item js-site-nav__item"><a href="#" class="site-nav__link is-active">Menu Item 2</a></li>
  </ul>
</nav>

However, this solution may not be ideal as using the complete BEM name could still complicate structural changes. Is there a better alternative to just using .site-nav__link?

Considering a class name like js-link may be an option, but it could lead to other issues. Would targeting .js-site-nav .js-link provide the best solution?

<nav role="navigation" class="site-nav">
  <ul class="site-nav__list">
    <li class="site-nav__item js-link"><a href="#" class="site-nav__link">Menu Item 1</a></li>
    <li class="site-nav__item js-link"><a href="#" class="site-nav__link is-active">Menu Item 2</a></li>
  </ul>
</nav>

While this feels like a more separated approach, is it the most effective solution?

Special thanks to @claudios for providing an example with a clear JS hook using js-add. This method might work well, but may not be suitable for all scenarios. Perhaps a JS hook like js-toggle-link could lead to a better structured approach.

Reference: HTML structure derived from the following talk (relevant part at 17 mins)...

Answer №1

My suggestion for effectively decoupling html, css, and javascript is to use prefixes for all javascript elements. For instance, you can use the prefix "js-*".

Consider this scenario: you have a button like

<button class="add">Add</button>
and you want to add javascript functionality to it. In this case, you can rewrite it as:

<button class="js-add add">Add</button>

If the button requires special treatment and must stand out from other buttons with the "add" class, you can do the following:

<button class="js-add add-special">Add</button>

I hope this explanation proves useful in improving the organization and structure of your code.

Answer №2

BEM actually promotes a different approach.

Instead of separating blocks (components) into markup (HTML), view (CSS) and behavior (JS), BEM suggests keeping them together.

For example, in the case of site-nav, all JS functionality can be handled within the block itself, treating its elements as an internal API of the block (making is-active a modifier of site-nav__link).

For more information, check out the documentation on bem.info:

Answer №3

In my personal view, using overly complex naming conventions can make things more difficult. With the availability of tools like SASS in CSS and object-oriented programming in JS, it is much easier to organize elements and events in a simple and efficient manner.

The key is to keep element and event names as straightforward as possible.

Let me explain further:

For example, consider the following structure that you have provided:

<nav role="navigation" class="site-nav js-site-nav">
  <ul class="site-nav__list">
    <li class="site-nav__item"><a href="#" class="site-nav__link">Menu Item 1</a></li>
    <li class="site-nav__item"><a href="#" class="site-nav__link is-active">Menu Item 2</a></li>
  </ul>
</nav>

While this hierarchical naming structure may seem organized initially, it can become confusing over time, especially for new team members trying to decipher the names independently.

If I were to implement this structure, I would simplify it as follows:

HTML

<nav role="navigation" class="site-nav js">
  <ul>
    <li><a href="#">Menu Item 1</a></li>
    <li><a href="#" class="active">Menu Item 2</a></li>
  </ul>
</nav>

SCSS

.site-nav{
    //styles here

    &.js{
    //styles here
    }

    ul{
        //styles here

        li{
            //styles here

            a{
               //styles here
            }
        }
    }
}

When writing an event for the a element, previously known as a.site-nav__link:

JS

document.querySelector('.site-nav ul li a').addEventListener(eventName, function() {});

By organizing elements in a logical hierarchy, finding and remembering their names becomes much simpler.

Now, let's discuss the use of the .js class and its purpose:

Typically, not every element that interacts with js requires a "js class." So, why do we use it? Let's clarify with an example.

Consider a button with the class .button and specific styles.

SCSS

.button{
    //Some styles
}

If we want certain buttons (with the same style) to increase in size when clicked, we add the .js class to identify them for manipulation with js and easier handling.

document.querySelector('.button.js').addEventListener('click', function() {
    this.className+=' clicked';
});

In the CSS, we define:

.button{
    //Some styles
    &.js{
        .clicked{
            transform:scale(1.1);
        }
    }
}

It's a straightforward concept!

Without using the .js class, we would need to create another class for those buttons. By utilizing a bit of hierarchy, we write less code, maintain organization, and avoid the need to rely on external references due to the simplistic and memorable naming conventions for elements and events!

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

Tips on preventing conflicts between jQuery FancyBox and mouse scrolling

<script src="js/jquery-1.9.1.js"></script> <?php include("fancybox/fb.php"); ?> <script type="text/javascript" src="js/jquery.slimscroll.js"></script> <script type="text/javascript"> ...

The HTML.php form displays boolean radio button values as 'on'

My html.php page includes three buttons: "Clear Page," "Retrieve," and "Update Details." Upon opening the form, users can input either a value for id="siteId" or id="siteName". By clicking the "Retrieve" button, the remaining details of a stored site are ...

Issue with click function not activating in Chrome when using Angular 6

I am facing an issue where the (click) function is not triggering in my select tag when I use Google Chrome, but it works fine in Mozilla. Below is my code: <div class="col-xl-4 col-lg-9"> <select formControlName="deptId" class="form-control ...

The basic shapes in the scene are just out of sight

Sorry for the easy question, but I'm having trouble getting the BoxGeometry to show up in the scene. The red background is displaying correctly. var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(0, window.innerWidth / window.inn ...

Regular expression: match all content up to a certain word(s)

I have two different versions of a string that look like this: The Student's Companion *Author: Alcock, Pete;May, Margaret;Wright, Sharon*MIL EAN/ISBN: 9781283333115 Java Programming: Java Expert*Author:Sarang, Poornachandra*MIL EAN/ISBN: 978128011 ...

New ways to style Links in NextJs 13

I am relatively new to Next.js and I am attempting to create a menu with a hover effect using the following code: import Link from 'next/link'; const MenuItem = ({ href, label }) => ( <Link href={href} className="menu-item"> ...

Unable to decipher the mysterious map of nothingness

I am currently working on a GET method in Node.js. My goal is to fetch data using the GET request and then use the MAP function to gather all the names into an array. However, I encountered the following error: /root/server.js:21 ...

What is the best way to add <li> elements dynamically in an AngularJS application?

I am dealing with html code similar to this: <ul class="list"> <div ng-repeat="avis in avisData"> <li id="li"> <a class="item item-thumbnail-left" href=""><img src=data:image/jpeg;base64,{{avis.image ...

Error message: The md-autocomplete function is throwing a TypeError because it cannot read the property 'then' of an undefined object

I am encountering an issue with the md-autocomplete component from angular material. Here is my code snippet: <md-autocomplete required md-search-text="searchTxt" md-selected-item-change="setModelValue(item.name)&q ...

`The Streaming module within React Native`

I am facing an issue in my React Native project where I want to use a node library that depends on stream (require('stream')). The problem arises with the error stream could not be found within the project because stream is a nodejs package not ...

The React-native application initialized using npx create-react-app encountered an error and could not launch

Hello there, A couple of months back, I developed an app using create-react-app. However, when I tried to run it with npm start, I encountered the following error message: react-scripts start It seems like there's an issue with the project depende ...

Customize the delete icon margin styles in Material-UI Chip component

Currently, I have implemented the V4 MUI Chip component with a small size and outlined variant, complete with a specified deleteIcon. However, I am encountering difficulties when attempting to override the margin-right property of the deleteIcon due to MUI ...

Error: Type Error - 'style' is not defined in the Progress Bar Project

Having recently started learning Javascript, I have been engaging with various tutorials and projects in order to gain familiarity with the language. One particular tutorial that caught my attention is a Progress-Bar tutorial by "dcode" available at this l ...

Dropdown menu is not positioning correctly over other elements on the webpage

After researching multiple stack overflow questions and attempting various solutions, I still haven't been able to resolve my issue. Please refrain from marking this question as a duplicate. The problem I am facing is that my dropdown menu is not ap ...

Use CSS to manipulate the dimensions of an overlay

Looking for a way to ensure that the height of your overlay matches the height of your carousel, even on smaller screen sizes? The HTML code below demonstrates how to combine simple HTML with a Bootstrap carousel featuring three images, along with an overl ...

React: Struggling to render values within {} of a multidimensional object

I'm facing a challenge that I can't seem to overcome and haven't found a solution for. The values between curly braces are not displaying in the Content and Total components. I've double-checked the JSX rules, but it seems like I might ...

Whenever I try to run npm start, my webpack is not able to locate my index.html page

Recently delving into the world of node.js and its packages, I initiated by executing npm init to lay out the package.json structure shown below: { "name": "test", "version": "1.0.0", "description": & ...

Difficulty encountered in resetting progress bar post ajax form submission

Hello, I hope you can assist me with an issue I am facing regarding my progress bar. After submitting the form using AJAX to insert data, my progress bar does not reset. I would like it to reset after clicking the submit button. The progress bar is speci ...

Configuring timezone for 'date' type in Plotly.js

I'm currently working on a graph to showcase the trend over time. The data I have is in Unix format and I use JavaScript code (new Date(data)).toUTCString to display it in my title. Surprisingly, while the data for the graph and the title is the same, ...

The sorting of elements using the jQuery sort() function encounters issues on webkit browsers

Looking for a solution to sort elements by a number? Consider this part of a function that does just that. The number used for sorting is fetched from a data-ranking attribute of the element: $(".tab_entry").sort(function(a,b){ return parseFloat(a.dat ...