Styling elements in Picture elements card: a small tutorial

Intro:
This thread is dedicated to people who started using the Picture elements card.
It contains basic hints for styling elements.
This is not about using the "card-mod" - everything regarding the "card-mod" will be described in the corresponding thread.


Positioning elements
Important notes about positioning
How to adapt PE card for different viewports

Rotating elements

Resizing elements:
scaling elements
changing font-size: state-badge, state-label, service-button
state-icon & icon
state-badge

Specific styles for elements:
state-label
state-icon & icon
service-button
state-badge
image

Define styles dynamically by card-mod
Changing Z-order for elements

Styling custom cards inside the Picture elements card

How to set a main image dynamically
About actions

When I should and when I should not use card-mod to style an element

Examples:
Charging a car

50 Likes

Understanding positioning:
Positioning of some element is defined by the "top" & "left" properties.
Position is defined for a “center” of the element which is kind of geometrical center of the element by default.
But the element’s “center” may be re-defined using a "transform: translate()" filter, for example:

  • "translate(-50%,-50%)" - “center” is a geometrical center;
  • "translate(0%,0%)" - “center” is a left top corner;
  • "translate(-100%,-100%)" - “center” is a right bottom corner.

By default the filter is "translate(-50%,-50%)".
Below some examples for different "translate()" filters are provided:
изображение

  - type: picture-elements
    title: '-'
    card_mod:
      style: |
        ha-card { height: 300px !important; }
    elements:
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 0%
          left: 0%
          transform: translate(0%, 0%)
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 0%
          left: 20%
          transform: translate(0, 50%)
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 0%
          left: 40%
          transform: translate(0, -50%)
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 0%
          left: 60%
          transform: translate(0, -100%)
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 0%
          left: 80%
          transform: translate(0, 100%)
    image: /local/images/blue.jpg

Below all elements have "top: 0%" position which corresponds to the top border of the elements’ area, and the "left: 0%" position corresponds to the left border of the elements’ area.
All elements are centered on the top border of the elements’ area - this is because default center’s position is "translate(-50%,-50%)":
изображение

  - type: picture-elements
    title: '-'
    card_mod:
      style: |
        ha-card { height: 150px !important; }
    elements:
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 0%
          left: 0%
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 0%
          left: 20%
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 0%
          left: 40%
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 0%
          left: 60%
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 0%
          left: 80%
    image: /local/images/blue.jpg

When the "translate(0,0)" is useful?
The "translate(0,0)" filter could be useful for transparent png images which are supposed to overlap the main background image, this is basically can be used for floorplans:

  • a main plot image is set as a background image with the style "top: 0, left: 0, translate(0,0)";
  • other images are used as transparent masks for displaying dark rooms, plot details like furniture, home appliances & equipment; these images should have the same dimensions as the main background image; for these images the style "top: 0, left: 0, translate(0,0)" should be used too.
5 Likes

Rotating an element:

First let’s consider a rotation around Z-axis.

In the example below a rotation applied to these elements:

  • state-badge;
  • state-icon;
  • icon;
  • state-label;
  • service-button;
  • image.

There are 2 methods to define an angle:

  • by “turns” (1 turn = 360degrees, used in the example below);
  • by “degrees”.

By default because of unknown reason a rotation causes changing the "translate()" style - so it causes changing a position too.
To avoid this, the "translate(-50%,-50%)" filter must be used along with the "rotate()" filter.
In the example below the first rotation (+90 degrees, 2nd column) is defined w/o using the "translate(-50%,-50%)" filter, other rotations are defined with it. It is clearly seen that the 1st rotated element changed it’s position.
WARNING: order of commands in “transform” function matters! Use "translate" before other commands.

type: picture-elements
title: ''
elements:
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 10%
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 30%
      transform: rotate(0.25turn)
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 60%
      transform: translate(-50%,-50%) rotate(-0.25turn)
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 85%
      transform: translate(-50%,-50%) rotate(0.5turn)
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 28%
      left: 10%
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 28%
      left: 30%
      transform: rotate(0.25turn)
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 28%
      left: 60%
      transform: translate(-50%,-50%) rotate(-0.25turn)
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 28%
      left: 85%
      transform: translate(-50%,-50%) rotate(0.5turn)
  - type: icon
    icon: mdi:car
    style:
      top: 38%
      left: 10%
  - type: icon
    icon: mdi:car
    style:
      top: 38%
      left: 30%
      transform: rotate(0.25turn)
  - type: icon
    icon: mdi:car
    style:
      top: 38%
      left: 60%
      transform: translate(-50%,-50%) rotate(-0.25turn)
  - type: icon
    icon: mdi:car
    style:
      top: 38%
      left: 85%
      transform: translate(-50%,-50%) rotate(0.5turn)
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 52%
      left: 10%
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 52%
      left: 30%
      transform: rotate(0.25turn)
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 52%
      left: 60%
      transform: translate(-50%,-50%) rotate(-0.25turn)
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 52%
      left: 85%
      transform: translate(-50%,-50%) rotate(0.5turn)
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 70%
      left: 10%
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 70%
      left: 30%
      transform: rotate(0.25turn)
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 70%
      left: 60%
      transform: translate(-50%,-50%) rotate(-0.25turn)
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 70%
      left: 85%
      transform: translate(-50%,-50%) rotate(0.5turn)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 90%
      left: 10%
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 90%
      left: 30%
      transform: rotate(0.25turn)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 90%
      left: 60%
      transform: translate(-50%,-50%) rotate(-0.25turn)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 90%
      left: 85%
      transform: translate(-50%,-50%) rotate(0.5turn)
