8000 [css-images] @image rule for manipulating images · Issue #6807 · w3c/csswg-drafts · GitHub
[go: up one dir, main page]

Skip to content

[css-images] @image rule for manipulating images #6807

@LeaVerou

Description

@LeaVerou

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() or background-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 setting object-fit: cover on a background-image so I could use background-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:

@image --foo {
	src: url("foo.png");
	aspect-ratio: 1 / 1;
	width: 100vw;
	object-fit: cover;
	filter: blur(10px);
	opacity: .5;
	transform: rotate(5deg);
}

Which would then be used like:

background: image(--foo);
border-image: image(--foo); /* etc */

Since any <image> is allowed in src, this can be used to create variants of the same image:

@image --foo-larger {
	src: image(--foo);
	scale: 2;
}

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 ratio
  • margin to add (transparent) spacing around image
  • object-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 of image-set().

Instead of:

background-image: image-set( "foo.png" 1x,
                             "foo-2x.png" 2x,
                             "foo-print.png" 600dpi );

it would be:

@image --foo {
	src: url("foo.png") 1x
           url("foo-2x.png") 2x,
          url("foo-print.png") 600dpi;
}

In fact, it would be nice if one could specify different descriptors depending on resolution, so that people could do things like:

@image --foo {
	src: url("foo.png") 1x;
}

@image --foo {
	src: url("foo.png") 2x;
	filter: blur(10px);
}

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:

  • It solves the problem using syntax that authors are already familiar with. Instead of needing to learn different ad hoc ways of transforming images that are specific to each use case, they only need to learn one @image rule and then they can even guess the descriptors they need as they are essentially a subset of existing CSS properties.
  • It's designed to be easy to extend in the future to solve more image manipulation use cases.
  • While lengthier, it's nicer to read than functional syntax like filter(). Compare:
background-image: filter(url("foo.png"), hue-rotate(135deg) opacity(.5));

with:

@image --foo {
	src: url("foo.png");
	filter: hue-rotate(135deg);
	opacity: .5;
}

/* ... */

background-image: image(--foo); 

The main downsides I see :

  • 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).
  • 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)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0