DEV Community

Kingsley Uwandu
Kingsley Uwandu

Posted on

Best Practices for Writing Clean and Maintainable Html, Css, and JavaScript Code

Every developer should know this: Building well-structured and lasting websites require more than just functionality. For instance, you are tasked with the responsibility of adding a new feature to an existing website, or fix a bug in a critical application. But, in this situation when you get in to the codebase, you find a rough and scattered HTML, a difficult to understand CSS, and disorganized JavaScript - The code is hard to read and understand, let alone to modify; making you spend more hours trying to understand what each piece does. All these, only to realize that making any change risks affecting something else. This is many developer’s experience. They, at some point in their career, have experienced the frustration of dealing with unclean and poorly structured code. This does not just slow down development – it also leads to increase in bugs, high maintenance costs, and worst, a frustrating work environment.

However, all these can be avoided with some straight-forward and simple coding practices for writing clean and maintainable HTML, CSS, and JavaScript. Following these practices ensures efficient development, improves productivity, easier collaboration, and a long-term and better user experience.

Html Best Practices

a. Use Semantic HTML:

Semantic HTML involve using HTML tags that gives meaning and purpose of the content they enclose. Elements like <header>, <nav>, <article>, <section>, and <footer> are semantic – They provide useful information to browser, search engines, and technologies that assists in the different roles of a webpage. This practice leads to:

  • Improved Accessibility: By providing meaning and context to the content structure, Semantic elements like <header>, <nav>, <main>, <article>, <section>, and <footer> helps certain technologies, such as screen readers to interpret the page structure more accurately. This allows visually impaired users to understand the layout and navigate the content more efficiently. For example, a <button> is recognized as a clickable button, and a screen reader will know this. This informs users who depend on these technologies that they can interact with the button using their keyboard.

  • Help Users navigate a webpage: When navigating a webpage using the Tab key, the browser will move focus to interactive elements like links (<a>), form controls (<input>, <button>, etc.), and any element with a tabindex attribute. Tags like <button> and <a> are keyboard accessible. When you press Tab, the focus will automatically move to these elements, allowing users to interact with them using the Enter or Space keys.

  • Keyboard Navigation: Semantic tags come with built-in keyboard behaviors. For instance, for <button>, pressing Enter or Space activates the button, and for <a> (with an href attribute), pressing Enter follows the link.
    Non-semantic elements (like <div> or <span>) do not have these built-in behaviors. You would need to add additional JavaScript to try this functionality, which likely is prone to error, and harder to maintain sometimes.

b. Logical Nesting of Elements:

Logical nesting ensures that elements are nested in a way that shows their relationships and hierarchies within the content. This practice helps maintain a clear and orderly document flow. This can be achieved in two ways:

  • Hierarchical Structure: Use elements in a hierarchical manner to indicate their level of importance and relationship to other content. For example, heading tags (<h1>, <h2>, etc.) should follow a logical order.
<article>
  <h1>Main Title</h1>
  <section>
    <h2>Subsection 1</h2>
    <p>Content for subsection 1.</p>
  </section>
  <section>
    <h2>Subsection 2</h2>
    <p>Content for subsection 2.</p>
  </section>
</article>
Enter fullscreen mode Exit fullscreen mode
  • Nesting child into parent: Proper nesting of child elements within their parent elements is one of the best practices for writing HTML code. It helps to improve the readability.

Parent element: An HTML element that contains other elements within its opening and closing tags.

Child element: An HTML element that is nested within another element (parent element).

For example:

<nav>
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>
Enter fullscreen mode Exit fullscreen mode

In the above code snippet, the <nav> element is the parent element.<ul> element is the child element of the <nav> element. While the <li> elements are child elements of the <ul> element, the <a> elements are child elements of the <li> elements. The arrangement improves code readability, ensure easier maintenance, and reduce code error.

c. Indentation and Formatting:

Indentation and Formatting do not affect how the web browser interprets the code itself, but they provide some benefits to anyone who needs to read or modify the code. While Indentation creates a visual hierarchy, clearly showing how elements are nested within each other, Formatting, similar to paragraphs and spacing in written text, separates different parts of the code, making it easier to differentiate between elements, attributes, and content. Both practices improve code readability.

Example of indentation:

<div class="crown">
  <h2>Section Title</h2>
  <p>This is a paragraph within the section.</p>
</div>
Enter fullscreen mode Exit fullscreen mode

Line Breaks: Line break is an example of formatting. Use line breaks to separate logical blocks of code, such as between different sections or elements. For example:

<header>
  <h1>Website Title</h1>
</header>

<main>
  <article>
    <h2>Article Title</h2>
    <p>Article content goes here.</p>
  </article>
</main>

<footer>
  <p>Footer content goes here.</p>
</footer>
Enter fullscreen mode Exit fullscreen mode

d. Clear and Descriptive Naming:

Using clear and descriptive names for IDs and classes helps others understand the purpose of each element quickly. Choose meaningful names that explain the content or purpose of the elements they refer to.

<div id="main-header" class="header">
  <h1>Website Title</h1>
</div>

<nav class="main-navigation">
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">Services</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>
Enter fullscreen mode Exit fullscreen mode

Consistent Naming Conventions: Stick to a consistent naming convention. For example, if you are using kebab-case for classes and IDs, use throughout.

<div class="content-wrapper">
  <section class="main-section">
    <h2 class="section-title">Section Title</h2>
    <p class="section-content">Content for this section.</p>
  </section>
</div>
Enter fullscreen mode Exit fullscreen mode

e. Separation of Files:

This means keeping different types of code separate. HTML code should be in Html file, stylings in Css file, and Javascript in Javascript files, which makes it easier to maintain and read the code.

HTML for Structure: Use HTML primarily for defining the structure and content of the web page, avoiding inline styles or scripts.

<article>
  <h2>Article Title</h2>
  <p>This is the content of the article.</p>
</article>
Enter fullscreen mode Exit fullscreen mode

CSS for Styling: Keep CSS in separate files or within <style> tags to handle the styling of the page. Example (external CSS file):

.article {
  font-family: Arial, sans-serif;
  color: blue;
}
Enter fullscreen mode Exit fullscreen mode

JavaScript for Behavior: Place JavaScript in separate files or within <script> tags to manage the behavior and interactivity. Example (external JavaScript file):

document.addEventListener('DOMContentLoaded', () => {
  const article = document.querySelector('.article');
  article.addEventListener('click', () => {
    alert('Article clicked!');
  });
});
Enter fullscreen mode Exit fullscreen mode

f. Consistent Document Flow:

A consistent document flow ensures that the content is presented in a logical and orderly manner. Organize your HTML to flow from top to bottom. This shows the reading order better:

<header>
  <h1>Website Title</h1>
</header>

<main>
  <section>
    <h2>Main Content</h2>
    <p>This is the main content area.</p>
  </section>

  <section>
    <h2>Secondary Content</h2>
    <p>This is the secondary content area.</p>
  </section>
</main>

<footer>
  <p>Footer content goes here.</p>
</footer>
Enter fullscreen mode Exit fullscreen mode

g. Comments and Documentation:

Adding comments and documentation helps explain the purpose and structure of the code, making it easy for future maintenance and collaboration. Use meaningful comments to explain the purpose of each sections. For example:

<!-- Main navigation menu -->
<nav>
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">Services</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>

<!-- Main content area -->
<main>
  <section>
    <h2>About Us</h2>
    <p>Information about our company.</p>
  </section>
</main>
Enter fullscreen mode Exit fullscreen mode

These comments should be used to section and group related parts of the code, making it easier to navigate:

<!-- Header Section -->
<header>
  <h1>Website Title</h1>
</header>

<!-- Navigation Section -->
<nav>
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">Services</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>

<!-- Main Content Section -->
<main>
  <section>
    <h2>About Us</h2>
    <p>Information about our company.</p>
  </section>
</main>

<!-- Footer Section -->
<footer>
  <p>&copy; 2024 Company Name</p>
</footer>
Enter fullscreen mode Exit fullscreen mode