image: /local/images/white.jpg

Below there is an example of rotation around X- & Y-axis (angle is defined by degrees) - for state-badge only.
Similarly to the previous example, the "translate(-50%,-50%)" filter is applied only to the 2nd & 3rd rotations.
image

type: picture-elements
title: ''
card_mod:
  style: |
    ha-card { height: 180px !important; }
elements:
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 10%
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 30%
      transform: rotateX(180deg)
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 60%
      transform: translate(-50%,-50%) rotateX(180deg)
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 85%
      transform: translate(-50%,-50%) rotateY(180deg)
image: /local/images/white.jpg
6 Likes

Scaling an element:

Scaling is achieved by using a "scale()" filter.
Better to use with the "translate(-50%,-50%)" filter as it was explained above.
In the example below the first scaling(0.5, 0.5) is defined w/o using the "translate(-50%,-50%)" filter, other scalings are defined with it. It is clearly seen that the 1st scaled element changed it’s position.

Note: other methods to change an element’s size:

  • state-badge - changing a badge’s size (link);
  • state-badge, state-label, service-button - changing a font-size (link);
  • state-icon, icon - changing an icon’s size (link);

type: picture-elements
title: ''
elements:
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 12%
      left: 10%
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 12%
      left: 30%
      transform: scale(0.5,0.5)
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 12%
      left: 60%
      transform: translate(-50%,-50%) scale(1.5,1)
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 12%
      left: 85%
      transform: translate(-50%,-50%) scale(1,1.5)
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 31%
      left: 10%
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 31%
      left: 30%
      transform: scale(0.5,0.5)
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 31%
      left: 60%
      transform: translate(-50%,-50%) scale(1.5,1)
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 31%
      left: 85%
      transform: translate(-50%,-50%) scale(1,1.5)
  - type: icon
    icon: mdi:car
    style:
      top: 43%
      left: 10%
  - type: icon
    icon: mdi:car
    style:
      top: 43%
      left: 30%
      transform: scale(0.5,0.5)
  - type: icon
    icon: mdi:car
    style:
      top: 43%
      left: 60%
      transform: translate(-50%,-50%) scale(1.5,1)
  - type: icon
    icon: mdi:car
    style:
      top: 43%
      left: 85%
      transform: translate(-50%,-50%) scale(1,1.5)
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 58%
      left: 10%
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 60%
      left: 30%
      transform: scale(0.5,0.5)
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 60%
      left: 60%
      transform: translate(-50%,-50%) scale(1.5,1)
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 60%
      left: 85%
      transform: translate(-50%,-50%) scale(1,1.5)
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 75%
      left: 10%
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 75%
      left: 30%
      transform: scale(0.5,0.5)
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 75%
      left: 60%
      transform: translate(-50%,-50%) scale(1.5,1)
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 75%
      left: 85%
      transform: translate(-50%,-50%) scale(1,1.5)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 90%
      left: 10%
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 90%
      left: 30%
      transform: scale(0.5,0.5)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 90%
      left: 60%
      transform: translate(-50%,-50%) scale(1.5,1)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 90%
      left: 85%
      transform: translate(-50%,-50%) scale(1,1.5)
image: /local/images/white.jpg

Changing an origin point:
There is some issue with scaling - and it is better to show it with images.
By default the scaled image is scaled “from its center” - that means that original and scaled images are centrally aligned.
To change it, a "transform-origin" function is used.
On the example below:

  • the 1st row is with original images;
  • the 2nd row is with scaled images (except the left image) - and the scaled images are centrally aligned with respect to the left image and to images on the 1st row;
  • the 3rd row is with scaled images (except the left image) - and the scaled images are centrally aligned with respect to the left image and left-aligned to images on the 1st row;
  • the 4th row is with scaled images (except the left image) - and the scaled images are top-aligned with respect to the left image and centrally aligned to images on the 1st row.

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 550px !important;
    }
