Open LeaVerou opened 2 years ago
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.
With functional syntaxes like filter() it's possible to use var() references trivially, and interpolation works out of the box. It's unclear if it's possible to have var() references resolve at the point of usage of the image, and interpolation may be trickier to define (but possible).
This is doable.
It has the same issues as @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)
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?
Re. different things depending on resolution, could you nest @media inside @image to do this? That would open all sorts of doors, without inventing another microsyntax.
Re. different things depending on resolution, could you nest @media inside @image to do this? That would open all sorts of doors, without inventing another microsyntax.
Agreed, this would be great. Do note that the syntax above is not a new microsyntax, it's taken directly from image-set()
. It is therefore an old microsyntax 😁
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 clip-path
inside @image function as a spriting syntax?
would
clip-path
inside @image function as a spriting syntax?
I hadn't thought of that, but I don't see why not. Cool use case!
@booluw wrote:
Great stuff, but won't this increase the overall parse time of the styles. How is the performance metrics?
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 filter: blur(10px);
in an @image
rule would have a similar effect on the performance as a filter: blur(10px);
on an element.
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 @image-manipulation
rule and a corresponding manipulate-image()
function we put the images through.
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);
}
background: manipulate-image(url("foo.png"), --foo);
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).
If border-radius
/corner-shape
would be supported folks could do something like these over sized background pills:
@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 border-image
was originally being implemented of folks taking issue with the fact that a 3x3 grid of a single image was necessary for border-image-source
and that they wished there were a way to do it with just one instance of that image. @image
would finally solve this by leveraging background-repeat
and making an element size 3x that of the image to generate the 3x3 grid from the single image.
ran across a situation on walmart.com where I think @image
might help:
.category-link{
background-image: image(--foo);
background-repeat: no-repeat;
background-position: center center;
}
@image --foo {
width: 90%;
aspect-ratio: 1;
background-color: #e2edfb;
border-radius: 50%;
}
@jsnkuhn Note that the idea behind this feature is to allow manipulating existing images. Your example obviously is meant to create one, which I believe is out of scope of this proposal.
Having said that, you could still achieve it with what was proposed earlier. With the proposed @image-manipulation
rule (and yes, @LeaVerou, we should find a better name for it) this could be done with
@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 border-radius
and corner-shape
, I agree that they could be part of this as well but their effect can also be achieved by using clip-path: circle()
as shown above or clip-path: path()
for other shapes than circles.
Sebastian
Btw. here are some name suggestions for rule and function name combinations:
@image-change
/ change-image()
@image-edit
/ edit-image()
@image-modification
/ modify-image()
@image-alternation
/ alter-image()
@image-adjust
/ adjust-image()
@image-adaptation
/ adapt-image()
@image-variation
/ vary-image()
@image-mutation
/ mutate-image()
@image-customization
/ customize-image()
@image
/ image()
(reusing the existing image()
function and introducing a new syntax to it may probably be a no-go, though)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 src: image(transparent)
or src: linear-gradient(...)
@SebastianZ ~I think the @image-customization / customize-image()
rule/function is better. Descriptive~
@image() / @image
is better, please. And if a user would use a gradient instead, should be defined inside of @image()
since an image is been 'created/manipulated' with that rule.
ran across a situation on walmart.com where I think
@image
might help:.category-link{ background-image: image(--foo); background-repeat: no-repeat; background-position: center center; } @image --foo { width: 90%; aspect-ratio: 1; background-color: #e2edfb; border-radius: 50%; }
Doesn't the width
here causes a conflict with background-size
property? Having two different widths might just leave room for buggy implementation.
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 src
descriptor and applying manipulations to it via the other descriptors.
My idea was to just put the manipulation rules into the at-rule (without src
descriptor), so you can reuse it for several images.
@LeaVerou wrote:
You could easily create new images by starting something like
src: image(transparent)
orsrc: linear-gradient(...)
@booluw wrote:
@image() / @image
is better, please. And if a user would use a gradient instead, should be defined inside of@image()
since an image is been 'created/manipulated' with that rule.
Did you think of the initial proposal or do you expect the src
descriptor to be optional? If the latter, this would merge both proposals, i.e. allow to define a one-off manipulation when the src
descriptor is provided or to reuse the manipulation by skipping the descriptor. Though that would also complicate the rule both for implementors and authors because it provides two different functionalities behaving different in different contexts.
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;
}
@booluw:
Doesn't the
width
here causes a conflict withbackground-size
property? Having two different widths might just leave room for buggy implementation.
@jsnkuhn expected the at-rule to work on the box model. Though the idea is to let it work on the image.
A width
in that rule means to manipulate the image's intrinsic width. The same applies to height
and aspect-ratio
. So, if an image has a size of 1000px x 1000px and you apply width: 500px
to it, it's intrinsic size is then 500px x 1000px. And that image can then be used with background-size
. So it is like you initially provided an 500px x 1000px image.
(See the example above where the generated image has an intrinsic width of 400px but is then resized via background-size: contain
based on the size of the element it is used in.)
And for clarity, providing a width
or any other size-related descriptors shrink or stretch the image. If the image shall be cropped, then clip-path
or object-fit
should be used.
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 em
.
Sebastian
Thanks @SebastianZ.
I think the sizes of those SVGs and gradients should be the values defined in the manipulation rule
, since the image is being created. That is; the image has it own box model, before being added to that of the element it is being applied to. Which implies that all box-model properties also work on the image.
There's another interesting use-case, I've mentioned it to @LeaVerou at CSSDay, having the @image-manipulation
add filters to the image and have the browser cache that, so that animating it later, using transform
for instance, will not cause browsers to melt down.
We had these exp. at Wix, where when applying both at the same time caused havoc, but when animating a canvas that already applied the filters, i.e. with effects already composited, the results were order(s) of magnitude better.
So, the idea is to somehow hint to the browser that this image will-not-change
, something like:
@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 .bg-parallax
without extra damage.
apologies for the confusion I think that some of the example ideas I've posted might fall better under something like element()
.
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.
@image-manipulation rotate-x-y {
transform: rotate(180deg);
}
@image-manipulation rotate-x {
transform: rotateX(180deg);
}
@image-manipulation rotate-y {
transform: rotateY(180deg);
}
a {background-image: url(yellow.webp);}
a:nth-of-type(2) { background-image: url(yellow.webp), rotate-x-y; }
a:nth-of-type(3) { background-image: url(yellow.webp), rotate-x; }
a:nth-of-type(4) { background-image: url(yellow.webp), rotate-y; }
in this case having to repeat the background-image: url(yellow.webp),
bit seems a bit clunky. Maybe there a way to do something more like manipulation-name
taking a cue from the already existing animation-name
property?
@booluw wrote:
I think the sizes of those SVGs and gradients should be the values defined in the
manipulation rule
, since the image is being created.
You are right that a new image is created by manipulating the source image. And with width
, height
and aspect-ratio
you can define the sizes of the manipulated image.
Though my question was how would a width: 80%;
be interpreted when the source image doesn't have an intrinsic width? I guess, the answer in that case is that the width of the manipulated image is undefined as well.
That is; the image has it own box model, before being added to that of the element it is being applied to. Which implies that all box-model properties also work on the image.
I wouldn't say that the image has its own box model. There are properties like padding
or box-sizing
that don't apply to it.
@ydaniv wrote:
There's another interesting use-case, I've mentioned it to @LeaVerou at CSSDay, having the
@image-manipulation
add filters to the image and have the browser cache that, so that animating it later, usingtransform
for instance, will not cause browsers to melt down.
I expected the images generated by an @image-manipulation
rule to always be cached because the manipulations are only applied once to an image. Or are there use cases, in which dynamically applying the rules is required?
@jsnkuhn wrote:
We have one background image that is then rotated in different ways to create slightly visually different backgrounds for the different links.
@image-manipulation rotate-x-y { transform: rotate(180deg); } @image-manipulation rotate-x { transform: rotateX(180deg); } @image-manipulation rotate-y { transform: rotateY(180deg); } a {background-image: url(yellow.webp);} a:nth-of-type(2) { background-image: url(yellow.webp), rotate-x-y; } a:nth-of-type(3) { background-image: url(yellow.webp), rotate-x; } a:nth-of-type(4) { background-image: url(yellow.webp), rotate-y; }
in this case having to repeat the
background-image: url(yellow.webp),
bit seems a bit clunky. Maybe there a way to do something more likemanipulation-name
taking a cue from the already existinganimation-name
property?
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 manipulate-image()
generates an <image>
value. That value can be used in many different properties like border-image-source
, mask-image
, list-style-image
, etc. And each one could have its own image manipulation applied. Therefore, a property like manipulation-name
(or rather background-image-manipulation
) that is bound to another property wouldn't make sense.
Though I assume the final name for the image manipulation function probably won't be that long.
Sebastian
@SebastianZ
I expected the images generated by an @image-manipulation rule to always be cached because the manipulations are only applied once to an image. Or are there use cases, in which dynamically applying the rules is required?
Other use cases are the old filter()
and others mentioned at the top, which could potentially be animated.
So does this rule imply immutability of the result without the ability to animate its properties?
I guess further animations could be applied in properties outside of the manipulation effects, which is reasonable.
@SebastianZ
You are right that a new image is created by manipulating the source image. And with
width
,height
andaspect-ratio
you can define the sizes of the manipulated image. Though my question was how would awidth: 80%;
be interpreted when the source image doesn't have an intrinsic width? I guess, the answer in that case is that the width of the manipulated image is undefined as well.
I think a width: 80%
should be interpreted in relation to the width of the elment the image is been applied to.
@ydaniv wrote:
I expected the images generated by an @image-manipulation rule to always be cached because the manipulations are only applied once to an image. Or are there use cases, in which dynamically applying the rules is required?
Other use cases are the old
filter()
and others mentioned at the top, which could potentially be animated. So does this rule imply immutability of the result without the ability to animate its properties? I guess further animations could be applied in properties outside of the manipulation effects, which is reasonable.
I see. Regarding the filter()
function, interpolation (and with that animation) is already defined in the Filter Effects specification.
Though I can now see the point for allowing to animate them. One way to achieve that with the proposed syntax would be:
@image-manipulation --rotate-image {
transform: rotate(359deg);
}
@keyframes --rotating-background {
from: { background-image: url("background.jpg"); }
to: { background-image: manipulate-image(url("background.jpg"), --rotate-image); }
}
.rotating-background {
animation: 35.9s --rotating-background infinite;
}
Alternatively, we might define the animation directly within the at-rule, i.e. allow the animation-*
properties as descriptors for the at-rule.
Though as far as I know, the descriptors of at-rules aren't animatable so far. So that would be a novelty. @LeaVerou Feel free to correct me on this.
So an example for that could then look like this:
@keyframes --rotate {
from: { transform: rotate(0deg); }
to: { transform: rotate(359deg); }
}
@image-manipulation --rotate-image {
animation: 35.9s --rotate infinite;
}
.rotating-background {
background-image: manipulate-image(repeating-url("background.jpg"), --rotate-image);
}
@booluw wrote:
You are right that a new image is created by manipulating the source image. And with
width
,height
andaspect-ratio
you can define the sizes of the manipulated image. Though my question was how would awidth: 80%;
be interpreted when the source image doesn't have an intrinsic width? I guess, the answer in that case is that the width of the manipulated image is undefined as well.I think a
width: 80%
should be interpreted in relation to the width of the elment the image is been applied to.
Making the manipulations dependent on the element they are used in, would cause significant performance issues as mentioned by @ydaniv. So if you animated the element's width, you'd have to run the manipulation rules for each frame of the animation and each element the rules are applied to.
Sebastian
Given the very positive feedback so far, let's add this to the agenda. Points to discuss:
Sebastian
If this feature was about image creation, it should not be limited to a single layer, i.e. it would require nesting or additive sources.
@image --composite {
@layer --stage {
src: "backdrop.jpg";
}
@layer --scene {
src: "parallax.png";
}
@layer --actor {
src: "map.svg#sprite";
position: 200px 300px;
}
}
I believe this would be suggested by the generic name @image
. Otherwise, a different and more specific name should be chosen, e.g. @image-effect
.
This issue is about image manipulation, i.e. creating variations of existing images. This is what the very first sentence of it says.
I am not completely against allowing the at-rule to also create completely new ones, though I am strongly in favor of restricting it to manipulation and rely on the existing methods to provide the source images, namely url()
, image-set()
, image()
, *-gradient()
, etc.
This allows to provide context sensitive images. And it makes implementations easier as they just have to provide one way of image sources.
Sebastian
Ah, and the use case of compositing images is a different one which should be discussed separately.
Sebastian
That @image
/ @image-manipulation
block surely looks a lot like @mixin
, no? Shouldn’t we then name it that way (or some other generic term), to leave the door open for future use-cases?
Note: not talking about its usage using the manipulate-image()
/ image()
function here; only targeting the at-rule / definition part.
@bramus I'm with you to keep the name @image
for future use cases, e.g. like combining the image manipulations discussed here with the compositing features mentioned by @Crissov, image creation features and possible other features.
Sebastian
This is already complex enough, if we add layers and other bells and whistles it's simply not going to happen in the forseeable future. I suggest we stay focused on the syntax that is needed to satisfy the majority of use cases, and not design around edge cases.
That @image / @image-manipulation block surely looks a lot like @mixin, no?
Can you elaborate on this? I don't see any resemblance.
That @image / @image-manipulation block surely looks a lot like @mixin, no?
Can you elaborate on this? I don't see any resemblance.
If you look at this example (as seen in the first post)…
@image --foo {
src: url("foo.png");
aspect-ratio: 1 / 1;
width: 100vw;
object-fit: cover;
filter: blur(10px);
opacity: .5;
transform: rotate(5deg);
}
… it’s an at-rule, an identifier, and a block with bunch of properties with assigned values (except for src
which isn’t a CSS property).
A basic mixin such as the one below (as seen in the Sass docs), also follows that same structure
@mixin reset-list {
margin: 0;
padding: 0;
list-style: none;
}
That @image / @image-manipulation block surely looks a lot like @mixin, no?
Can you elaborate on this? I don't see any resemblance.
If you look at this example (as seen in the first post)…
… it’s an at-rule, an identifier, and a block with bunch of properties with assigned values (except for
src
which isn’t a CSS property).A basic mixin such as the one below …
The suggested at-rule shares the syntax with a mixin like basically any at-rules with bodies but besides that there is no relation to mixins at all.
An @mixin
in Sass can have arbitrary properties and nested rules within it. The at-rule suggested here is restricted to a bunch of descriptors resembling properties (but which aren't properties) that are used to manipulate the given image. E.g. it does not allow padding: 0;
or list-style: none;
.
To summarize them, the descriptors proposed so far are:
src
aspect-ratio
width
height
inline-size
block-size
object-fit
margin
filter
opacity
transform
scale
rotate
translate
clip-path
mask
border-radius
corner-shape
background-color
will-change
animation
Which ones actually make it into the at-rule is still to be discussed.
Sebastian
Yeah, the similarity there appears to be just "follows standard CSS syntactic patterns", but the same can be said of almost any at-rule. @counter-style and @font-face also look like that, for example, but I don't think it's reasonable to say they're "like @mixin". At-rules containing descriptors is just how CSS things are written.
In particular, @mixin specifically contains properties that'll eventually apply to an element; @image here just contains descriptors that resemble existing properties but won't ever apply to an element in the page. (And nothing prevents us from adding descriptors that go beyond what properties can currently do, either.)
And I already start with the discussion. 😃
src
As stated earlier, should not be included, because the rule is meant to do image manipulations.aspect-ratio
Changes the aspect ratio of the image, i.e. stretches or shrinks it. Questions: Does it work the same way as the aspect-ratio
property? I.e. either width
or height
(but not both) must be explicitly set to a value and the other one to auto
?width
Changes the width of the image, i.e. stretches or shrinks it.height
Changes the height of the image, i.e. stretches or shrinks it.inline-size
Changes the width or height of the image depending on the writing mode, i.e. stretches or shrinks it. Question: How is the writing mode determined?block-size
Changes the width or height of the image depending on the writing mode, i.e. stretches or shrinks it. Same question as for inline-size
.object-fit
Changes the way how the image is fit into the area given by the width and height. Question: When we have this, would it make sense to also have object-position
?margin
Adds a transparent spacing around the image. Question: Should also the longhands be allowed?filter
Applies filters to the image. Regarding blur()
, drop-shadow()
and similar effects that draw outside the original width and height of the image, should the dimensions be adjusted accordingly or should they stay the same? Should we introduce something like overflow-clip-margin
to allow control over that? opacity
Applies transparency to the image.transform
Applies transformations to the image. Same question as for filter
.transform-origin
Defines the origin used for the transformations applied via transform
, scale
, rotate
or translate
.scale
Scales the image. Same question as for filter
.rotate
Rotates the image. Same question as for filter
.translate
Translates the image. Same question as for filter
.clip-path
Applies some clipping to the image.mask
Applies a mask to the image.border-radius
Adds bevel to the corners of the image.corner-shape
Specifies the shape of the corners created by border-radius
.background-color
Specifies the background color drawn on parts outside the manipulated image. Question: Should there be equivalents for all background-*
properties?will-change
Indicates whether the image will be changed due to some animation or transition. Obviously closely related to animation
and transition
. Question: Are manipulations composited? See also below.animation
Animates the image. Questions: Do we need that? Is that the right approach? When animations are added, then maybe also `transition?image-resolution
Sets the intrinsic resolution of the image.Any other suggestions? Did I miss anything from above?
Sebastian
Any other suggestions? Did I miss anything from above?
I think padding
could be useful, for adding transparent spacing around the main image. Maybe border
too?
what would the difference be between padding
, margin
and clip-path: inset();
here?
I think
padding
could be useful, for adding transparent spacing around the main image. Maybeborder
too?what would the difference be between
padding
,margin
andclip-path: inset();
here?
Right, I took margin
from your initial proposal for that, @LeaVerou. clip-path: inset();
is different because it clips the image. I imagine margin
to add extra transparent space around the image. It might be replaced by padding
so that the background shines through if set (which would also be transparent by default but can be changed via the background-color
property [and other background-* properties if we decide to add them, too]).
Sebastian
Although we're only in the context of manipulation of an existing image, I'd still like to stress the need for compositing and/or blending multiple images/colors. As a way of hinting to the UA to cache this in a single layer that "will not change" , so that we can more easily apply other effects on it, say scroll-animations. Kind of bringing WebGL-powers down to the masses 😄
Looking at a related example syntax I previously provided, let me think that transform-origin
should also be considered. I've added it to the list above.
Sebastian
@bramus wrote:
That
@image
/@image-manipulation
block surely looks a lot like@mixin
, no? Shouldn’t we then name it that way (or some other generic term), to leave the door open for future use-cases?
Now I finally understand what you meant with that. We should give this rule a general name so that it can be extended in the future and restrict it to image manipulations for now.
If that's what you meant by your sentence, then I guess I'm fine with that. Though I want to stress that image creation is a topic on its own and needs separate discussion, especially regarding context-sensitivity as mentioned in a previous comment.
Sebastian
Now I finally understand what you meant with that. We should give this rule a general name so that it can be extended in the future and restrict it to image manipulations for now.
Yes, that’s what I meant by that. Was purely looking at the “shape” of how it was defined. But as @tabatkins pointed out that’s because it “follows standard CSS syntactic patterns” – Same can be said for other at-rules such as @font-face
, @scroll-timeline
(RIP), … The listed examples reminded me of them, mainly because many of the descriptors have a directly matching property. This was a wrong path to follow.
Generalizing also doesn’t seem a good idea the more I think about it, especially if an author would want to feature detect this using at-rule()
.
tl;dr disregard my mentions of mixins
Generalizing also doesn’t seem a good idea the more I think about it, especially if an author would want to feature detect this using
at-rule()
.
Authors can do feature detection, e.g. via at-rule(@image; corner-shape: angle)
, indenpendent of the name of the rule.
Though thinking more about it and looking at possible additions like compositions, I still believe it's better to handle image creation separately from image manipulation. And if we use a more specific name now, it is still possible to turn it into an alias for a more general one, but not the other way round.
Sebastian
another example from the wild that I think might be covered (https://www.fivebelow.com/):
a radial-gradient pattern image that is then rotated and clipped at the top? Would there need to be a scale
with the rotate
to make sure there are no transparent bit at the corners?
We talked about resolution of the source image a lot, though we didn't talk about setting the resolution of the manipulated image.
CSS Images 4 defines an image-resolution
which allows to overwrite the resolution of all the images used in or on an element. For @image
it could be reused to change the resolution of the manipulated image. So I've added it to the list above.
Sebastian
The CSS Working Group just discussed @image rule for manipulating images
, and agreed to the following:
RESOLVED: Accept @image and add it to css-images-5
It's getting late here, but just some quick thoughts on the meeting discussion:
... rough approach is an `@image` rule, which provides a doubel dashed name ... a bunch of descriptors, which takes a src image, then others which are copies of other CSS properites that do useful things ... currently only supporting things you can already do to elements ... once defined, you could use this image in CSS ... image(--foo)
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.
heycam: Alternative approach is to slam all of these filtering and transforms into the image() function itself
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 still need to give that some deeper thought. But it also doesn't seem to exclude each other.
dbaron: could you talk briefly about how sizing of these images works? ... looks like there's some sizing related properties in there ... transforms and filters which might have sizing implementations TabAtkins: you have a width/height property ... that's the natural width/heihgt of the produced image ... scaling etc. would be purely visual effects
I imagined width: auto;
and height: auto;
to be possible, meaning that transforms and effects like blurs would change the size of the canvas to fit in the manipulated image.
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.
fantasai: what else is in images 5? Rossen: almost nothing fantasai: current images is images-4. images-5 is just an ED, don't think there's anything even in it
The repository doesn't hold any images-5 ED yet. There are just a few issues labelled with css-images-5.
Sebastian
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:
There 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)