Styling components

Styling components

This is an experimental solution

The pattern behind styling components dynamically from within the CMS is still being researched. The proposed solution might change based on user feedback.

Vue Storefront integration for Bloomreach Content not only allows you to add components to your pages. It also offers a pattern for styling these components dynamically from within the CMS.

It all starts with the Styles field group defined in Bloomreach Content. It allows you to modify your components' CSS, including:

  • margins,
  • paddings,
  • height,
  • width,
  • flex container properties,
  • grid container properties.

styles field group

Each of these property groups is represented by a separate field group in Bloomreach Content (e.g Margins, Paddings or Grid container properties). The Styles field group is simply bringing them all together. Finally, all document types implement the Styles field group. As a result, you can add stylesheets to our components from within the Experience Manager.

styles field group 2

Flexible screen resolutions

You can create different stylesheets for different screen resolutions. All you have to do is specify min and max properties under Screen resolution. For screens bigger than 600 pixels and smaller than 1200 pixels:

screen resolutions

If you omit the min and max properties, the stylesheet will be applied to all screen resolutions unless overriden by other stylesheets which do have min and max set.

Multiple CSS properties

The styles property which lands on the frontend is an array of stylesheet objects. Once the RenderComponent wrapper gets the CMS component data, it locates the styles array and transforms it into a set of <style /> tags added to the <head /> of the current document. Each <style /> tag uses media queries and is tied to a specific frontend component through a unique CSS class.

<style>
@media (min-width: 600px) and (max-width: 1200px) {
  .cms-component-19515447-5126-41ec-ab74-57a11f5d0c4c {
    /* component styles go here */
  }
}
</style>

The logic inside RenderComponent traverses objects within the styles array and looks for properties with primivite values. Once found, they are transformed into CSS declarations. For example, the following object found in the styles array:

{
  resolutions: {
    min: 600,
    max: 1200
  },
  margins: {
    margin_top: '30px',
    margin_bottom: '30px',
    margin_left: 'auto',
    margin_right: 'auto',
  },
  dimensions: {
    width: '300px'
  }
}

would be transformed into the following <style /> tag:

<style>
  @media (min-width: 600px) and (max-width: 1200px) {
    .cms-component-19515447-5126-41ec-ab74-57a11f5d0c4c {
      margin-top: '30px';
      margin-bottom: '30px';
      margin-left: 'auto';
      margin-right: 'auto';
      width: '300px';
    }
  }
</style>

Proper casing is required!

Names of objects containing the primitives do not matter. What matters is the casing of multi-word CSS property names (e.g. margin-top). By convention, they must use snake_case so that the RenderComponent wrapper can transform them properly. Bear that in mind while augmenting the styles field group with your custom CSS properties.

Hero slider example

Dynamic styles are especially useful for components which are nested inside other components. A perfect example might be a Hero slider built from the Hero and the Scrollable.

By default, Storefront UI Scrollable component inserts a vertical gap between all of its elements. What might be desirable for a product card slider, does not look good in case of a Hero slider which should always span the entire width of the screen.

scrollable gap

Fortunately, we can change that using the Gaps property. Set it to 0 and the ugly vertical gap on the left disappears:

scrollable gap disappeared

Caveats

Being an experimental solution, the pattern behind styling components dynamically has certain limitations.

Classes do not affect nested components

Classes generated as a result of the styles transformation are only applied to the root elements of page components. They cannot affect deeply nested elements such as buttons or images. Fortunately, the default implementation should give you enough flexibility in the vast majority of cases.

Unnecessary properties in certain components

A single Styles field group shared between all components might not be the best solution. It contains a lot of properties. Some of them are universal and applicable to all components (e.g. margin or padding) whereas other are rather component-specific (e.g. grid-template-areas). It would be advisable to create a dedicated field group for every component, containing the relevant properties only.

As soon as the solution is not experimental anymore (i.e. receives proper feedback on the ease of use and the choice of CSS properties for every component), such separate field groups for all components will be delivered as part of the integration. Until then, we strongly encourage you to reuse the existing field groups for CSS properties (e.g. Margins, Paddings, Gaps) and create your custom styling field groups for components.