elements:
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 10%
      left: 15%
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 10%
      left: 45%
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 10%
      left: 80%
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 30%
      left: 15%
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 30%
      left: 45%
      transform: translate(-50%,-50%) scale(1.5,1.5)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 30%
      left: 80%
      transform: translate(-50%,-50%) scale(1.5,1.5)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 50%
      left: 15%
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 50%
      left: 45%
      transform-origin: left
      transform: translate(-50%,-50%) scale(1.5,1.5)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 50%
      left: 80%
      transform-origin: left
      transform: translate(-50%,-50%) scale(1.5,1.5)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 70%
      left: 15%
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 70%
      left: 45%
      transform-origin: top
      transform: translate(-50%,-50%) scale(1.5,1.5)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 70%
      left: 80%
      transform-origin: top
      transform: translate(-50%,-50%) scale(1.5,1.5)
image: /local/images/white.jpg

Another example - 4 images, 3 of them scaled with using "transform-origin: left top":
image
Note: a "border: 1px solid black" style is used for make image’s border look more clear.

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 250px !important;
    }
elements:
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 10%
      left: 15%
      transform-origin: left top
      transform: translate(-50%,-50%) scale(3.5,3.5)
      border: 1px solid black
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 10%
      left: 15%
      transform-origin: left top
      transform: translate(-50%,-50%) scale(2.5,2.5)
      border: 1px solid black
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 10%
      left: 15%
      transform-origin: left top
      transform: translate(-50%,-50%) scale(1.5,1.5)
      border: 1px solid black
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 10%
      left: 15%
      border: 1px solid black
image: /local/images/white.jpg

Large images’ auto-scaling:
There is one more issue regarding scaling - for images whose width is larger than a card’s width (actually, larger than a space available for an image) with "translate(0,0)".
These images are automatically scaled to fill all available area to the right (keeping aspect ratio):
image
The example below contains 3 same images:

  • the 1st image is placed to the left top corner with "translate(0,0)" filter and fills the whole card to the right (keeping aspect ratio);
  • the 2nd & 3rd images are shifted to the right and fill the remained area to the right (keeping aspect ratio).
type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 450px !important;
    }
elements:
  - type: image
    image: /local/images/pink.jpg
    style:
      top: 0%
      left: 0%
      transform: translate(0,0)
      border: 1px solid black
  - type: image
    image: /local/images/pink.jpg
    style:
      top: 0%
      left: 30%
      transform: translate(0,0)
      border: 1px solid black
  - type: image
    image: /local/images/pink.jpg
    style:
      top: 10%
      left: 60%
      transform: translate(0,0)
      border: 1px solid black
image: /local/images/white.jpg

Oddly this happens with "translate(0,0)" and does not happen with "translate(-50%,-50%)" (haven’t checked with other combinations).
For example, I cannot explain these cases:
a) Here an image (904x679) with "translate(-50%,-50%)" occupies half of the available area (although it’s width is more than twice bigger than the card’s width):

type: picture-elements
elements:
  - type: image
    image: /local/images/test/pink_mask.png
    style:
      top: 0%
      left: 0%
      transform: translate(-50%,-50%)
image: /local/images/test/blue.jpg

image

b) Here the same image is placed in the card’s center and also does not occupy the whole available area:

type: picture-elements
elements:
  - type: image
    image: /local/images/test/pink_mask.png
    style:
      top: 50%
      left: 50%
      transform: translate(-50%,-50%) scale(1,1)
image: /local/images/test/blue.jpg

image

5 Likes

Changing font-size:

This operation may be applied to:

  • state-badge;
  • state-label;
  • service-button.

For “state-badge” & “state-label” the "font-size" style must be used.
For “service-button” - the "--mdc-typography-button-font-size" variable must be used.
Note that changing the font-size for a badge causes a scaling the badge too.
image

type: picture-elements
title: ''
card_mod:
  style: |
    ha-card { height: 320px !important; }
elements:
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 12%
      left: 10%
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 12%
      left: 40%
      font-size: 10px
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 12%
      left: 80%
      font-size: 20px
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 30%
      left: 10%
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 30%
      left: 40%
      font-size: 10px
  - type: state-label
    entity: sensor.cleargrass_1_co2
    style:
      top: 30%
      left: 80%
      font-size: 20px
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 40%
      left: 10%
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 40%
      left: 40%
      '--mdc-typography-button-font-size': 10px
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 40%
      left: 80%
      '--mdc-typography-button-font-size': 20px
image: /local/images/white.jpg
1 Like

Resizing icons:

Resizing may be done by using a "--mdc-icon-size" variable.
This method may be applied to:

  • state-icon;
  • icon.

image

type: picture-elements
title: ''
card_mod:
  style: |
    ha-card { height: 200px !important; }
elements:
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 10%
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 45%
      '--mdc-icon-size': 10px
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 8%
      left: 80%
      '--mdc-icon-size': 40px
  - type: icon
    icon: mdi:car
    style:
      top: 21%
      left: 10%
  - type: icon
    icon: mdi:car
    style:
      top: 21%
      left: 45%
      '--mdc-icon-size': 10px
  - type: icon
    icon: mdi:car
    style:
      top: 21%
      left: 80%
      '--mdc-icon-size': 40px