h. Keeping HTML DRY (Don't Repeat Yourself):

The DRY (Don't Repeat Yourself) principle helps in reducing repetition of code. It, like the other practices, improves readability, and make it easier to maintain as it makes the process more efficient and less error-prone.

Techniques to Keep HTML DRY

Reusable Components: Create reusable components for elements that appear multiple times on your site. Use technologies like templates or frameworks that support component-based architectures.

Server-Side Includes (SSI): Use server-side includes to embed common elements (like headers, footers, and navigation menus) across multiple pages.

Client-Side Templating: Use client-side templating engines such as Mustache, Handlebars, or Pug to create reusable HTML templates that can be dynamically inserted into the page.

CSS Classes for Repeated Styles: Instead of repeating inline styles, use CSS classes to apply the same styles to multiple elements.

JavaScript for Dynamic Content: Use JavaScript to insert or generate repeated content, reducing the need to embed multiple instances of the same HTML.

Example using PHP Include:

Step 1: Create Reusable Components

First, create separate PHP files for the common elements you want to reuse across multiple pages, such as headers, footers, and navigation menus.

Header File (header.php):

<!-- header.php -->
<header>
  <h1>Website Title</h1>
  <nav>
    <ul>
      <li><a href="index.php">Home</a></li>
      <li><a href="about.php">About</a></li>
      <li><a href="contact.php">Contact</a></li>
    </ul>
  </nav>
</header>
Enter fullscreen mode Exit fullscreen mode

Footer File (footer.php):

<!-- footer.php -->
<footer>
  <p>&copy; 2024 Company Name. All rights reserved.</p>
</footer>
Enter fullscreen mode Exit fullscreen mode

Step 2: Include These Components in Your Main Files

Use the include or require statement in your main HTML files to insert these components.

Home Page (index.php):

<!-- index.php -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Home</title>
</head>
<body>
  <?php include 'header.php'; ?>

  <main>
    <h2>Welcome to Our Website</h2>
    <p>Home page content goes here.</p>
  </main>

  <?php include 'footer.php'; ?>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

About Page (about.php):

<!-- about.php -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>About</title>
</head>
<body>
  <?php include 'header.php'; ?>

  <main>
    <h2>About Us</h2>
    <p>Information about our company.</p>
  </main>

  <?php include 'footer.php'; ?>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

The advantage of the above is, any changes made to these components will automatically show across all the pages that include them. Above all, it makes the entire code cleaner.

Css Best Practices

A. Using a CSS Preprocessor

CSS preprocessors like SASS (Syntactically Awesome Style Sheets) and LESS (Leaner Style Sheets) enable developers to write more maintainable, efficient, and modular CSS. These preprocessors add features to CSS that make it easier to manage styles for larger projects, including variables, nesting, mixins, and functions.

Benefits of Using a CSS Preprocessor

Variables: Store reusable values (e.g., colors, font sizes) in variables, making it easy to update them across your stylesheet.

Nesting: Nest CSS rules to show the HTML structure, making the stylesheet more readable and maintainable.

Mixins: Create reusable part of CSS that can be included in other rules, reducing repetition.

Functions and Operations: Use functions and perform operations (e.g., calculations, color manipulations) to generate dynamic styles.

Example with SASS

Setting up Variables:

Instead of repeating the same color value throughout your Stylesheet, you can define them as variables.

//variables.scss
$primary-color: #3498db;
$secondary-color: #2ecc71;
$font-stack: 'Hevetica, Ariel, san-serif';
Enter fullscreen mode Exit fullscreen mode

Using Nesting:
Nesting allows to structure your css in a way that shows your HTML, improving readability.

// Style.scss
header {
  background: $primary-color;
  color: #fff;
  nav {
    ul {
      list-style: none;
      li {
        display: inline-block;
        margin-right: 10px;
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Creating Mixins:
Mixins help you define reusable CSS snippets.

// mixins.scss
@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
  -moz-border-radius: $radius;
  border-radius: $radius;
}

// Using the mixin
button {
  @include border-radius(5px);
  background: $secondary-color;
  color: #fff;
  padding: 10px 20px;
  border: none;
}
Enter fullscreen mode Exit fullscreen mode

Functions and Operations:
You can use functions and perform operations to dynamically generate styles.

// functions.scss
@function calculate-rem($size) {
  @return $size / 16px * 1rem;
}

// Using the function
body {
  font-size: calculate-rem(16px); // 1rem
}

h1 {
  font-size: calculate-rem(32px); // 2rem
}
Enter fullscreen mode Exit fullscreen mode

Importing Partial Files:
Organize your SASS code into multiple files and import them into a main file.

// main.scss
@import 'variables';
@import 'mixins';
@import 'functions';
@import 'styles';
Enter fullscreen mode Exit fullscreen mode

From the above, we see clearly that nesting provides a logical structure to styles, mixins reduce repetition of code, and functions enable dynamic and reusable styling. All these combine to write CSS that is cleaner, more modular, and easier to maintain.

B. Organizing and Structuring:

Organize your CSS into multiple files based on functionality to make it easy to maintain.

Example:

/* layout.css */
.header {
  background-color: #333;
  color: white;
}

.footer {
  background-color: #f1f1f1;
  color: #333;
}

/* typography.css */
body {
  font-family: 'Arial, sans-serif';
}

h1 {
  font-size: 2em;
}

/* forms.css */
input[type="text"] {
  border: 1px solid #ccc;
  padding: 10px;
}
Enter fullscreen mode Exit fullscreen mode

C. Naming Conventions:

Use consistent naming conventions. For example, if you choose to use the BEM (Block Element Modifier), use throughout.

<div class="card card--featured">
  <div class="card__header">Title</div>
  <div class="card__body">Content</div>
</div>
Enter fullscreen mode Exit fullscreen mode
.card {
  border: 1px solid #ccc;
  padding: 20px;
}

.card--featured {
  background-color: #f9f9f9;
}

.card__header {
  font-weight: bold;
}

.card__body {
  font-size: 14px;
}
Enter fullscreen mode Exit fullscreen mode

D. Commenting:

Add comments to document sections of your CSS.

Example:

/* Header Styles */
.header {
  background-color: #333;
  color: white;
}

/* Footer Styles */
.footer {
  background-color: #f1f1f1;
  color: #333;
}
Enter fullscreen mode Exit fullscreen mode

E. Consistent Formatting:

Use a consistent formatting style (line break) for readability.

Example:

.header {
  background-color: #333;
  color: white;
}

.footer {
  background-color: #f1f1f1;
  color: #333;
}
Enter fullscreen mode Exit fullscreen mode

F. Avoiding !important:

Minimize the use of !important to avoid specificity issues.

Example:

/* Avoid this */
.button {
  background-color: blue !important;
}

/* Prefer this */
.button {
  background-color: blue;
}
Enter fullscreen mode Exit fullscreen mode

G. Efficient Styling with Selectors:

Use specific class and ID selectors for better performance to make it easier to maintain.

Example:

/* Prefer this */
.navbar {
  background-color: #333;
}

/* Overly specific */
div.container .navbar {
  background-color: #333;
}
Enter fullscreen mode Exit fullscreen mode

Overly specific selectors can become difficult to maintain, make styles harder to override, and can cause unexpected behavior if another rule with slightly lower specificity tries to style the same element.

H. Use Utility Classes:

Create utility classes for common styles to promote reuse. A utility class in CSS is a single-purpose class that applies a specific styling rule or a small set of rules to an element.

Example:

/* Utility classes */
.text-center {
  text-align: center;
}

.margin-top-small {
  margin-top: 10px;
}

/* Usage */
<div class="text-center margin-top-small">Centered text with margin</div>
Enter fullscreen mode Exit fullscreen mode

JavaScript Best Practices

a. Use let and const Instead of var:

let and const have block scope, which helps prevent common bugs related to variable hoisting and scope issues.

Example:

// Using let
let count = 1;
count = 2; // Valid

// Using const
const name = 'Robert';
// name = 'Kingsley'; // Error: Assignment to constant variable
Enter fullscreen mode Exit fullscreen mode

b. Use Descriptive Variable and Function Names:

Choose meaningful names that clearly describe the variable's or function's purpose.

Example:

// Good
let userName = 'Donald';
function getUserAge(user) {
  return user.age;
}

// Bad
let x = 'Donald';
function foo(u) {
  return u.a;
}
Enter fullscreen mode Exit fullscreen mode

c. Less and straightforward functions:

Functions should perform a single task. This makes them easier to test and maintain.

Example:

// Good
function add(a, b) {
  return a + b;
}

function multiply(a, b) {
  return a * b;
}

// Bad
function calculate(a, b) {
  const sum = a + b;
  const product = a * b;
  return [sum, product];
}
Enter fullscreen mode Exit fullscreen mode

d. Use Strict Equality (===) and Inequality (!==) :

Strict equality checks both value and type, preventing unexpected type coercion.

Example:

// Good
if (age === 18) {
  console.log('You are 18 years old.');
}

// Bad
if (age == 18) {
  console.log('You are 18 years old.');
}
Enter fullscreen mode Exit fullscreen mode

e. Use Template Literals for Strings:

Template literals make it easier to include variables and expressions inside strings.

Example:

// Good
let name = 'Robert';
let greeting = `Hello, ${name}!`;

// Bad
let greeting = 'Hello, ' + name + '!';
Enter fullscreen mode Exit fullscreen mode

f. Use Default Parameters:

Default parameters helps handle cases where arguments are not provided.

Example:

// Good
function greet(name = 'Guest') {
  console.log(`Hello, ${name}!`);
}

greet(); // Hello, Guest!

// Bad
function greet(name) {
  if (name === undefined) {
    name = 'Guest';
  }
  console.log(`Hello, ${name}!`);
}
Enter fullscreen mode Exit fullscreen mode

g. Use Array and Object Destructuring:

Destructuring helps extract values from arrays or properties from objects into different variables.

Example:

// Good
const user = { name: 'Robert', age: 25 };
const { name, age } = user;

const numbers = [1, 2, 3];
const [first, second] = numbers;

// Bad
const user = { name: 'Robert', age: 25 };
const name = user.name;
const age = user.age;

const numbers = [1, 2, 3];
const first = numbers[0];
const second = numbers[1];
Enter fullscreen mode Exit fullscreen mode

h. Avoid Global Variables:

Global variables can lead to conflicts and bugs. Always declare variables within the scope they are needed.

Example:

// Good
function calculateSum() {
  let sum = 0;
  // code to calculate sum
  return sum;
}

// Bad
let sum = 0; // Global variable
function calculateSum() {
  // code to calculate sum
  return sum;
}
Enter fullscreen mode Exit fullscreen mode

i. Use Comments appropriately:

Comments should explain the why behind the code, not the what. They are useful for complex logic or important details.

Example:

// Good
// Calculate the sum of all items in the array
function calculateTotal(items) {
  let total = 0;
  items.forEach(item => {
    total += item;
  });
  return total;
}

// Bad
function calculateTotal(items) {
  // This function calculates the total
  let total = 0;
  items.forEach(item => {
    total += item; // Add item to total
  });
  return total;
}
Enter fullscreen mode Exit fullscreen mode

j. Use Array Methods Instead of Loops:

Methods like map, filter, and forEach are often more readable and concise than loops.

Example:

// Good
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2); // [2, 4, 6]

// Bad
const numbers = [1, 2, 3];
const doubled = [];
for (let i = 0; i < numbers.length; i++) {
  doubled.push(numbers[i] * 2);
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Follow these standards for HTML, CSS and JavaScript to create clean, maintainable and efficient code. Well-written code is easier for you and others to understand, but it also forms a good foundation for future development of the code. Well-written code saves time when debugging or wanting to add new features to any existing code. It makes it easier to collaborate with others

Top comments (1)

Collapse
 
jennijuli3 profile image
Jenni Juli

Best content thank you for posting. Best software Training institute in chennai for all the software related courses.