-
Notifications
You must be signed in to change notification settings - Fork 693
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[css-images] @image rule for manipulating images #6807
Comments
Big +1 here, I like this a lot. The fact that you can just use existing properties in easily-understood ways is a big plus here, both for authors and for us spec editors.
This is doable.
Already solved, yeah - this would define tree-scoped names. |
Great stuff, but won't this increase the overall parse time of the styles. How is the performance metrics? |
Agreed, this would be great. Do note that the syntax above is not a new microsyntax, it's taken directly from |
Yeah, using the image-set syntax and semantics is much better than trying to reproduce it thru media queries; MQs fundamentally can't handle resolution negotiation. |
would |
I hadn't thought of that, but I don't see why not. Cool use case! |
@booluw wrote:
As I understand it, the parse time doesn't increase much. It's the generation of the image that slows down its display a bit. I'm not an implementer but I assume the effect to be comparable to applying the existing properties to the element the image is used on. What I mean by that is that a The difference is that it's just the image that's affected and not a whole element. And the generated image can be cached and reused in different places. Thinking a bit more about this, I think it makes sense to split the manipulations from the image itself. So we'd have an Taking @LeaVerou's example this would then look like: @image-manipulation --foo {
aspect-ratio: 1 / 1;
width: 100vw;
object-fit: cover;
filter: blur(10px);
opacity: .5;
transform: rotate(5deg);
}
This has the advantage, that authors can easily apply the same manipulations to different images and that existing logic for loading/generating the images can be reused. So instead of @image --foo {
src: url("foo.png") 1x
url("foo-2x.png") 2x,
url("foo-print.png") 600dpi;
...
}
background-image: image(--foo); for providing different image sources for the image manipulation you'd write @image-manipulation --foo {
...
}
background-image: manipulate-image(
image-set( "foo.png" 1x,
"foo-2x.png" 2x,
"foo-print.png" 600dpi
),
--foo
); Sebastian |
I love it! Yes, reusable image manipulations are far better than my original proposal (assuming we bikeshed the names). |
@SebastianZ reuseable image manipulations would actually help in performance since the logic would be cached. |
I have a faint memory from back in the day that |
@jsnkuhn Note that the idea behind this feature is to allow manipulating existing images. Having said that, you could still achieve it with what was proposed earlier. With the proposed @image-manipulation --circle {
width: 190px;
aspect-ratio: 1;
clip-path: circle(closest-side);
}
.category-link {
background-image: manipulate-image(image(#e2edfb), --circle);
background-repeat: no-repeat;
background-position: center center;
} And regarding Sebastian |
Btw. here are some name suggestions for rule and function name combinations:
Obviously some of them fit better than others, though I just wanted to get the ball rolling for that. Sebastian |
You could easily create new images by starting something like |
@SebastianZ
|
Doesn't the |
Just a recap, as it seems, people have forgotten about or have different understandings of the proposals: @LeaVerou's initial idea was to create an image and manipulate it with this at-rule by defining the image source via the @LeaVerou wrote:
@booluw wrote:
Did you think of the initial proposal or do you expect the Linear gradients (like any other images) are covered by both proposals. In Lea's proposal: @image --rainbow-circle {
src: linear-gradient(red, yellow, lime, blue, purple);
width: 400px;
aspect-ratio: 1;
clip-path: circle(400px);
}
.rainbow {
background-image: image(--rainbow-circle);
background-size: contain;
} My proposal: @image-manipulation --rainbow-circle {
width: 400px;
aspect-ratio: 1;
clip-path: circle(400px);
}
.rainbow {
background-image: manipulate-image(linear-gradient(red, yellow, lime, blue, purple), --rainbow-circle);
background-size: contain;
}
@jsnkuhn expected the at-rule to work on the box model. Though the idea is to let it work on the image. A An issue that can arise is when images do not have an intrinsic size like gradients, colors or some forms of SVGs. For them it needs to be defined what happens when you provide percentages or other relative units like Sebastian |
Thanks @SebastianZ. |
There's another interesting use-case, I've mentioned it to @LeaVerou at CSSDay, having the So, the idea is to somehow hint to the browser that this image @image-manipulation --recolor-effect {
filter: url(recolor-filter.svg#filter);
will-change: none;
}
.bg-parallax {
background-image: manipulate-image(image(url(bg.webp)));
} And then animate |
apologies for the confusion I think that some of the example ideas I've posted might fall better under something like So let me give this another try: We have one background image that is then rotated in different ways to create slightly visually different backgrounds for the different links.
in this case having to repeat the |
@booluw wrote:
You are right that a new image is created by manipulating the source image. And with
I wouldn't say that the image has its own box model. There are properties like @ydaniv wrote:
I expected the images generated by an @jsnkuhn wrote:
The proposed syntax would actually look like this: a:nth-of-type(2) { background-image: manipulate-image(url(yellow.webp), rotate-x-y); }
a:nth-of-type(3) { background-image: manipulate-image(url(yellow.webp), rotate-x); }
a:nth-of-type(4) { background-image: manipulate-image(url(yellow.webp), rotate-y); } I know, that makes it even longer to write. Though I assume the final name for the image manipulation function probably won't be that long. Sebastian |
We talked about resolution of the source image a lot, though we didn't talk about setting the resolution of the manipulated image. Sebastian |
The CSS Working Group just discussed
The full IRC log of that discussion<heycam> Topic: @image rule for manipulating images<heycam> github: https://github.com//issues/6807 <heycam> TabAtkins: this is a request for feedback and possible WD, precised details are being discussed on the thread <heycam> ... this is a request for a way to manipulate images directly in CSS <heycam> ... right now you can do a handful of things directly in CSS <heycam> ... certain repetitions with background properties <heycam> ... but anything more complex, running a filter on it, opacity, etc. your only choice is to use a separate image, or to put it on a declarative element and then apply CSS properties to that element <heycam> ... this is trying to split the different, and allow existing existing effecfts (transforms, filters), directly in a CSS image <heycam> ... rough approach is an @image rule, which provides a doubel dashed name <heycam> ... a bunch of descriptors, which takes a src image, then others which are copies of other CSS properites that do useful things <heycam> ... currently only supporting things you can already do to elements <heycam> ... once defined, you could use this image in CSS <heycam> ... image(--foo) <Rossen_> q? <heycam> q+ <Rossen_> ack heycam <fantasai> heycam: Alternative approach is to slam all of these filtering and transforms into the image() function itself <fantasai> heycam: if you need to re-use that, put it all into a custom property <fantasai> heycam: have you thought about that? <heycam> TabAtkins: I don't believe there's a great reason to go one way or the other <heycam> ... back in the day, using it in an image() function you'd need to repeat it <heycam> ... but with variables it's not a huge deal now <heycam> ... some bits of functionality like image layering have been discussed, but more widely as pulling in SVG's filter capabilities via nested at rules <heycam> ... having them be consistent in approach would be nice <heycam> ... but now that I bring that up, it could still be done using CSS functions <heycam> ... it would be a matter of what we find more convenient to do, or more natural <JakeA> q+ <heycam> ... don't think there's a huge way to go one way or the other <Rossen_> ack dbaron <heycam> dbaron: could you talk briefly about how sizing of these images works? <heycam> ... looks like there's some sizing related properties in there <heycam> ... transforms and filters which might have sizing implementations <heycam> TabAtkins: you have a width/height property <heycam> ... that's the natural width/heihgt of the produced image <heycam> ... scaling etc. would be purely visual effects <andreubotella> q+ <heycam> ... it would scale it within the bounds of the width/height that's already been provided <Rossen_> ack JakeA <heycam> JakeA: for blurring a low quality image as a placeholder <heycam> ... that's difficult with filters now, because it blurs the edge as well <heycam> ... here you want to recognize the edge and not blur the transparency into it <heycam> ... so it works a bit more like backdrop-filter <Rossen_> ack andreubotella <heycam> andreubotella: could you use such an @image rule in the src property? <heycam> ... if you already have declared an image, then you want to apply some further transformations to that? <heycam> ... and for the current properties, it seems like you could apply a set of properties to multiple images <heycam> TabAtkins: the exact answer to that depends on what we want to define <heycam> ... being able to put a generated image in as the source of a new generated image is reasoanble <ydaniv> q+ <heycam> ... whether that gets rasterized then transformed, as if it's an independent image, or these transformations are additively appended to the list of existing transformations in some intelligent fashion? no opinion <heycam> ... both have pros/cons. simplicity on one side, understandability <heycam> ... avoiding rasterization effects <heycam> ... both seems potentially reasonable <heycam> ... can discuss those <heycam> andreubotella: thinking also maybe not having it rasterized, that might limit the properties we could add to @image rules <heycam> TabAtkins: I think everythign we've discssed so far in the thread is compatible with just holding it as a scene graph <heycam> ydaniv: might be some advantage to have this rasterized beforehand <Rossen_> ack ydaniv <heycam> ... if you're just setting the properties outside the at rule, you could have them animated <heycam> ... then if you want to do further animations on the element, then have the browser apply all of these at the same time every frame, could be heavy for the browser to handle <heycam> ... so maybe this could be some sort of performance boost <heycam> ... another thing that might be way off, if you're thinking about syntax, having this for replaced images, object manipulation, that could be useful <heycam> ... so not just for background-image, <image> values, but use the same manipulations on replaced elements like straight on an <img> element <heycam> TabAtkins: right now you can take any replaced element and put properties on it <heycam> ... but you want to be able to run these on the underlying image itself, and still be displayed in the bounds of the image element? so apply a rotate to the source image? <heycam> ydaniv: I want to optimize for having the src already rasterized, then if I'm rotating the image outside, then the browser doesn't have to handle rasterizing every frame <heycam> ... what you're saying is another use case which is also valuable <Rossen_> ack dbaron <Zakim> dbaron, you wanted to talk about ordering <heycam> dbaron: Andreu's comment made me think about another set of questions about the ordering of these operations <heycam> ... in CSS, a bunch of these things are properties where the order that they apply in is defined by our processing model <heycam> ... the relative ordering we apply opactiy, filter, transform, etc. on a single element is defined by CSS's processing model <heycam> ... one thought is that re being able to nest the output of one of these as the source of another, that's probably quite useful, since sometimes you want to apply these things in a differetn order than how CSS's processing model works <heycam> TabAtkins: os the same descriptor multiple times in different fashions <heycam> s/os/or/ <heycam> dbaron: maybe falling back to that processing model isn't the right thing here? for this rule, the graphical operations maybe shouldn't be order independent? <heycam> ... so the order of the descriptors matters <heycam> TabAtkins: if you have them in an order, that implies you should be able to repeat: rotate, blur, rotate <heycam> ... first, object model issues <heycam> ... also, that would run into our forward compat fallback ability <heycam> ... where you can say something twice and ignore the first, unsupported value <heycam> ... but I like the way you are thinking <heycam> ... having this order be controllable is probably a great idea <Rossen_> q? <emilio> q+ <Rossen_> ack emilio <heycam> emilio: that kind of issue disappears if you add the operations in the image() function <heycam> TabAtkins: yes, it removes the fact taht ordering and repetition is ap roblem <heycam> ... now support is an all or nothing for the entire graph <heycam> ... on the other hand, if an image transform isn't supported, and you are trying to rely upon it, you probably do want the whole thing to fail <heycam> ... so that is an argument in favor of a function <heycam> q+ <emilio> heycam: I realized that there might be a semantic difference between image() and the at rule <Rossen_> ack heycam <emilio> ... each of those are a different image <emilio> ... is there any situation where having the image defined in the at-rule lets you have a single place where you can do image manipulations, where with image() you'd need to apply the transform to all uses of the image() function <emilio> ... it's probably not an issue, I don't think they can express different things <emilio> TabAtkins: being able to say that one in an at-rule there's an efficiency arg to be made there <heycam> TabAtkins: how to animate an at rule is an open question <heycam> ... how to animate a function is already a reasonably solved problem <heycam> ... match up lists, animate individual parameters <heycam> TabAtkins: does the WG feel this is OK, or objectiosn to the approach in general? <heycam> fantasai: my main concern is prioritization wrt other things we're doing <heycam> ... other than that doesn't seem terrible <heycam> Rossen: from a use case approach, it's fine <heycam> fantasai: definitely needs a lot more work <heycam> Rossen: that's like most other work we take on <heycam> fantasai: this is not a small task <heycam> Rossen: assuming Mia and others will be contributing to this? <heycam> TabAtkins: I'm shepherding this <andreubotella> /s/Mia/Lea/ <heycam> Rossen: acknowledge this adds more work to the group, but I'm hearing support for the use case and approach <heycam> ... so I'm personally OK with this <fantasai> s/Mia/Lea/ <heycam> TabAtkins: do we want this added to images 5, or is it larger enough to be split out? <heycam> fantasai: what else is in images 5? <heycam> Rossen: almost nothing <heycam> fantasai: current images is images-4. images-5 is just an ED, don't think there's anything even in it <heycam> TabAtkins: just want to know if it should be merged into the totality of the images spec <heycam> RESOLVED: Accept @image and add it to css-images-5 |
It's getting late here, but just some quick thoughts on the meeting discussion:
This was the initial proposal by @LeaVerou but the discussion since moved towards a rule purely used for manipulating the images and using a function to specify the source image.
This is definitely an interesting approach that would probably make animation easier and easily allow applying manipulations in order. Though I assume it may also quickly get quite complicated syntax-wise.
I imagined Imagine you rotate an image by 30 degrees and you want it not to be clipped. Without auto-sizing, you have to calculate the new size of the canvas yourself, then calculate the padding that is needed to get that size to finally be able to rotate the image.
The repository doesn't hold any images-5 ED yet. There are just a few issues labelled with css-images-5. Sebastian |
asking this a different way: would |
Nah, not particularly, it would just be :root {
--hero-image: image("hero-base.png",
rotate(...)
repeat(...)
sepia(...)
);
} |
The downside of that is that is that it doesn't align with existing properties and you might not be able to express everything with that like e.g. Sebastian |
A few more thoughts. ScalingThinking about this a bit more, I don’t think we should restrict ourselves to descriptors that correspond to CSS properties. Obviously when concepts match we should re-use CSS property names as much as possible, but there are many concepts that are useful for manipulating images, but do not have a corresponding CSS property. It seems to me that For 9-slice scaling, there is no corresponding CSS property that would make sense, but it seems pretty straightforward to add a descriptor like:
or two separate descriptors ( We also need to be able to optionally decouple the source bounding box from the output bounding box. The original proposal includes size properties as overriding the image’s intrinsic dimensions, but assumes these will also be the intrinsic dimensions of the output. Using
|
@LeaVerou Your proposal somewhat overlaps with The use case of tiling and repeating the image sounds reasonable. Though I wonder why we need a Sebastian |
I like @LeaVerou's idea of supporting both creating and manipulating images via Could we also support a use case for inline-defined images and manipulations for any images/manipulations that are intended for single use and do not need to be defined under a variable name for reuse? Hypothetically, this would be supported: @image --circle {
src: url(/some-path/background.png),
width: 190px;
aspect-ratio: 1;
clip-path: circle(closest-side);
}
.category-link {
background-image: image(--circle, { width: 100px });
background-repeat: no-repeat;
background-position: center center;
} Any braced object inside It may even prove an equally common use case to store a common set of rules for an image inside an @image --fancy {
/* some rules */
}
#element-1 {
background-image: image(--fancy, { src: '../some-image.png' });
}
#element-2 {
background-image: image(--fancy, { src: '../some-other-image.png' });
} |
@brandonmcconnell Yes, I think we should do this. Supporting complex use cases should not come at the cost of making simple use cases more complicated. In fact, why not support both? |
There have been a lot of issues over the years about manipulating an existing image in some way before it's used by CSS.
Some examples from a quick search:
background-filter
#4706There are also a bunch of features we defined and never got implementor interest, such as
filter()
orbackground-image-transform
.With my author hat on, I've also stumbled on use cases where I wanted to transform images, even in simple ways such as being able to override an image's intrinsic dimensions while setting
background-size
to a different size. Or just essentially settingobject-fit: cover
on a background-image so I could usebackground-size: <percentage>{2}
without distortion.What if we could address all of these in one fell swoop by creating a new at-rule to define images that CSS can then access through the
image()
function?Something like:
Which would then be used like:
Since any
<image>
is allowed insrc
, this can be used to create variants of the same image:The descriptors I envision being allowed in
@image
are:src: <image>
: Mandatory, sets the image we are manipulating. Can be any CSS<image>
including gradients etc.width
,height
,inline-size
,block-size
to override intrinsic dimensions. Percentages resolve relative to original intrinsic size OR viewport (not sure which one makes more sense; at least the latter is always available)aspect-ratio
to override intrinsic aspect ratiomargin
to add (transparent) spacing around imageobject-fit
opacity
filter
transform
and friends (translate
,scale
,rotate
)clip-path
mask
The
src
descriptor could also support setting the source to a different image depending on resolution, as a nicer to read alternative ofimage-set()
.Instead of:
it would be:
In fact, it would be nice if one could specify different descriptors depending on resolution, so that people could do things like:
In the future, we may even want to add descriptors providing a fallback, color space, or other metadata about images.
The advantages of this syntax I see are:
@image
rule and then they can even guess the descriptors they need as they are essentially a subset of existing CSS properties.filter()
. Compare:with:
The main downsides I see :
filter()
it's possible to usevar()
references trivially, and interpolation works out of the box. It's unclear if it's possible to havevar()
references resolve at the point of usage of the image, and interpolation may be trickier to define (but possible).@property
wrt to global scope and shadow DOM (but that applies to most at-rules anyway and we likely need to fix it for all of them)The text was updated successfully, but these errors were encountered: