Important
You are browsing the documentation for version 4.2 of OroCommerce, OroCRM and OroPlatform, which is no longer maintained. Read version 5.1 (the latest LTS version) of the Oro documentation to get up-to-date information.
See our Release Process documentation for more information on the currently supported and upcoming releases.
Oro Frontend Development Guidelines¶
Oro Frontend Development Guidelines describe the Code style, a set of conventions that describe the way to write code.
Naming Conventions¶
The main idea of the naming convention is to create names as informative and clear as possible.
Selector Naming¶
Selector names are lowercase and their logical parts are divided by a dash (-).
Acceptable
product-gallery-widget
Unacceptable
productgallerywidget, productGalleryWidget, product_gallery_widget
Block Name¶
A block is a logical self-contained functional component of the user interface.
A block identifier should match the corresponding layout block type identifier.
Block names (part of the block identifier) may be prefixed with a short namespace or a bundle identifier if similar blocks are provided by multiple bundles to eliminate confusion, for instance.
Examples:
product-info, shopping-cart, currency-switcher
order-group-totals and quote-group-totals, or even crm-quote-group-totals and commerce-quote-group-totals
Element Name¶
The namespace of an element (which is equal to the parent block ID) identifies the element as belonging to the block.
In the element identifier, the element name is delimited from the element namespace by a double underscore (**__**):
block-name\_\_elem-name
If a block has several identical elements (e.g., menu items), all of them will have the same name (e.g. menu__item).
Modifier Name¶
The namespace of a modifier (which is equal to the parent block ID or the parent element ID) identifies the modifier as belonging to the block or the element.
The modifier name is delimited by a single underscore (_) from the modifier namespace:
for Boolean modifiers - owner-name_mod-name
for key-value type modifiers - owner-name_mod-name–mod-val
This gives the following advantages:
The logic of naming enables you to immediately understand what a particular class represents.
Decreases the possible conflict issues between classes.
Each element is in the namespace.
Components are easily transferred from project to project.
HTML Coding Standards¶
Base Code Style¶
Do not add a slash at the end of single elements.
The attributes in use are “ “, not ‘ ‘.
No spaces or tabs after the closing tag.
Indent only with spaces.
The attachment elements are indented with 4 spaces.
Simple Names¶
<div class="product">
<p class="product__name">Product name</p>
<div class="product__prices">...</div>
<div class="product__info">...</div>
</div>
The Order of the Attributes¶
The required and optional attributes for the tag (e.g., name, type, src, href, etc).
Attributes used for UI customization (e.g., class, data-*, etc).
Attributes with JSON content.
<input name type id
class
data-*
data-entity="{{ {
id: entity.id,
title: entity.title
}|json_encode }}"
/>
CSS Coding Standards¶
Base Code Style¶
Built on SASS preprocessor.
Focused on web standards.
The Principles of CSS Architecture¶
Predictability — Predictability for CSS means that your rules are behaving as expected.
Reusable — CSS rules should be abstract and decoupled enough for you to build new components quickly from existing parts without having to recode patterns and problems that you have already solved.
Scalable — Scalable CSS means that it can be easily managed by a single person or a large engineering team.
Support — When new components and features need to be added, updated or rearranged on your site, doing so should not require refactoring existing CSS.
Responsive — We use CSS to resize, hide, shrink, enlarge, or move the content to make it look good on any screen.
SASS Code Standards¶
Use the .scss syntax.
Indentation only with spaces.
Indent size: 4 spaces
Continuation indent: 4 spaces
The attributes in use are ‘ ‘ not “ “.
Use: {}, :, ;.
Put a space before the opening brace { in rule declarations.
Put the closing braces } of rule declarations on a new line.
Each component is written in a separate file.
Do not write vendors’ prefixes.
Format¶
Add a space before the opening brace and a line break after. Add a line break before closing brace.
Acceptable
.element {
color: $color;
}
Unacceptable
.element{color: $color;}
Selector Delimiters¶
Add a line break after each selector delimiter. Delimiter should not have spaces before and after.
Acceptable
.element1,
.element2 {
color: $color;
}
Unacceptable
.element1, .element2 {
color: $color;
}
Type Selectors¶
Unless necessary (for example with helper classes), do not use element names in conjunction with IDs or classes. Avoiding unnecessary ancestor selectors is useful for performance reasons.
Acceptable
.element {
...
}
Unacceptable
div.element {
...
}
div#element {
...
}
Combinator Indents¶
Use spaces before and after combinators.
Acceptable
.element1 + .element2 {
color: $color;
}
Unacceptable
.element1+.element2 {
color: $color;
}
Properties Line Break¶
Use line break for each property declaration.
Acceptable
.element {
position: absolute;
top: 0;
left: 0;
}
Unacceptable
.element {
position: absolute; top: 0; left: 0;
}
Properties Colon Indents¶
Use no space before property colon and a space after.
Acceptable
.element {
color: $color;
}
Unacceptable
.element1 {
color : $color;
}
.element2 {
color:$color;
}
.element3 {
color :$color;
}
End of the Selector¶
Each selector should be finished with a new line.
Acceptable
.element1 {
color: $color;
}
.element2 {
color: $color;
}
Unacceptable
.element1 {
color: $color;
}
.element2 {
color: $color;
}
Shorthand¶
If you use more than 2 parameters (three indents, for example), write short:
.element {
margin: 10px 0 5px;
}
If less, then:
.element {
margin-top: 10px;
margin-right: 2px;
}
Floating Values¶
Do not add zero for fractional numbers.
Acceptable
.element {
opacity: .5;
}
Unacceptable
.element {
opacity: 0.5;
}
Zero and Units¶
Omit the units for zero value.
Acceptable
.element {
margin: 0;
}
Unacceptable
.element {
margin: 0px;
}
Border¶
Use 0 instead of none to specify that a style has no border.
Acceptable
.element {
border: 0;
}
Unacceptable
.element {
border: none;
}
Nesting¶
When selectors become quite long, you may write CSS that is:
Strongly coupled to the HTML
Overly specific
Not reusable
Selector Nesting¶
Be careful with selector nesting. In general try to use 2 nested levels max.
Exceptions are pseudo elements and states.
Acceptable
.block {
&__element {
&--modifier {
...
}
}
&--modifier {
...
}
}
Unacceptable
.block {
...
.block__element {
...
&.block__element--modifier {
// STOP!
}
}
&.block--modifier {}
}
No Elements of Elements¶
According to BEM methodology, there are no elements of elements. It makes the elements dependent on the block only. So, you can easily move them across the block when providing changes to the interface.
Acceptable
.block {
...
.block__some-element {
...
}
.block__other-element {
...
}
}
Unacceptable
.block {
...
.block__some-element {
...
.block__some-element__other-element {
// STOP!
}
}
}
Place of @media Rules¶
All @media rules are placed at the end of file. The block applies only to the common styles for all devices. @media describes individual styles for each type of device. This enables us to change or add styles only for a specific type of device in the future.
Acceptable
.block {
width: 50%;
padding: 10px;
background-color: get-color('additional', 'middle');
&__element {
font-size: 12px;
}
}
@include breakpoint('tablet') {
.block {
width: 100%;
}
}
@include breakpoint('mobile') {
.block {
padding: 15px;
&__element {
font-size: 15px;
}
}
}
Unacceptable
.block {
width: 50%;
padding: 10px;
background-color: get-color('additional', 'middle');
@include breakpoint('tablet') {
width: 100%;
}
@include breakpoint('mobile') {
padding: 15px;
}
&__element {
font-size: 12px;
// STOP!
@include breakpoint('mobile') {
font-size: 15px;
}
}
}
Work with Colors¶
To work with a color, use the get-color() function which returns a color from a predefined color scheme.
Example:
.block {
border-color: get-color('additional', 'light');
color: get-color('primary', 'main');
}
If you need darker, lighter or more transparent color, use the native Sass functions: darken(), lighten(), transparentize(), etc.
.block {
background-color: transparentize(get-color('primary', 'main'), .8);
border-color: darken(get-color('additional', 'light'), 10%);
color: lighten(get-color('primary', 'main'), 10%);
}
Group Properties¶
Group properties are grouped in the following order:
variables
positioning
block model
typography
visualization
other (animation, opacity)
mixins
Each group should be followed by an empty string.
In CSS, each property can be treated in different groups depending on their use: vertical-align, overflow, clear, resize, transform.
Acceptable
// variables
$element-color: #000 !default;
$element-font: 12px !default;
$element-line-height: 1.2 !default;
.element {
// positioning
position: absolute;
top: 0;
right: 0;
z-index: z('fixed');
// block model
width: 100px;
height: 100px;
margin: 10px;
padding: 10px 20px;
// typography
font-size: $element-font;
line-height: $element-line-height;
text-align: center;
// visualization
border: 10px solid #333;
background: red;
color: $element-color;
// other
cursor: pointer;
opacity: .2;
// mixins
// grouping @includes at the end makes it easier to read the entire selector.
@include clearfix;
}
Unacceptable
.element {
text-align: center;
margin: 0;
$color: #000;
@include clearfix;
color: $color;
right: 0;
position: absolute;
}
Use @extend Directive¶
Use @extend only selector that is a single class.
Helper class include after variables.
Helper class has maximum 5 rules.
Helper class has abstract name and overall design style.
Examples:
$default-size: 400px !default;
$default-offset: 10px auto !default;
$default-inner-offset: 15px !default;
$default-background: #dadada !default;
%dialog {
width: $default-size;
margin: $default-offset;
padding: $default-inner-offset;
background: $default-background;
}
.modal {
// other modal styles
@extend %dialog;
&__close {
// other button styles
@extend %dialog__close;
}
&__header {
// other header styles
@extend %background-gradient;
}
}
Logical Sense¶
Use the logical number of modifiers for the element.
Acceptable
“Quiet classes”
%modifier {}
%another-modifier {}
%yet-another-modifier {}
.block {
&__element {
&--modifier {
@extend %modifier;
@extend %another-modifier;
@extend %yet-another-modifier;
}
}
}
<div class="block">
<div class="
block__element
block__element--modifier">
</div>
</div>
Unacceptable
<div class="block">
<div class="
block__element
block__element--modifier
block__element--another-modifier
block__element--yet-another-modifier">
</div>
</div>
The Main Mixins and Functions¶
Helper to clear inner floats.
@mixin clearfix {
&:after {
content: '';
display: block;
clear: both;
}
}
// use
.block {
@include clearfix;
}
Helper for the positioning of pseudo-elements.
@mixin after {
content: '';
position: absolute;
display: block;
}
// use
.block {
//...
&:after {
@include after;
}
}
Helper function for organizing z-index
@function z($layer) {
$layers: (
'base': 1,
'fixed': 50,
'dropdown': 100,
'popup': 150,
'hidden': -1
);
$z-index: map-get($layers, $layer);
@return $z-index;
}
// use
.dialog {
//...
z-index: z('popup') + 1;
&-overley {
//...
z-index: z('popup');
}
}
Helper mixin for organizing @media rules
@mixin breakpoint($type) {
$breakpoints: (
'large': '(max-width: ' + #{$breakpoint-large} + ')',
'tablet': '(max-width: ' + #{$breakpoint-tablet} + ')',
'mobile': '(max-width: ' + #{$breakpoint-mobile} + ')'
);
@media #{map-get($breakpoints, $type)} {
@content;
}
}
// use
@include breakpoint('tablet') {
// styles for tablet version
}
Best Practices¶
$block-font-title: 'Tahoma' !default;
$block-offset: 10px !default;
.block {
@include clearfix;
&:hover {
background-color: get-color('secondary', 'light');
}
&__element {
float: left;
width: 25%;
padding-left: $list-offset * 2;
font-size: 14px;
@extend %transition;
&:hover {
border-color: get-color('additional', 'middle');
}
// compound class
&-title {
margin-bottom: $list-offset;
font-family: $list-font-title;
font-size: 22px;
line-height: 1.1;
}
&--first {
padding-left: 0;
}
}
&__content {
padding: $list-offset ($list-offset * 2);
}
// State written &. (the active state of the menu item, for example).
// Usually dynamic.
&.expand {
...
}
}
@include breakpoint('tablet') {
.block {
width: 100%;
&__content {
padding: $list-offset * 2;
font-size: 15px;
}
}
}
@include breakpoint('mobile') {
.block {
&__element {
width: 100%;
&-title {
margin-bottom: 0;
font-size: 25px;
}
}
}
}
Comments¶
Prefer the // line comments to block comments.
Prefer comments on their own line. Avoid end-of-line comments.
Acceptable
Unacceptable