image: /local/images/white.jpg
2 Likes

Resizing a badge:

Resizing may be done by using a "--ha-label-badge-size" variable.
Note that this does not affect font-size.
image

type: picture-elements
title: ''
card_mod:
  style: |
    ha-card { height: 150px !important; }
elements:
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 12%
      left: 10%
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 12%
      left: 45%
      '--ha-label-badge-size': 35px
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 12%
      left: 80%
      '--ha-label-badge-size': 80px
image: /local/images/white.jpg
1 Like

Other styles for “state-label”:

  • displaying prefix & suffix;
  • displaying entity’s attribute;
  • colored text.

image

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 80px !important;
    }
elements:
  - type: state-label
    entity: sun.sun
    style:
      top: 8%
      left: 15%
  - type: state-label
    entity: sun.sun
    prefix: '{ '
    suffix: ' }'
    style:
      top: 18%
      left: 15%
  - type: state-label
    entity: sun.sun
    style:
      top: 8%
      left: 80%
      color: orange
  - type: state-label
    entity: sun.sun
    attribute: elevation
    style:
      top: 18%
      left: 80%
image: /local/images/blue.jpg
1 Like

Other styles for “state-icon” & “icon”:

  • colored icon.

The “state-icon” element MUST be associated with some entity, the “icon” element - MAY be associated.

state-icon:
By default for entities like "sensor" (same for "device_tracker", "person", "zone", …) an icon’s color for the “state-icon” does not depend on the entity’s state.
The "--paper-item-icon-color" variable is used to change a color:
image

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 70px !important;
    }
elements:
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 6%
      left: 10%
  - type: state-icon
    entity: sensor.cleargrass_1_co2
    style:
      top: 6%
      left: 40%
      '--paper-item-icon-color': red
image: /local/images/white.jpg

By default for entities like "binary_sensor", "sun.sun", "switch", "input_boolean" an icon’s color for the “state-icon” DOES depend on the entity’s state - if the property "state_color: true" is set for the element. If it is set to "false", then the color DOES NOT depend on the state.
The "--paper-item-icon-active-color" & "--paper-item-icon-color" variables are used to change a color.
The "--paper-item-icon-active-color" variable affects on color if the property "state_color: true" is set for the element.
The 1st row on the picture below is for "state_color: true", the 2nd row - for "state_color: false".
image

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 170px !important;
    }
elements:
  - type: state-icon
    entity: binary_sensor.service_on_value
    state_color: true
    style:
      top: 6%
      left: 10%
  - type: state-icon
    entity: binary_sensor.service_on_value
    state_color: true
    style:
      top: 6%
      left: 35%
      '--paper-item-icon-active-color': red
      '--paper-item-icon-color': cyan
  - type: state-icon
    entity: binary_sensor.service_off_value
    state_color: true
    style:
      top: 6%
      left: 65%
  - type: state-icon
    entity: binary_sensor.service_off_value
    state_color: true
    style:
      top: 6%
      left: 90%
      '--paper-item-icon-active-color': red
      '--paper-item-icon-color': cyan
  - type: state-icon
    entity: binary_sensor.service_on_value
    state_color: false
    style:
      top: 20%
      left: 10%
  - type: state-icon
    entity: binary_sensor.service_on_value
    state_color: false
    style:
      top: 20%
      left: 35%
      '--paper-item-icon-active-color': red
      '--paper-item-icon-color': cyan
  - type: state-icon
    entity: binary_sensor.service_off_value
    state_color: false
    style:
      top: 20%
      left: 65%
  - type: state-icon
    entity: binary_sensor.service_off_value
    state_color: false
    style:
      top: 20%
      left: 90%
      '--paper-item-icon-active-color': red
      '--paper-item-icon-color': cyan
image: /local/images/white.jpg

icon:
The "color" CSS property is used to change an icon’s color:
image

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 70px !important;
    }
elements:
  - type: icon
    icon: mdi:car
    style:
      top: 6%
      left: 10%
  - type: icon
    icon: mdi:car
    style:
      top: 6%
      left: 40%
      color: red
image: /local/images/white.jpg
1 Like

Other styles for “service-button”:

Some styles may be changed:
image

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 70px !important;
    }
elements:
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 6%
      left: 15%
  - type: service-button
    title: Command
    service: homeassistant.update_entity
    service_data:
      entity_id: sun.sun
    style:
      top: 6%
      left: 70%
      --mdc-theme-primary: red
      background: rgb(220,220,220)
      border: 1px solid black
      border-radius: 5px
image: /local/images/white.jpg
2 Likes

Other styles for “state-badge”:

Example 1 - different styles:
image

type: picture-elements
card_mod:
  style: |
    ha-card { height: 140px !important; }
