Estilos en Polymer 2. Parte 8

Introducción

En esta ocasión vamos a tratar todo lo que tiene que ver con los estilos en los componentes.

Para tener una visión clara de lo que vamos a probar en este módulo, a continuación añado un pequeño índice:

  • Estilos en los elementos
  • Estilos en los slots
  • Estilos compartidos
  • Custom styles

Estilos en los componentes

Los estilos en un componente esta encapsulados dentro del mismo, evitando de esta forma la sobreescritura y los conflictos con estilos fuera del componente, ya que están aislados.

Ademas de que los estilos no pueden salir fuera del componente, si existe algún estilo fuera del componente y dentro del componente que coincidan, el que esta dentro del componente sustituye a los estilos de fuera del componente.

Tenemos que tener en cuenta que algunos estilos de css pueden traspasar el componente (color, font, etc..).

Dentro del componentes existe un elemento llamado :host, y hace referencia al propio componente.

Con la definición :host {} en nuestro css dentro del componente podemos dar estilos a todo el componente.

Estilos con los slots

Antes de empezar, ¿que es un slot?. Para entenderlo vamos a definir unos términos para que podamos comprender que es un slot:

  • Shadow DOM: El Shadow DOM es un DOM dentro del DOM principal. Se puede llegar a confundir con un iframe, pero son totalmente diferentes ya que un iframe es un DOM totalmente diferente y el Shadow DOM forma parte del DOM.
  • Light DOM: El Light DOM es un árbol DOM simple dentro de un elemento HTML.

Pues un slot nos permite usar el light DOM, usar el contenido dentro de ese elemento HTML.

Para entenderlo mejor voy añadir un poco de código:

index.html

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">

  <title>slot-element demo</title>

  <script src="../bower_components/webcomponentsjs/webcomponents-loader.js"></script>

  <link rel="import" href="../bower_components/iron-demo-helpers/demo-pages-shared-styles.html">
  <link rel="import" href="../bower_components/iron-demo-helpers/demo-snippet.html">
  <link rel="import" href="../slot-element.html">

  <custom-style>
    <style is="custom-style" include="demo-pages-shared-styles">
    </style>
  </custom-style>
</head>

<body>
  <slot-element prop1="Valor de la propiedad">
    Light DOM
  </slot-element>
</body>

</html>

slot-element.html

<link rel="import" href="../polymer/polymer-element.html">

<dom-module id="slot-element">
  <template>
    <style>
      :host {
        display: block;
      }
    </style>
    <!-- Gracias a slot podemos ver el contenido dentro del componente -->
    <slot></slot>
    <h2>Hola mundo, esta es mi propiedad:::.... [[prop1]]!</h2>
  </template>

  <script>
    /**
     * `slot-element`
     * 
     *
     * @customElement
     * @polymer
     * @demo demo/index.html
     */
    class SlotElement extends Polymer.Element {
      static get is() { return 'slot-element'; }
      static get properties() {
        return {
          prop1: {
            type: String,
            value: 'slot-element'
          }
        };
      }
    }

    window.customElements.define(SlotElement.is, SlotElement);
  </script>
</dom-module>

El uso del slot nos permite añadir contenido dentro del componente. El slot ademas tiene una propiedad llamada name, que nos permite definir múltiples slots.

Esto es útil ya que dentro del componente podemos definir una estructura con una definición de slots y únicamente desde fuera asignar contenido a esos slots.

Un ejemplo para entenderlo:

index.html

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">

  <title>slot-element demo</title>

  <script src="../bower_components/webcomponentsjs/webcomponents-loader.js"></script>

  <link rel="import" href="../bower_components/iron-demo-helpers/demo-pages-shared-styles.html">
  <link rel="import" href="../bower_components/iron-demo-helpers/demo-snippet.html">
  <link rel="import" href="../slot-element.html">

  <custom-style>
    <style is="custom-style" include="demo-pages-shared-styles">
    </style>
  </custom-style>
</head>

<body>
  <slot-element prop1="Valor de la propiedad">
    Light DOM
    <span slot="nombre">Jose</span>
    <span slot="edad">50</span>
  </slot-element>
</body>

</html>

slot-element.html

<link rel="import" href="../polymer/polymer-element.html">

<dom-module id="slot-element">
  <template>
    <style>
      :host {
        display: block;
      }

      .nombre {
        color: #ff0000;
      }

      .edad {
        color: #00ff00;
      }
    </style>
    <!-- Gracias a slot podemos ver el contenido dentro del componente -->
    <slot></slot>
    <hr>
    <h2>Hola mundo, esta es mi propiedad:::.... [[prop1]]!</h2>
    <hr>
    <h1>Nombre.....
      <slot name="nombre" class="nombre"></slot>
    </h1>
    <hr>
    <h3>Edad.......
      <slot name="edad" class="edad"></slot>
    </h3>
    <hr>
  </template>

  <script>
    /**
     * `slot-element`
     * 
     *
     * @customElement
     * @polymer
     * @demo demo/index.html
     */
    class SlotElement extends Polymer.Element {
      static get is() { return 'slot-element'; }
      static get properties() {
        return {
          prop1: {
            type: String,
            value: 'slot-element'
          }
        };
      }
    }

    window.customElements.define(SlotElement.is, SlotElement);
  </script>
</dom-module>

Para terminar con los slots y como estamos en el tema de estilos, vamos a definir estilos para los slots.

Dentro de CSS existe un pseudo elemento que nos sirve para dar estilos a los slots directamente, y es ::slotted.

La sintaxis para este pseudo elemento con algunos ejemplos:

  • ::slotted(h1)
  • ::slotted(.nombre_clase)
  • ::slotted([slot=nombre])

