Skip navigation

Coding convention

One page summary of how to works on Frontend project.

General

Resources can be loaded without relying on a specific order

Given that Optimizly CMS is block-based, components may appear multiple times on a page. Ensure that your scripts accommodate this scenario, allowing all blocks to function as expected.

Editor Config

All new scripts must use TypeScript and follow the ES Module format.

For new projects that do not have specific coding convention requirements, the following rules should be applied in the .editorconfig file:

.editorconfig file:

root = true

[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
max_line_length = 150

[CHANGELOG.md]
indent_size = false

.prettierrc.yaml file:

# Documentation: https://prettier.io/docs/en/options.html

trailingComma: es5
tabWidth: 2
useTabs: false
semi: true
endOfLine: lf
singleQuote: true
bracketSpacing: true
bracketSameLine: false
arrowParens: always
htmlWhitespaceSensitivity: css
singleAttributePerLine: false

# JSX
jsxSingleQuote: false

# Vue
vueIndentScriptAndStyle: false

Should a customer have specific rules, these should take precedence over the above rules.

To enforce these rules, install Prettier and enable it in Visual Studio Code. Additionally, ensure that Format on Paste and Format on Save are enabled in Visual Studio Code's settings.

CSS

Use relative units when possible

For the root element of the DOM, typically represented by the <html> tag, set the font size using pixels (px), as shown below:

html {
  font-size: 16px; /* Some websites may opt for 10px */
}

When specifying breakpoints for media queries, continue to use the pixel unit (px).

For all other CSS properties:

  • Utilize relative units such as %, em, rem, vw, vh, ch, ex, vmin, vmax.
    It's advisable to minimize the use of ch, ex, vmin, and vmax units in our codebase, if possible.

  • Avoi absolute units such as mm, cm, in, pt, pc, px.

We provide a px2rem mixin to facilitate the conversion from pixels (px) to rems (rem). For instance, if the root element has a font-size of 16px, invoking px2rem(32px) will return 2rem.

Naming convention

When it comes to naming conventions, it is strongly recommended that all class names adhere to the BEM (Block Element Modifier) methodology. This recommendation is particularly pertinent when the HTML needs to be integrated by the Backend team. BEM offers the advantage of requiring minimal to no reintegration effort in the event of styling changes. It's worth noting that naming conventions such as Tailwind CSS or other Atomic CSS-like methodologies are not particularly suitable in this context.

However, if the HTML is generated from the client-side or does not necessitate integration by the Backend team, alternative naming conventions can be considered. Nevertheless, even in these cases, BEM remains highly recommended.

Breakpoints

We adopt a mobile-first approach, meaning that CSS rules are initially applied to all screen sizes by default.

For styles that should apply to both tablet and desktop screens, use @include tablet.
For styles exclusive to desktop screens, use @include desktop.

Below are sample mixins for these breakpoints:

@mixin tablet {
  @media (min-width: px2rem(768px)) {
    @content;
  }
}

@mixin desktop {
  @media (min-width: px2rem(1024px)) {
    @content;
  }
}

In most cases, you will only need to use @include tablet for both tablet and desktop unless there are specific differences mentioned in the user story.

The number of breakpoints and the media queries for each breakpoint may vary from one project to another, but we consistently adhere to the mobile-first approach.

For example, an element with the target class will have a

black color on mobile and a blue color on tablet and desktop:

.target {
  color: black;

  @include tablet {
    color: blue;
  }
}

Alternatively, if an element with the target class should have a black color on mobile, a blue color on tablet, and a red color on desktop, you can achieve it like this:

.target {
  color: black;

  @include tablet {
    color: blue;
  }

  @include desktop {
    color: red;
  }
}
Define rich text styles globally

When styling Rich Text content, apply styles at a global level rather than per block. For example, if the design specifies:

  • H2 elements in Rich Text Blocks (RTB) should have a font size of 24px
  • Base font size for Rich Text should be 16px

The global CSS should be:

body {
  font-size: 16px;
}

h2 {
  font-size: 24px;
}

With this approach, all blocks will inherit these base styles by default. If a specific block needs a custom style, it can override the global style like this:

.block__heading {
  font-size: 32px;
}
Avoid excessive sub-block style files

When building UI components, avoid splitting styles into too many separate files, such as these files for an Accordion Block:

  • accordion.scss
  • accordion-item.scss

Loading multiple CSS files results in unnecessary HTTP requests. Since accordion-item.scss is unlikely to be reused outside the Accordion Block, it's better to structure those styles like this:

  • _block.scss
  • _item.scss
  • accordion.scss

In accordion.scss, import the internal styles:

@import 'block';
@import 'item';

This way, only one CSS file is delivered to the browser, improving performance and maintainability.

If an element is likely to be reused across multiple blocks, consider moving its styles into a shared base CSS file. It's generally preferable to have a slightly larger base CSS file than to duplicate the same styles in multiple block-specific files.

However, if the element is only reused in a few blocks - and those blocks don't appear frequently across pages - it's more efficient to duplicate the styles within each block rather than include them in the base CSS.

Ideally, each block should be associated with a single CSS file. In certain cases, it may make sense to split styles into multiple files for a block, but this should be done with care and only after thorough review.

Centralize z-index values

Define all z-index values as SCSS variables in a single location, rather than hardcoding them in individual elements. This approach provides better visibility and control over the stacking order across the UI. It helps you understand which elements use z-index and how they relate to each other in the visual hierarchy.

When introducing a new element that requires z-index, you’ll know exactly which value to assign to maintain the correct stacking order.

Example:

$header-z-index: 100;
$video-overlay-z-index: 90;
Favor SCSS variables over direct CSS variables

Using SCSS variables to reference CSS variables allows you to manage related values in one central place, making them easier to maintain and update.

Example:

// variables.scss
$fg: var(--fg);
$bg: var(--bg);

// light-theme
--fg: #000;
--bg: #fff;

// dark-theme.scss
--fg: #fff;
--bg: #000;

// base.scss
body {
  color: $fg;
  background-color: $bg;
}

By assigning CSS variables to SCSS variables (e.g., $fg), you gain the benefits of SCSS features like error checking. For instance, if you accidentally reference a non-existent variable like $foreground-color, the SCSS compiler will throw an error, helping you catch mistakes early and avoid broken builds.