Home > other >  How to group the css selectors
How to group the css selectors

Time:08-06

:host([aspect-ratio='square']) img {
      aspect-ratio: var(--ratio-square);
    }
    :host([aspect-ratio='landscape']) img {
      aspect-ratio: var(--ratio-landscape);
    }
    :host([aspect-ratio='portrait']) img {
      aspect-ratio: var(--ratio-portrait);
    }
    :host([aspect-ratio='widescreen']) img {
      aspect-ratio: var(--ratio-widescreen);
    }
    :host([aspect-ratio='ultrawide']) img {
      aspect-ratio: var(--ratio-ultrawide);
    }
    :host([aspect-ratio='golden']) img {
      aspect-ratio: var(--ratio-golden);
    }

How can I make it to a single line? by reducing the duplicates of this code

CodePudding user response:

I don't think you can reasonably do this with a single line.

You could do simplify it with Sass/Scss:

$ratios: "square", "landscape", "portrait", "widescreen", "ultrawide", "golden";

@each $ratio in $ratios {
    :host([aspect-ratio='#{$ratio}']) img {
      aspect-ratio: var(--ratio-#{$ratio});
    }
}

Which generates the CSS:

:host([aspect-ratio='square']) img {
    aspect-ratio: var(--ratio-square);
}

:host([aspect-ratio='landscape']) img {
    aspect-ratio: var(--ratio-landscape);
}

:host([aspect-ratio='portrait']) img {
    aspect-ratio: var(--ratio-portrait);
}

:host([aspect-ratio='widescreen']) img {
    aspect-ratio: var(--ratio-widescreen);
}

:host([aspect-ratio='ultrawide']) img {
    aspect-ratio: var(--ratio-ultrawide);
}

:host([aspect-ratio='golden']) img {
    aspect-ratio: var(--ratio-golden);
}

CodePudding user response:

I can't think of any CSS only solution here. You'd basically need to be able to read the content of the attribute (attr() should be able to do that), and then use it to compose a new CSS variable. This last step is more problematic, I don't think there is any way to compose strings in CSS and pass them to a func like var().

I would have hoped for the new @property rule to allow us to do something around that, but when I tried to reference var(--css-var) values as syntax that simply failed (with no real surprises I must admit). And even if that did work, I'm not sure the attr() could have been used there either. attr() produces <string> and I don't think there is a way to convert a <string> to a variable name.

So the best I can think of as a CSS HTML only solution is to modify your HTML code so that instead of doing

<my-elem aspect-ratio="square">content</my-elem>

You do

<my-elem style="--ratio:var(--ratio-square)">content</my-elem>

As you can see, that's a bit more character but stays relatively readable, and then your CSS can become

:host([style*="--ratio:"]) img { aspect-ratio: var(--ratio) }

class MyElem extends HTMLElement {
  constructor() {
    super();
    const style = document.createElement('style');
    const img = new Image();
    const shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.appendChild(style);
    shadowRoot.appendChild(img);

    style.textContent = `
img { width: 150px; border: 1px solid; }
:host([style*="--ratio:"]) img {
  aspect-ratio: var(--ratio);
}    
`;
  }
}
customElements.define("my-elem", MyElem);
:root {
  --ratio-square: 1/1;
  --ratio-landscape: 4/3;
  --ratio-golden: 1/1.618;
}
<my-elem style="--ratio:var(--ratio-square)"></my-elem>
<my-elem style="--ratio:var(--ratio-landscape)"></my-elem>
<my-elem style="--ratio:var(--ratio-golden)"></my-elem>

But given that you are in a ShadowDOM, you can actually keep that attribute and use your CustomElement's constructor to set the proper CSS variable at construct:

class MyElem extends HTMLElement {
  constructor() {
    super();
    const style = document.createElement('style');
    const img = new Image();
    const shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.appendChild(style);
    shadowRoot.appendChild(img);
    const ratio = this.getAttribute("aspect-ratio");
    style.textContent = `
img { width: 150px; border: 1px solid; }
:host([aspect-ratio]) img {
  aspect-ratio: var(--ratio-${ratio});
}    
`;
  }
}
customElements.define("my-elem", MyElem);
:root {
  --ratio-square: 1/1;
  --ratio-landscape: 4/3;
  --ratio-golden: 1/1.618;
}
<my-elem aspect-ratio="square"></my-elem>
<my-elem aspect-ratio="landscape"></my-elem>
<my-elem aspect-ratio="golden"></my-elem>

  • Related