elements:
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 10%
      left: 10%
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      color: orange
      '--label-badge-text-color': magenta
      '--label-badge-red': green
      '--label-badge-background-color': yellow
      '--ha-label-badge-label-color': blue
      '--ha-label-badge-size': 75px
      '--ha-label-badge-title-width': 150px
      '--ha-label-badge-title-font-size': 20px
      top: 10%
      left: 40%
  - type: state-badge
    entity: binary_sensor.updater
    style:
      top: 10%
      left: 70%
  - type: state-badge
    entity: binary_sensor.updater
    style:
      top: 10%
      left: 90%
      color: orange
      '--label-badge-text-color': magenta
      '--label-badge-blue': green
      '--label-badge-background-color': yellow
      '--ha-label-badge-size': 35px
      '--mdc-icon-size': 29px
      '--ha-label-badge-title-font-size': 10px
image: /local/images/white.jpg

Example 2 - hidden label:
image

type: picture-elements
card_mod:
  style: |
    ha-card { height: 120px !important; }
elements:
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 10%
      left: 10%
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      color: transparent
      top: 10%
      left: 40%
image: /local/images/white.jpg

Example 3 - playing with "background-color" & "opacity":
image

type: picture-elements
card_mod:
  style: |
    ha-card { height: 120px !important; }
elements:
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 10%
      left: 10%
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 10%
      left: 30%
      opacity: 0.3
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 10%
      left: 50%
      background-color: rgb(0, 128, 0)
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 10%
      left: 70%
      background-color: rgb(0, 128, 0)
      opacity: 0.3
  - type: state-badge
    entity: sensor.cleargrass_1_co2
    style:
      top: 10%
      left: 90%
      background-color: rgba(0, 128, 0, 0.3)
image: /local/images/white.jpg
1 Like

Other styles for “image”:

image

type: picture-elements
title: ''
card_mod:
  style: |
    ha-card {
      height: 280px !important;
    }
elements:
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 10%
      left: 20%
      transform: translate(-50%,-50%) scale(2,2)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 10%
      left: 70%
      filter: saturate(0.1)
      transform: translate(-50%,-50%) scale(2,2)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 30%
      left: 20%
      filter: invert(100%)
      transform: translate(-50%,-50%) scale(2,2)
  - type: image
    image: /local/images/small_pic.jpg
    style:
      top: 30%
      left: 70%
      border: 1px solid black
      transform: translate(-50%,-50%) scale(2,2)
image: /local/images/white.jpg
1 Like

Conditional styles:

Styles can be set dynamically dependingly on some conditions (like some entity’s state) with the help of "card-mod":


type: vertical-stack
cards:
  - type: entities
    entities:
      - entity: input_boolean.test_boolean
  - type: picture-elements
    card_mod:
      style: |
        ha-card {
          {% if is_state('input_boolean.test_boolean','on') %}
          --my-state-color: magenta;
          --my-transform-style: translate(-50%,-50%) rotate(-0.25turn);
          {% else %}
          --my-state-color: cyan;
          --my-transform-style: translate(-50%,-50%)
          {% endif %}
        }
    elements:
      - type: state-badge
        entity: sensor.cleargrass_1_co2
        style:
          top: 8%
          left: 20%
          '--label-badge-background-color': var(--my-state-color)
          transform: var(--my-transform-style)
      - type: state-icon
        entity: sensor.cleargrass_1_co2
        style:
          top: 28%
          left: 20%
          '--paper-item-icon-color': var(--my-state-color)
          transform: var(--my-transform-style)
      - type: icon
        icon: mdi:car
        style:
          top: 38%
          left: 20%
          color: var(--my-state-color)
          transform: var(--my-transform-style)
      - type: state-label
        entity: sensor.cleargrass_1_co2
        style:
          top: 52%
          left: 20%
          color: var(--my-state-color)
          transform: var(--my-transform-style)
      - type: service-button
        title: Command
        service: homeassistant.update_entity
        service_data:
          entity_id: sun.sun
        style:
          top: 70%
          left: 20%
          '--mdc-theme-primary': var(--my-state-color)
          transform: var(--my-transform-style)
      - type: image
        image: /local/images/small_pic.jpg
        style:
          top: 90%
          left: 20%
          transform: var(--my-transform-style)
    image: /local/images/white.jpg

Important note: this method CANNOT be used to define dynamically other options like “image”, “entity” etc.

Also: there are 2 ways:

  1. Declare a variable on a picture-elements card’s level - then this variable may be used for a few elements.
  2. Declare a variable on some element’s level - to use this variable for this element only.

One more example.

1 Like

Changing Z-order for elements:

By default elements have a Z-index in accordance to the order they are defined in a card.
The example below has one “image” element, some “state-label” elements, some “icon” elements.
Some elements are overlapped by the “image” element by default.
The "z-index" property may be used to change a Z-index:
image

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 150px !important;
    }
