Open brandonmcconnell opened 1 year ago
~Also posted this same proposal to https://github.com/whatwg/html/issues/9064. It's a clear duplicate, so whichever place is better suited for this proposal, let's keep it there and close the other.~
UPDATE: I closed the other duplicate issue in favor of this one, as it feels more in line with the realm of the CSSWG.
I would love this, I'm tired of tricky <use>
setups that provide the desirable cached asset strategy while also being stylable. With this proposal, I'd use the <img>
tag and let it do all the tricky work, while i get to style shapes inside it 👍🏻
With CSS Linked Parameters there is already an approach to pass parameters to an SVG or other external resources.
It provides three ways to style SVGs via specific parameters.
Sebastian
@SebastianZ Thanks! I hadn't heard of that yet.
TL;DR — I think that CSS Linked Parameters draft looks really cool, though I don't think it removes the need/value in a proposal like ::src
. I think they would both be valuable tools in the tool belt, and I can imagine scenarios where I would reach for either one.
Some key differences between the two proposals are…
img[src]
or in the CSS url()
function.img
element is in as well as the structure of the svg
source itself (see example 5 above).@brandonmcconnell I actually also like your approach, just wanted to outline that there is already something targetting the SVG styling issues we currently have.
You outlined the differences quite well. And those differences indicate their advantages and disadvantages.
From a CSS author's perspective, the big advantage of this proposal is that they are in full control of styling the SVGs.
Though this may be seen as a disadvantage, too, as its easier to violate any copyrights regarding the SVGs when allowing to manipulate them arbitrarily. But that's something that can (roughly) be targeted via the mentioned disallow-external-styles
or allow-external-styles
.
And the approach here is (at least currently) limited to SVGs referenced in <img>
elements. The Linked Parameters approach, while mainly focusing on SVG as well, can also target other resources like documents in iframes.
From this view, and especially regarding documents in iframes, it makes a lot of sense that both the author's CSS and the resource have to agree on specific parameters for manipulation. So that approach can be seen as an API.
Also, this approach is limited to resources referenced via HTML. And because it uses a pseudo-element, it is limited to styling one resource. Though in CSS you can reference different resources like in the following example:
.container-with-border {
border-image: src('border.svg') 30;
background: src('background.svg') center / contain no-repeat;
}
With Linked Parameters you can style both images individually. With the ::src
approach, styling them is not possible at all.
For what it's worth, the approach might also target <source>
s within <picture>
elements and possibly other media referencing HTML elements.
Sebastian
@SebastianZ Thanks! I really appreciate your insight, and that helps me to better understand the reaches of the Linked Parameters draft as well as better understand the differences between both approaches and their advantages/disadvantages. Super exciting stuff 👏🏼
I totally agree with you btw. I'm sure this approach will be more useful than just for SVGs on img
, as will probably reach picture
/source
and maybe even video
someday depending on what sources are supported down the line.
I would call the proposed pseudo-element ::content
because it forms the shadow root for the replaced content, i.e. if we assume img {content: attr(src)}
still worked. That’s why there should also be likewise pseudo-elements to match all other properties that may embed external content (usually images):
::marker
could be extended to become the same for list-style-image
. ::background
or an extended ::backdrop
or maybe ::canvas
for background-image
::border
for border-image
(and probably variants for all edges)@Crissov I really like that idea. We can certainly bikeshed on the name a bit more and do something other than ::src
.
I like the ::content
name a lot too, as long as it won't confuse users between the content
property and the ::content
pseudo-element, but as you pointed out, I think that they could actually work well together. In that case, keeping the name the same would be ideal.
@Crissov Note that background-image can take a list of images, so ::background
would have to use a function notation.
Having said that, this would allow to "pierce into" the contents of individual images. Though I am not a big fan of introducing a new pseudo-element for each property that can take an <image>
value.
Sebastian
I think the immediate and most useful case would be for svg
images. At least for this first spec, I think it would be best to continue either without support for background-image support, as that is a pretty unique use case, or do so with a separate pseudo, as you mentioned, like ::background
though I hear you and also would like to avoid adding too many pseudos if we can help it.
Table of Contents
Description
Currently, it is not possible to apply CSS styles to an SVG if it is used via
img[src]
.This proposal adds a new CSS syntax that would enable developers to target the root SVG element in such cases and apply CSS styles to it and its descendants.
Proposal
To achieve this, a pseudo-element can be added to the img src link that acts as the root for the SVG, allowing styles to be targeted for both the SVG and its child elements. The syntax for this can use
::src
as it is tied to thesrc
for the image.Syntax
To target the root SVG element, the syntax can be as follows:
To target child elements within the SVG, the syntax can follow standard CSS selector patterns:
All usual CSS selector patterns, properties, rules, and other conventions would work here as if the SVG had been embedded directly on the page, under the
img
element.Architecture
Any styles applied to
img::src
would not conflict with styles set on theimg
itself. Rather, think of it almost as if thesvg
element is a direct child of theimg
element, ifimg
supported such a thing. This is very similar to how the ShadowDOM and shadow roots already work. In fact, the ShadowDOM may be the ideal implementation/solution for this proposal.Consider this example:
This above code would be treated similarly to a ShadowDOM tree where
img::src
exposes thesvg
element as a shadow-root under the image itself. So in this example, the twoborder
styles would not conflict but rather, theimg
element would receive its assignedborder
styles, and then thesvg
would receive itsborder
styles applied viaimg::src
as if it had been assigned to thesvg
element itself.Examples
SVG source for below examples (expand/collapse)
For completeness, here is example HTML/SVG source that can be used with the below examples: ```html ``` ```html ``` This looks like this: --- ### …and now for the actual examples:
To demonstrate the proposed syntax, here are two examples targeting the root SVG and a child element within it:
1️⃣ Example 1: Targeting the root SVG
In this example, the `fill` property is applied to the root `svg` element: ```css img::src { fill: red; border: 10px solid blue; } ```2️⃣ Example 2: Targeting a child element within the SVG
In this example, `fill` and `stroke`-related properties are applied to the `rect` element, and `font`-related properties are applied to the `text` element within the SVG: ```css img::src g rect { fill: violet; stroke: red; stroke-width: 3%; stroke-dasharray: 2px; } img::src g text { font-family: cursive; font-size: 32px; } ```3️⃣ Example 3: Applying a rotation animation to the
In this example, an animation is applied to the `rect` element within the `g` group: ```css img::src g rect { animation: rotate 3s linear infinite; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ```rect
element4️⃣ Example 4: Applying a transition to the
In this example, a transition is applied to the `fill` property of the `text` element within the `g` group. When the `text` element is hovered, its `fill` property is changed: ```css img::src g text { transition: fill 0.5s ease-in-out; } img::src g text:hover { fill: green; } ```text
element on:hover
5️⃣ Example 5: Styling all icons from a specific directory to be a default color and then change colors on `:hover` and `:active` states, respectively
In this more practical example, any `svg` icons pulled from a specific directory (e.g. `/my-icons/`) will receive a default color and then a different color and transition on hover, only when displayed under the `.gallery` section: ```css :root { --default-gallery-icon-color: cyan; --hovered-gallery-icon-color: magenta; } .gallery img[src^="/my-icons/"]::src { fill: var(--default-gallery-icon-color); transition: all 0.5s ease-in-out; } .gallery img[src^="/my-icons/"]::src:hover { fill: var(--hovered-gallery-icon-color); transform: scale(1.25); } ``` I'm not sure how feasible this example is, depending on if we can granularly pass user events like a hover state into the image's source. If so, this would be great.Other thoughts & gotchas
In terms of security, I don't foresee too much if any risk in this feature. That said, I can imagine situations where someone may not want their SVG meddled with and would want a way to prevent style injections like this. With that in mind, it could be helpful to add support for an attribute to `svg` to enable disallowing style injection, like `disallow-external-styles`: ```html ``` Notably, while we could add an attribute like `allow-external-styles` to instead allow such styling on a per-case basis, I think the better default would be to allow styling unless specifically disallowed.