mirror of
https://github.com/odoo/documentation.git
synced 2025-12-17 18:09:11 +07:00
[IMP] scss: update, improve preexisting content
Add a new content focused on SCSS and user-interface.
- SCSS coding guidelines: regroup information already available (eg [1])
or based on "oral tradition".
The aim is not to establish new rules, ~99% of the current codebase
is already compliant.
- SCSS inheritance: explain how SCSS assets management works in odoo.
For example, people still find confusing that overrides are defined
*before* the variable to customize.
- SCSS optimization tips: suggestions to lean SCSS code. Based on SCSS
optimization task's know-how [2].
- CSS variables: explain how this feature is commonly used in odoo to
adapt layout & design without raw CSS overrides.
- UI Icons: Add link to fontAwesome4 library . Replace the picture of
odoo icons with the actual font (90kb image VS 15Kb font)
[1] https://github.com/odoo/odoo/wiki/SCSS-coding-guidelines
[2] https://www.odoo.com/web#id=2704984&menu_id=4720&cids=1&model=project.task&view_type=form
task-3090800
closes odoo/documentation#3327
X-original-commit: 2ca32b40bc
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
This commit is contained in:
committed by
Antoine Vandevenne (anv)
parent
8a30786495
commit
9571a32131
@@ -921,8 +921,8 @@ Symbols and Conventions
|
||||
|
||||
.. _contributing/development/js_guidelines:
|
||||
|
||||
Javascript and CSS
|
||||
==================
|
||||
Javascript
|
||||
==========
|
||||
|
||||
Static files organization
|
||||
--------------------------
|
||||
@@ -969,14 +969,373 @@ More precise JS guidelines are detailed in the `github wiki <https://github.com
|
||||
You may also have a look at existing API in Javascript by looking Javascript
|
||||
References.
|
||||
|
||||
CSS coding guidelines
|
||||
.. _contributing/coding_guidelines/scss:
|
||||
|
||||
CSS and SCSS
|
||||
============
|
||||
|
||||
.. _contributing/coding_guidelines/scss/formatting:
|
||||
|
||||
Syntax and Formatting
|
||||
---------------------
|
||||
|
||||
- Prefix all your classes with *o_<module_name>* where *module_name* is the
|
||||
technical name of the module ('sale', 'im_chat', ...) or the main route
|
||||
reserved by the module (for website module mainly, i.e. : 'o_forum' for
|
||||
*website_forum* module). The only exception for this rule is the
|
||||
webclient: it simply uses *o_* prefix.
|
||||
- Avoid using *id* tag
|
||||
- Use Bootstrap native classes
|
||||
- Use underscore lowercase notation to name class
|
||||
.. tabs::
|
||||
|
||||
.. code-tab:: html SCSS
|
||||
|
||||
.o_foo, .o_foo_bar, .o_baz {
|
||||
height: $o-statusbar-height;
|
||||
|
||||
.o_qux {
|
||||
height: $o-statusbar-height * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.o_corge {
|
||||
background: $o-list-footer-bg-color;
|
||||
}
|
||||
|
||||
.. code-tab:: css CSS
|
||||
|
||||
.o_foo, .o_foo_bar, .o_baz {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.o_foo .o_quux, .o_foo_bar .o_quux, .o_baz .o_qux {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.o_corge {
|
||||
background: #EAEAEA;
|
||||
}
|
||||
|
||||
- four (4) space indents, no tabs;
|
||||
- columns of max. 80 characters wide;
|
||||
- opening brace (`{`): empty space after the last selector;
|
||||
- closing brace (`}`): on its own new line;
|
||||
- one line for each declaration;
|
||||
- meaningful use of whitespace.
|
||||
|
||||
.. spoiler:: Suggested Stylelint settings
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
"stylelint.config": {
|
||||
"rules": {
|
||||
// https://stylelint.io/user-guide/rules
|
||||
|
||||
// Avoid errors
|
||||
"block-no-empty": true,
|
||||
"shorthand-property-no-redundant-values": true,
|
||||
"declaration-block-no-shorthand-property-overrides": true,
|
||||
|
||||
// Stylistic conventions
|
||||
"indentation": 4,
|
||||
|
||||
"function-comma-space-after": "always",
|
||||
"function-parentheses-space-inside": "never",
|
||||
"function-whitespace-after": "always",
|
||||
|
||||
"unit-case": "lower",
|
||||
|
||||
"value-list-comma-space-after": "always-single-line",
|
||||
|
||||
"declaration-bang-space-after": "never",
|
||||
"declaration-bang-space-before": "always",
|
||||
"declaration-colon-space-after": "always",
|
||||
"declaration-colon-space-before": "never",
|
||||
|
||||
"block-closing-brace-empty-line-before": "never",
|
||||
"block-opening-brace-space-before": "always",
|
||||
|
||||
"selector-attribute-brackets-space-inside": "never",
|
||||
"selector-list-comma-space-after": "always-single-line",
|
||||
"selector-list-comma-space-before": "never-single-line",
|
||||
}
|
||||
},
|
||||
|
||||
.. _contributing/coding_guidelines/scss/properties_order:
|
||||
|
||||
Properties order
|
||||
----------------
|
||||
|
||||
Order properties from the "outside" in, starting from `position` and ending with decorative rules
|
||||
(`font`, `filter`, etc.).
|
||||
|
||||
:ref:`Scoped SCSS variables <contributing/coding_guidelines/scss/scoped_scss_variables>` and
|
||||
:ref:`CSS variables <contributing/coding_guidelines/scss/css_variables>` must be placed at the very
|
||||
top, followed by an empty line separating them from other declarations.
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
.o_element {
|
||||
$-inner-gap: $border-width + $legend-margin-bottom;
|
||||
|
||||
--element-margin: 1rem;
|
||||
--element-size: 3rem;
|
||||
|
||||
@include o-position-absolute(1rem);
|
||||
display: block;
|
||||
margin: var(--element-margin);
|
||||
width: calc(var(--element-size) + #{$-inner-gap});
|
||||
border: 0;
|
||||
padding: 1rem;
|
||||
background: blue;
|
||||
font-size: 1rem;
|
||||
filter: blur(2px);
|
||||
}
|
||||
|
||||
.. _contributing/coding_guidelines/scss/naming_conventions:
|
||||
|
||||
Naming Conventions
|
||||
------------------
|
||||
|
||||
Naming conventions in CSS are incredibly useful in making your code more strict, transparent and
|
||||
informative.
|
||||
|
||||
| Avoid `id` selectors, and prefix your classes with `o_<module_name>`, where `<module_name>` is the
|
||||
technical name of the module (`sale`, `im_chat`, ...) or the main route reserved by the module
|
||||
(for website modules mainly, i.e. : `o_forum` for the `website_forum` module).
|
||||
| The only exception for this rule is the webclient: it simply uses the `o_` prefix.
|
||||
|
||||
Avoid creating hyper-specific classes and variable names. When naming nested elements, opt for the
|
||||
"Grandchild" approach.
|
||||
|
||||
.. rst-class:: bg-light
|
||||
.. example::
|
||||
|
||||
.. container:: alert alert-danger
|
||||
|
||||
Don't
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<div class=“o_element_wrapper”>
|
||||
<div class=“o_element_wrapper_entries”>
|
||||
<span class=“o_element_wrapper_entries_entry”>
|
||||
<a class=“o_element_wrapper_entries_entry_link”>Entry</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
.. container:: alert alert-success
|
||||
|
||||
Do
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<div class=“o_element_wrapper”>
|
||||
<div class=“o_element_entries”>
|
||||
<span class=“o_element_entry”>
|
||||
<a class=“o_element_link”>Entry</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Besides being more compact, this approach eases maintenance because it limits the need of renaming
|
||||
when changes occur at the DOM.
|
||||
|
||||
.. _contributing/coding_guidelines/scss/scss_variables:
|
||||
|
||||
SCSS Variables
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Our standard convention is `$o-[root]-[element]-[property]-[modifier]`, with:
|
||||
|
||||
* `$o-`
|
||||
The prefix.
|
||||
* `[root]`
|
||||
Either the component **or** the module name (components take priority).
|
||||
* `[element]`
|
||||
An optional identifier for inner elements.
|
||||
* `[property]`
|
||||
The property/behavior defined by the variable.
|
||||
* `[modifier]`
|
||||
An optional modifier.
|
||||
|
||||
.. example::
|
||||
|
||||
.. code-block:: scss
|
||||
|
||||
$o-block-color: value;
|
||||
$o-block-title-color: value;
|
||||
$o-block-title-color-hover: value;
|
||||
|
||||
.. _contributing/coding_guidelines/scss/scoped_scss_variables:
|
||||
|
||||
SCSS Variables (scoped)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
These variables are declared within blocks and are not accessible from the outside.
|
||||
Our standard convention is `$-[variable name]`.
|
||||
|
||||
.. example::
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
.o_element {
|
||||
$-inner-gap: compute-something;
|
||||
|
||||
margin-right: $-inner-gap;
|
||||
|
||||
.o_element_child {
|
||||
margin-right: $-inner-gap * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.. seealso::
|
||||
`Variables scope on the SASS Documentation
|
||||
<https://sass-lang.com/documentation/variables#scope>`_
|
||||
|
||||
.. _contributing/coding_guidelines/scss/mixins:
|
||||
|
||||
SCSS Mixins and Functions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Our standard convention is `o-[name]`. Use descriptive names. When naming functions, use verbs in
|
||||
the imperative form (e.g.: `get`, `make`, `apply`...).
|
||||
|
||||
Name optional arguments in the :ref:`scoped variables form
|
||||
<contributing/coding_guidelines/scss/scoped_scss_variables>`, so `$-[argument]`.
|
||||
|
||||
.. example::
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
@mixin o-avatar($-size: 1.5em, $-radius: 100%) {
|
||||
width: $-size;
|
||||
height: $-size;
|
||||
border-radius: $-radius;
|
||||
}
|
||||
|
||||
@function o-invert-color($-color, $-amount: 100%) {
|
||||
$-inverse: change-color($-color, $-hue: hue($-color) + 180);
|
||||
|
||||
@return mix($-inverse, $-color, $-amount);
|
||||
}
|
||||
|
||||
.. seealso::
|
||||
- `Mixins on the SASS Documentation <https://sass-lang.com/documentation/at-rules/mixin>`_
|
||||
- `Functions on the SASS Documentation <https://sass-lang.com/documentation/at-rules/function>`_
|
||||
|
||||
.. _contributing/coding_guidelines/scss/css_variables:
|
||||
|
||||
CSS Variables
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
In Odoo, the use of CSS variables is strictly DOM-related. Use them to **contextually** adapt the
|
||||
design and layout.
|
||||
|
||||
Our standard convention is BEM, so `--[root]__[element]-[property]--[modifier]`, with:
|
||||
|
||||
* `[root]`
|
||||
Either the component **or** the module name (components take priority).
|
||||
* `[element]`
|
||||
An optional identifier for inner elements.
|
||||
* `[property]`
|
||||
The property/behavior defined by the variable.
|
||||
* `[modifier]`
|
||||
An optional modifier.
|
||||
|
||||
.. example::
|
||||
|
||||
.. code-block:: scss
|
||||
|
||||
.o_kanban_record {
|
||||
--KanbanRecord-width: value;
|
||||
--KanbanRecord__picture-border: value;
|
||||
--KanbanRecord__picture-border--active: value;
|
||||
}
|
||||
|
||||
// Adapt the component when rendered in another context.
|
||||
.o_form_view {
|
||||
--KanbanRecord-width: another-value;
|
||||
--KanbanRecord__picture-border: another-value;
|
||||
--KanbanRecord__picture-border--active: another-value;
|
||||
}
|
||||
|
||||
.. _contributing/coding_guidelines/scss/variables_use:
|
||||
|
||||
Use of CSS Variables
|
||||
--------------------
|
||||
|
||||
In Odoo, the use of CSS variables is strictly DOM-related, meaning that are used to **contextually**
|
||||
adapt the design and layout rather than to manage the global design-system. These are typically used
|
||||
when a component's properties can vary in specific contexts or in other circumstances.
|
||||
|
||||
We define these properties inside the component's main block, providing default fallbacks.
|
||||
|
||||
.. example::
|
||||
|
||||
.. code-block:: scss
|
||||
:caption: :file:`my_component.scss`
|
||||
|
||||
.o_MyComponent {
|
||||
color: var(--MyComponent-color, #313131);
|
||||
}
|
||||
|
||||
.. code-block:: scss
|
||||
:caption: :file:`my_dashboard.scss`
|
||||
|
||||
.o_MyDashboard {
|
||||
// Adapt the component in this context only
|
||||
--MyComponent-color: #017e84;
|
||||
}
|
||||
|
||||
.. seealso::
|
||||
`CSS variables on MDN web docs
|
||||
<https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties>`_
|
||||
|
||||
.. _contributing/coding_guidelines/scss/css_scss_variables_use:
|
||||
|
||||
CSS and SCSS Variables
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Despite being apparently similar, `CSS` and `SCSS` variables behave very differently. The main
|
||||
difference is that, while `SCSS` variables are **imperative** and compiled away, `CSS` variables are
|
||||
**declarative** and included in the final output.
|
||||
|
||||
.. seealso::
|
||||
`CSS/SCSS variables difference on the SASS Documentation
|
||||
<https://sass-lang.com/documentation/variables#:~:text=CSS%20variables%20are%20included%20in,use%20will%20stay%20the%20same>`_
|
||||
|
||||
In Odoo, we take the best of both worlds: using the `SCSS` variables to define the design-system
|
||||
while opting for the `CSS` ones when it comes to contextual adaptations.
|
||||
|
||||
The implementation of the previous example should be improved by adding SCSS variables in order to
|
||||
gain control at the top-level and ensure consistency with other components.
|
||||
|
||||
.. example::
|
||||
|
||||
.. code-block:: scss
|
||||
:caption: :file:`secondary_variables.scss`
|
||||
|
||||
$o-component-color: $o-main-text-color;
|
||||
$o-dashboard-color: $o-info;
|
||||
// [...]
|
||||
|
||||
.. code-block:: text
|
||||
:caption: :file:`component.scss`
|
||||
|
||||
.o_component {
|
||||
color: var(--MyComponent-color, #{$o-component-color});
|
||||
}
|
||||
|
||||
.. code-block:: text
|
||||
:caption: :file:`dashboard.scss`
|
||||
|
||||
.o_dashboard {
|
||||
--MyComponent-color: #{$o-dashboard-color};
|
||||
}
|
||||
|
||||
.. _contributing/coding_guidelines/scss/root:
|
||||
|
||||
The `:root` pseudo-class
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Defining CSS variables on the `:root` pseudo-class is a technique we normally **don't use** in
|
||||
Odoo's UI. The practice is commonly used to access and modify CSS variables globally. We perform
|
||||
this using SCSS instead.
|
||||
|
||||
Exceptions to this rule should be fairly apparent, such as templates shared across bundles that
|
||||
require a certain level of contextual awareness in order to be rendered properly.
|
||||
|
||||
Reference in New Issue
Block a user