Estilos compartidos

Con los estilos compartidos podemos definir una declaración de estilos global y que los podamos usar en diferentes componentes y/o aplicaciones.

Para crearlos solo necesitamos crear un dom-module con un id para poder usarlo, y dentro un template con un style.

estilo_general.html

<dom-module id="estilos">
    <template>
        <style>
            h1 {
                font-size: 30px;
                color: #ff0000;
                font-weight: bold;
            }
        </style>
    </template>
</dom-module>

slot-element.html

<link rel="import" href="../polymer/polymer-element.html">
<link rel="import" href="estilo_general.html">
<dom-module id="slot-element">
  <template>
    <style include="estilo-general">
      :host {
        display: block;
      }

      .nombre {
        color: #ff0000;
      }

      .edad {
        color: #00ff00;
      }
    </style>
    <!-- Gracias a slot podemos ver el contenido dentro del componente -->
    <slot></slot>
    <hr>
    <h2>Hola mundo, esta es mi propiedad:::.... [[prop1]]!</h2>
    <hr>
    <h1>Nombre.....
      <slot name="nombre" class="nombre"></slot>
    </h1>
    <hr>
    <h3>Edad.......
      <slot name="edad" class="edad"></slot>
    </h3>
    <hr>
  </template>

  <script>
    /**
     * `slot-element`
     * 
     *
     * @customElement
     * @polymer
     * @demo demo/index.html
     */
    class SlotElement extends Polymer.Element {
      static get is() { return 'slot-element'; }
      static get properties() {
        return {
          prop1: {
            type: String,
            value: 'slot-element'
          }
        };
      }
    }

    window.customElements.define(SlotElement.is, SlotElement);
  </script>
</dom-module>

Custom Styles

A día de hoy existen infinidad de componentes creados por empresas y/o personas que nos permiten personalizar los estilos para esos componentes.

La idea es que nosotros también podamos crear componentes y que tanto nosotros como otras personas puedan personalizar nuestro componente.

Para entender mejor como funciona vamos añadir un componente de la web www.webcomponents.org y vamos a ver como podemos personalizar los estilos.

En ese ejemplo voy a usar el componente paper-spinner, y para añadirlo usaremos el siguiente comando:

  • bower install –save PolymerElements/paper-spinner

Ahora para poder usarlo deberemos importar el componente a nuestro código con la siguiente linea:

  • <link rel=»import» href=»./bower_components/paper-spinner/paper-spinner.html»>

Con esto ya solo nos queda añadir el componente dentro de nuestro código:

  • <paper-spinner active>…</paper-spinner>

Hasta este momento solamente hemos instalado, importado y añadido el componente.

Ahora vamos a probar a personalizar los estilo.

Dentro de la documentación del componente tenemos una parte donde nos indican las propiedades que podemos usar para cambiar el estilo a nuestro componente.

Teniendo claro que necesitamos o queremos cambiar en los estilos vamos hacer uso de esa variable de css para poder personalizar el componente.

  • paper-spinner { –paper-spinner-stroke-width: 20px; }

Con esta modificación hemos cambiado el grosor del spinner.

Con el uso de los custom styles hemos podido hacer uso de las variables en css. Ahora vamos a ver que es un mixin en ccs.

Un mixin en css es una forma de añadir una o múltiples propiedades css dentro de una variable de css.

.caja {
  border-radius:4px;
  border:solid 1px #aaaaaa;
  background:#dddddd;
  color:#000000;
  box-shadow:0px 0px 15px rgba(0,0,0,0.25);
}

.rojo {
  background:#ff0000;
  color:#ffffff;
}
.verde {
  background:#00ff00;
  color:#ffffff;
}
.caja_roja{
  .caja;
  .rojo;
}

Para terminar vamos a implementar los estilos personalizados, y para poder usar los mixins necesitamos importar el shim de ShadyCSS.

Para entender mejor su uso, vamos añadir un poco de código y comprobar que es muy simple:

<link rel="import" href="./bower_components/polymer/polymer-element.html">
<link rel="import" href="estilo_general.html">
<link rel="import" href="./bower_components/paper-spinner/paper-spinner.html">
<link rel="import" href="./bower_components/shadycss/apply-shim.html">
<dom-module id="slot-element">
  <template>
    <style include="estilo-general">
      :host {
        display: block;
        --test-mixin: {
          border: 1px solid #ff0000;
          width: 100px;
          height: 100px;
          color: #00ffff;
        }
      }

      .nombre {
        color: #ff0000;
      }

      .edad {
        @apply --test-mixin;
      }

      paper-spinner {
        --paper-spinner-stroke-width: 10px;
      }
    </style>
    <hr>
    <paper-spinner active>...</paper-spinner>
    <hr>
    <!-- Gracias a slot podemos ver el contenido dentro del componente -->
    <slot></slot>
    <hr>
    <h2>Hola mundo, esta es mi propiedad:::.... [[prop1]]!</h2>
    <hr>
    <h1>Nombre.....
      <slot name="nombre" class="nombre"></slot>
    </h1>
    <hr>
    <h3>Edad.......
      <slot name="edad" class="edad"></slot>
    </h3>
    <hr>
  </template>

  <script>
    /**
     * `slot-element`
     * 
     *
     * @customElement
     * @polymer
     * @demo demo/index.html
     */
    class SlotElement extends Polymer.Element {
      static get is() { return 'slot-element'; }
      static get properties() {
        return {
          prop1: {
            type: String,
            value: 'slot-element'
          }
        };
      }
    }

    window.customElements.define(SlotElement.is, SlotElement);
  </script>
</dom-module>