w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.42k stars 652 forks source link

Request for New CSS Property: 'mask-rotation' #10024

Open Thiago2104 opened 6 months ago

Thiago2104 commented 6 months ago

Summary:

I am proposing the addition of a new CSS property, mask-rotation, to provide developers with more control over the orientation and rotation of CSS masks.

Motivation:

Currently, CSS offers properties like mask-size, mask-origin, and mask-position for controlling the size, origin, and position of masks. However, there is no direct property to manage the rotation or orientation of the mask. This feature would be particularly useful for scenarios where precise control over the mask's rotation is required.

Proposed Solution:

Introduce a new property, mask-rotation, that allows developers to specify the rotation angle for CSS masks. The property value could accept degrees (deg) as a unit, similar to how rotate works in transformations.

Example:

.element {
    mask-image: url('mask.png');
    mask-size: cover;
    mask-origin: center;
    mask-rotation: 45deg; /* Rotates mask-image 45 degrees clock-wise */
}

Key Words:

The new property could have key words to specify the type of rotation and the axis where it is rotating:

Also, adding the axis to the key words specify the axis where it is rotating:

Example:

.element {
    mask-image: url('mask.png');
    mask-size: cover;
    mask-origin: center;
    mask-rotation: y right, flip; /* Rotates mask-image horizontally 90 degrees, and rotates mask 180 degrees clock-wise */
}

Benefits:

fantasai commented 6 months ago

We should do backgrounds and masking in conjunction here... and I wonder if it shouldn't be a more generic -transform property.

SebastianZ commented 6 months ago

This use case is covered by the @image rule we resolved on.

Examples:

@image --rotate {
  rotate: 45deg;
}

@image --flip-vertically {
  transform: rotateX(180deg);
}

.element {
    mask-image: image(url('mask.png'), --rotate);
    mask-size: cover;
}

.element {
    mask-image: image(url('mask.png'), --flip-vertically);
    mask-size: cover;
}

This has two major advantages over new properties:

  1. It can be used everywhere were images are allowed and is not limited to masks.
  2. It allows all kinds of image manipulations and is not limited to rotations.

So I vote to close this in favor of the more general solution.

Sebastian

PS: @Thiago2104 Your second example rotates the image by 90 degrees along the y-axis, which effectively makes it invisible.

Thiago2104 commented 6 months ago

Hi @SebastianZ

I've tried your proposal with a mask image animation that makes the mask to rotate 180deg when .dark tag triggers. I'm using an svg as the mask:

@image --rotate {
  rotate: 180deg;
}
.light .alternate-gradient-bg{
    clip-path: circle(150% at 95.25% 90.5%);
    mask-image: none;
    mask-composite: exclude;
    mask-repeat: no-repeat;
    mask-size: 4500px;
    mask-position: bottom -2180px right -2180px;
    transition: 1s ease-out;
}
.dark .alternate-gradient-bg{
    clip-path: circle(4.4% at 95.25% 90.5%);
    mask-image: image(url("/BlackHole.svg"), --rotate);
    mask-composite: exclude;
    mask-repeat: no-repeat;
    mask-size: 100px;
    mask-position: bottom 20px right 20px;
    transition: 1s ease-out;
}

But what I got is that the tag image in the mask-image makes the mask of the svg to not being applied even without using the @image rule. What I currently have is a mask animation where the gradient background has a black hole mask, that when combined with clip-path and changing the mask-size, gives the illusion of the background being absorbed by a blackhole, the only thing left is making the mask to rotate from 0 to 180deg during transition so the black hole effect is done. That's why I'm proposing a mask-rotate property, so it is consistent with mask-size and mask-position properties on making mask animations.

I'm sharing a code-pen with a small demonstration of what I currently have BlackHole - Supernova Theme Toggle (It is not responsive yet, so it is possible that mask is not allign with button or clip-paths seems weird)

Thiago2104 - Naryalin

SebastianZ commented 6 months ago

But what I got is that the tag image in the mask-image makes the mask of the svg to not being applied even without using the @image rule.

That is because the @image rule and the new syntax for the image() function don't exist in browsers yet, nor are they specified. There is only a resolution to add them to the specifications, at the moment. So it will still take some time until that solution will work.

For now, you might get the result you're looking for by using two separate elements that overlay each other and work with mix-blend-mode rather than a mask. (I didn't try that out, though. Maybe someone else can come up with a better solution.)

Sebastian

Thiago2104 commented 6 months ago

Thank you @SebastianZ for your explanation. Then I'll try your suggestion while the @image rule comes to the browsers. I'll let this issue open for now if there are other use cases where this new property is reasonable (for a small example, maybe masks without using images, but I didn't check that though).

Thiago2104 - Naryalin