Uncouple JavaScript and CSS

September 16, 2012, by Alexis Bernard

I used to tighten JavaScript to my CSS. My JavaScript was also too coupled to the backend of web application. Having too much coupled code is bad because refactoring becomes harder and costly. I am going to show you how I solved that problem.

Here is a basic snippet where CSS and JavaScript are heavily coupled.

<span class="delete">Delete</span>

$('.delete').click(deletePicture);

This is bad code because when you refactor some CSS you can break your Javascript code. For example if I rename .delete in my CSS files to .remove, I may forget to do the same in my JavaScript files. It happens often because CSS files are edited by designers and JS files are written by programmers. Even though communication may be good between developers and designers on your team, you can be sure this situation will happen.

Fortunately HTML5 has introduced the very convenient “data-anything” attributes. If the selector is based on a data attribute, then JavaScript won’t be coupled to the CSS anymore.

<span class="delete" data-action="delete-picture">Delete</span>

$('[data-action=delete-picture').click(deletePicture);

I really enjoy this approach and it makes me feel more confident between JS and CSS. However I still couple my JS to the backend of web application. Check the following snippet where I added a picture ID into the HTML.

<span class="delete" data-picture-id="123">Delete</span>

$('[data-action=delete-picture').click(deletePicture);

function deletePicture(event) {
  $.ajax('/pictures/' + event.attr('data-picture-id'), {type: 'DELETE', ...});
}

My code is coupled to the backend because JavaScript code builds the URL on its own. The URL schema is shared by both frontend and backend. If the URL changes on the backend, then a frontend developer have to update the JavaScript code. That’s exactly the same problem as the previous one. My solution is to include the picture’s full path into the HTML document.

<a href="/pictures/123" data-action="delete-picture">Delete</a>

$('[data-action=delete-picture').click(deletePicture);

function deletePicture(event) {
  event.preventDefault();
  $.ajax(event.target.href, {type: 'DELETE', ...});
}

Now, the JS is neither coupled to the CSS nor the backend side. The code is nicer, it breaks less often and is easier to refactor.

I switched the span to an anchor for semantic purpose. That’s why I call preventDefault to tell to the browser to not open the link. If you prefer to have a span with a data-url attribute instead of the href, that’s perfectly fine too.