elements:
  - type: icon
    icon: mdi:car
    style:
      top: 10%
      left: 10%
  - type: icon
    icon: mdi:car
    style:
      top: 10%
      left: 40%
      z-index: 999
  - type: state-label
    entity: sun.sun
    style:
      top: 35%
      left: 20%
  - type: state-label
    entity: sun.sun
    style:
      top: 40%
      left: 20%
      z-index: 999
  - type: image
    image: /local/images/pink_mask.png
    style:
      top: 0%
      left: 0%
  - type: icon
    icon: mdi:car
    style:
      top: 10%
      left: 20%
  - type: state-label
    entity: sun.sun
    style:
      top: 30%
      left: 20%
image: /local/images/blue.jpg
1 Like

Styling custom cards inside the Picture elements card:

Example 1 - toggle-entity row:
image

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 250px !important;
    }
elements:
  - type: custom:hui-element
    row_type: toggle-entity
    entity: input_boolean.test_boolean
    name: Some toggle (default style)
    style:
      top: 0%
      left: 0%
      transform: translate(0,0)
  - type: custom:hui-element
    row_type: toggle-entity
    entity: input_boolean.test_boolean
    name: Some toggle
    style:
      top: 14%
      left: 0%
      transform: translate(0,0)
      width: 250px
      '--paper-item-icon-color': magenta
      color: cyan
  - type: custom:hui-element
    row_type: toggle-entity
    entity: input_boolean.test_boolean
    name: Some toggle
    style:
      top: 21%
      left: 0%
      transform: translate(0,0)
      width: 250px
      '--paper-item-icon-color': green
      color: orange
  - type: custom:hui-element
    row_type: toggle-entity
    entity: input_boolean.test_boolean
    name: Some toggle
    style:
      top: 28%
      left: 0%
      transform: translate(0,0)
      width: 250px
      '--paper-item-icon-color': red
      color: magenta
      '--switch-unchecked-track-color': lightgreen
      '--switch-checked-track-color': cyan
      '--switch-unchecked-button-color': red
      '--switch-checked-button-color': green
image: /local/images/white.jpg

Example 2 - Glance card:
image

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 450px !important;
    }
elements:
  - type: custom:hui-element
    card_type: glance
    entities:
      - entity: sensor.cleargrass_1_co2
      - entity: sensor.cleargrass_1_co2
    name: Some toggle (default style)
    style:
      top: 10%
      left: 10%
      transform: translate(0,0)
      '--paper-item-icon-color': red
      '--ha-card-background': rgba(0,100,0,0.8)
      '--ha-card-border-radius': 14px
  - type: custom:hui-element
    card_type: glance
    entities:
      - entity: sensor.cleargrass_1_co2
      - entity: sensor.cleargrass_1_co2
    name: Some toggle (default style)
    style:
      top: 60%
      left: 10%
      transform: translate(0,0)
      '--paper-item-icon-color': red
      '--ha-card-background': rgba(0,0,0,0)
      background-image: url("/local/images/blue_low_2.jpg")
      background-size: 100% 100%
image: /local/images/pink.jpg

Example 3 - Entities card:

type: picture-elements
card_mod:
  style: |
    ha-card {
      height: 250px !important;
    }
elements:
  - type: custom:hui-element
    card_type: entities
    entities:
      - entity: input_boolean.test_boolean
        name: Some toogle
      - entity: input_number.test_number
        name: Some silder
    style:
      top: 5%
      left: 5%
      transform: translate(0,0)
      '--paper-item-icon-color': red
      '--ha-card-background': rgba(0,0,255,0.1)
      '--ha-card-border-radius': 14px
      width: 400px
      --primary-text-color: orange
image: /local/images/white.jpg
3 Likes

Issues about positioning & scaling elements

When creating a floorplan, people sometimes facing an issue “my floorplan is malformed on iPad/iPhone/etc”.
In short - you may spend lot of time to position your elements (lightbulbs, furniture, equipment, doors, smoke detectors, …) on a floorplan - i.e. by setting “top / left / scale” properties; and then on another device your results look differently.
On GitHub there are plenty of issues about the same problem. People consider this as a bug - which is wrong.

A similar case - a floorplan look differently when a view is in “panel: true” mode or with a right sidebar. Reason is same - size of a card is different in these cases.

There is a difference between icons/badges/labels and images in part of scaling.
Consider an example below.

Create an image larger than your viewport (for instance, for my 1920x1200 screen I created a 3000x3000 image) with a similar “chess” pattern:
image
So, the image must have clear marks for 33%, 66% in horizontal & vertical directions.

Create a new view in Panel mode and add this card:

type: picture-elements
elements:
  - type: state-icon
    entity: sun.sun
    icon: mdi:white-balance-sunny
    style:
      top: 33.3333%
      left: 33.3333%
      transform: translate(-50%,-50%) scale(2,2)
  - type: icon
    icon: mdi:white-balance-sunny
    style:
      top: 33.3333%
      left: 66.6666%
  - type: state-badge
    entity: sun.sun
    icon: mdi:white-balance-sunny
    style:
      top: 66.6666%
      left: 33.3333%
  - type: state-label
    entity: sun.sun
    icon: mdi:white-balance-sunny
    style:
      top: 66.6666%
      left: 66.6666%
image: /local/images/test/9colors_low.jpg

image

Now resize the browser’s window - all elements are still placed on same places:

A small trick how to set positions ONCE - i.e. w/o endless “set position → save → reload page → check if it is OK → set position → …”:
– open your floorplan’s main image in Photoshop (or any other program with a similar functionality);
– place a mouse on a desired point;
– write down coordinates of this point in pixels (like “1234, 567”);
– calculate a relative coordinates like “left = COORD_X / IMAGE_WIDTH”; let it be “left = 1234 / 3000 = 41.13 %”.

Note that on a smaller viewport elements become BIGGER (respectively to the main image).
This may be solved by scaling elements differently on different viewports ("transform: translate(-50%,-50%) scale(diff_scale_value,diff_scale_value)").
Two ways may be used:
– the whole floorplan card is a decluttering-card - pass a scale value as a variable;
– use card-mod to set scales conditionally dependingly on a current viewport (use “mediaquery”).

Result - all tested elements (icons, badges, labels) are placed / scaled properly on different viewports.


Now let’s check images as elements.
Consider these facts:

  1. A main image fills all card’s area: first it fills the area in horizontal direction (since the card’s width is fixed), then it fills the area in vertical direction (according to the image’s aspect ratio).
  2. Assume that some “image” element is placed with "left: 33.333%, translate(0%,0%)" - i.e. the top left corner has coord_x = 33.333%. So there is 66.6667% space left on the right. If the image’s width is less than this space - then this image is placed in this space with a possible gap between the image & right border (unoccupied space). If the image’s width is bigger - then it occupies the whole space left w/o a gap (no unoccupied space left). This is described here.

Means - image elements have different sizes (respectively to the main image) dependingly on a current viewport.
Add this element to the test card (image size is 100px x 100px - less than the main image):

  - type: image
    image: /local/images/test/1color.jpg
    style:
      top: 33.3333%
      left: 66.6666%
      transform: translate(0%,0%)

and resize the browser’s window:

The only right solution seems to use the same size for the main image and image elements:
– all image elements have "left: 0%, top: 0%, translate(0%,0%)";
– all image elements are PNG files with transparent background.

Check this:

type: picture-elements
elements:
  - type: image
    image: /local/images/test/car.png
    style:
      top: 0%
      left: 0%
      transform: translate(0%,0%)
image: /local/images/test/garage.png


where the garage & car - are different images:

The same approach may be used to create “dark rooms” for a floorplan.

3 Likes

How to set a main image dynamically:

There 3 methods available to achieve this:

  1. Use card-mod to define background color for the card.
  2. Use “image” element with “state_image” option.
  3. Use “config-template-card” to define background color for the card.

Card-mod method:

Consider this card:

type: vertical-stack
cards:
  - type: entities
    entities:
      - input_select.test_tri_state
  - type: picture-elements
    image: /local/images/test/transparent.png
    elements:
      - type: state-label
        entity: input_select.test_tri_state
        style:
          top: 20%
          left: 20%
    card_mod:
      style: |
        ha-card {
          {% if is_state('input_select.test_tri_state','auto') %}
            {% set IMAGE = '/local/images/test/lightgreen_1.jpg' %}
          {% elif is_state('input_select.test_tri_state','on') %}
            {% set IMAGE = '/local/images/test/lightgreen_2.jpg' %}
          {% else %}
            {% set IMAGE = '/local/images/test/lightgreen_3.jpg' %}
          {% endif %}
          background-size: 100% 100%;
          background-image: url({{IMAGE}});
        }

The “input_select.test_tri_state” helper has three possible values - “auto, on, off”.
The “transparent.png” is a LARGE (I myself use a 4K image) transparent png-file - it must be larger than any of used images (lightgreen_1…3.jpg). If you need a particular size (not square) - define a CSS “height” property by card-mod.
Note that all 3 images (lightgreen_1…3.jpg) may have different dimensions - anyway they will be stretched; surely all images should be of the same size since they describe “one card in different conditions”.


"image" element method:

Currently only an internal “`image’” element can have a dynamically defined image (“state-image”). When using this way, a user need to enlarge the internal “image” element to cover whole card - which is not an easy task.
The best way is to use images of the SAME dimensions (1920x1080 on the example below):
– transparent (or ANY, anyway will be overlapped but I recommend using transparent to avoid visible transitions) image as the “main image” of the card;
– different corresponding images for different conditions.
Here there is a limitation: “each condition = a state of some entity”, i.e. it cannot be some complex condition. If you need a complex condition - either use a template sensor for this condition or use other methods described in this post.

type: vertical-stack
cards:
  - type: entities
    entities:
      - input_select.test_tri_state
  - type: picture-elements
    image: /local/images/test/transparent_1920_1080.png
    elements:
      - type: image
        entity: input_select.test_tri_state
        style:
          top: 0%
          left: 0%
          transform: translate(0,0)
        state_image:
          auto: /local/images/test/lightgreen_1.jpg
          'on': /local/images/test/lightgreen_2.jpg
          'off': /local/images/test/lightgreen_3.jpg
      - type: state-label
        entity: input_select.test_tri_state
        style:
          top: 20%
          left: 10%

image


"config-template-card" method:

Place the whole picture-elements card inside “config-template-card” and set the main image in a JS template dynamically:

type: vertical-stack
cards:
  - type: entities
    entities:
      - entity: input_boolean.test_boolean

  - type: custom:config-template-card
    variables:
      INPUT_BOOLEAN: states['input_boolean.test_boolean']
    entities:
      - ${INPUT_BOOLEAN.entity_id}
    card:
      type: picture-elements
      image: >-
        ${INPUT_BOOLEAN.state === "on" ?
        "/local/images/test/blue.jpg" :
        "/local/images/test/orange.jpg" }
      elements:
        - type: state-label
          entity: sun.sun
          style:
            top: 50px
            left: 100px

image

Here only the “‘input_boolean.test_boolean’” entity is defined as “monitored”, but IRL all entities used on the “picture-elements” card must be listed as “monitored”.
I do not recommend this method since it may cause flickering of the card (the whole card is redrawn if any of monitored entities changes).

3 Likes

A few words about actions:

Consider this example:

  - type: picture-elements
    image: /local/images/test/transparent_1920_1080.png
    elements:

      - type: image
        entity: zone.home
        style:
          top: 0%
          left: 0%
          transform: translate(0,0)
        image: /local/images/test/lightgreen_1.jpg

      - type: state-label
        entity: sun.sun
        style:
          top: 20%
          left: 20%

      - type: icon
        icon: mdi:car
        style:
          top: 20%
          left: 60%
        tap_action:
          action: navigate
          navigation_path : /developer-tools/yaml

      - type: state-icon
        entity: input_boolean.test_boolean
        style:
          top: 50%
          left: 10%

      - type: icon
        icon: mdi:link
        style:
          top: 50%
          left: 70%
        tap_action:
          action: url
          url_path : http://google.com

      - type: icon
        icon: mdi:circle
        style:
          top: 50%
          left: 90%
        tap_action:
          action: call-service
          service: input_boolean.toggle
          data:
            entity_id: input_boolean.test_boolean

      - type: service-button
        title: Toggle boolean
        style:
          top: 75%
          left: 30%
        service: input_boolean.toggle
        service_data:
          entity_id: input_boolean.test_boolean

Here each element has an associated action:
– the “image” element - used to “mimic” the card’s main image (it covers the whole card - described here & here); the main image itself cannot have an action associated;
– the “state-label” element has a default “more-info” action;
– two “icon” elements have “navigate” & “url” actions;
– another “icon” element uses “input_boolean.toggle” service call;
– the “state-icon” element has a default “more-info” action;
– the “service-button” element uses “input_boolean.toggle” service call.


Next, imagine that an additional layer should be added into the card (in case of a floorplan - could be a dark room mask). To prevent overlapping other elements, this layer must be added BELOW other elements (which may be overlapped otherwise):

  - type: picture-elements
    image: /local/images/test/transparent_1920_1080.png
    elements:
      - type: image
        entity: zone.home
        ....

      - type: image
        style:
          top: 0%
          left: 0%
          transform: translate(0,0)
          pointer-events: none
        image: /local/images/test/transparent_mask.png

      - type: state-label
        ...

      ...

image

Note a “pointer-events: none” style which makes this layer “transparent”, i.e. here an action for the 1st image element is executed.


Regarding “service-button”.
It is used to call a service - so it cannot be used to show “more-info”, navigate or follow url.
If you need to have a “service-button” to execute of of these actions - you may “mimic” this element by a “state-label” element:
image
Here “service-button” on the right, “state-label” on the left.
Add this element:

      - type: state-label
        entity: input_text.test_text
        style:
          top: 75%
          left: 60%
          color: var(--primary-color)
          text-transform: uppercase
          font-family: var(--mdc-typography-button-font-family,var(--mdc-typography-font-family,Roboto,sans-serif))
          font-weight: var(--mdc-typography-button-font-weight,500)
          letter-spacing: var(--mdc-typography-button-letter-spacing,0.0892857em)
          font-size: var(--mdc-typography-button-font-size,0.875rem)
        tap_action:
          ...

Here CSS values are same as used for the “service-button” element and may be changed in some HA version, so use this method on your own risk.

reserved post 16

reserved post 17